blob: 6bfc37a46cfd760aac3466953df3060151ae7c60 [file] [log] [blame]
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05001#include "certs_manager.hpp"
2
Patrick Williams26fb83e2021-12-14 14:08:28 -06003#include <openssl/evp.h>
Marri Devender Raof4682712019-03-19 05:00:28 -05004#include <openssl/pem.h>
5#include <unistd.h>
6
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +02007#include <algorithm>
Marri Devender Rao6ceec402019-02-01 03:15:19 -06008#include <phosphor-logging/elog-errors.hpp>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -05009#include <xyz/openbmc_project/Certs/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050010#include <xyz/openbmc_project/Common/error.hpp>
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +010011
Nan Zhoue1289ad2021-12-28 11:02:56 -080012namespace phosphor::certs
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050013{
Nan Zhoucf06ccd2021-12-28 16:25:45 -080014namespace
15{
16namespace fs = std::filesystem;
17using ::phosphor::logging::commit;
18using ::phosphor::logging::elog;
19using ::phosphor::logging::entry;
20using ::phosphor::logging::level;
21using ::phosphor::logging::log;
22using ::phosphor::logging::report;
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050023
Nan Zhoucf06ccd2021-12-28 16:25:45 -080024using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
25using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
26using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
27using NotAllowedReason =
28 ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
29using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
30 Certs::InvalidCertificate::REASON;
31using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
32using Argument =
33 ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050034
Nan Zhoucf06ccd2021-12-28 16:25:45 -080035// RAII support for openSSL functions.
36using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
37using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
38using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
39
40constexpr int supportedKeyBitLength = 2048;
41constexpr int defaultKeyBitLength = 2048;
42// secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
43constexpr auto defaultKeyCurveID = "secp224r1";
44} // namespace
Marri Devender Raof4682712019-03-19 05:00:28 -050045
46Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
Nan Zhoucf06ccd2021-12-28 16:25:45 -080047 const char* path, CertificateType type,
48 const std::string& unit, const std::string& installPath) :
49 internal::ManagerInterface(bus, path),
Marri Devender Raof4682712019-03-19 05:00:28 -050050 bus(bus), event(event), objectPath(path), certType(type),
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050051 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
52 certParentInstallPath(fs::path(certInstallPath).parent_path())
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050053{
Marri Devender Raob57d75e2019-07-25 04:56:21 -050054 try
55 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -050056 // Create certificate directory if not existing.
Nan Zhoubf3cf752021-12-28 11:02:07 -080057 // Set correct certificate directory permissions.
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -050058 fs::path certDirectory;
59 try
Marri Devender Raob57d75e2019-07-25 04:56:21 -050060 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -080061 if (certType == CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -050062 {
63 certDirectory = certInstallPath;
64 }
65 else
66 {
67 certDirectory = certParentInstallPath;
68 }
69
70 if (!fs::exists(certDirectory))
71 {
72 fs::create_directories(certDirectory);
73 }
74
75 auto permission = fs::perms::owner_read | fs::perms::owner_write |
76 fs::perms::owner_exec;
77 fs::permissions(certDirectory, permission,
78 fs::perm_options::replace);
79 storageUpdate();
80 }
Patrick Williams71957992021-10-06 14:42:52 -050081 catch (const fs::filesystem_error& e)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -050082 {
83 log<level::ERR>(
84 "Failed to create directory", entry("ERR=%s", e.what()),
85 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
86 report<InternalFailure>();
87 }
88
89 // Generating RSA private key file if certificate type is server/client
Nan Zhoucf06ccd2021-12-28 16:25:45 -080090 if (certType != CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -050091 {
92 createRSAPrivateKeyFile();
93 }
94
95 // restore any existing certificates
96 createCertificates();
97
98 // watch is not required for authority certificates
Nan Zhoucf06ccd2021-12-28 16:25:45 -080099 if (certType != CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500100 {
101 // watch for certificate file create/replace
102 certWatchPtr = std::make_unique<
103 Watch>(event, certInstallPath, [this]() {
104 try
105 {
106 // if certificate file existing update it
107 if (!installedCerts.empty())
108 {
109 log<level::INFO>("Inotify callback to update "
110 "certificate properties");
111 installedCerts[0]->populateProperties();
112 }
113 else
114 {
115 log<level::INFO>(
116 "Inotify callback to create certificate object");
117 createCertificates();
118 }
119 }
120 catch (const InternalFailure& e)
121 {
122 commit<InternalFailure>();
123 }
124 catch (const InvalidCertificate& e)
125 {
126 commit<InvalidCertificate>();
127 }
128 });
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500129 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100130 else
131 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500132 try
133 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500134 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
135 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500136 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500137 log<level::NOTICE>(
138 "Legacy certificate detected, will be installed from: ",
139 entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
140 install(singleCertPath);
141 if (!fs::remove(singleCertPath))
142 {
143 log<level::ERR>(
144 "Unable to remove old certificate from: ",
145 entry("SINGLE_CERTPATH=%s",
146 singleCertPath.c_str()));
147 elog<InternalFailure>();
148 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500149 }
150 }
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500151 catch (const std::exception& ex)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500152 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500153 log<level::ERR>("Error in restoring legacy certificate",
154 entry("ERROR_STR=%s", ex.what()));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200155 }
156 }
157 }
Patrick Williams71957992021-10-06 14:42:52 -0500158 catch (const std::exception& ex)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500159 {
160 log<level::ERR>("Error in certificate manager constructor",
161 entry("ERROR_STR=%s", ex.what()));
162 }
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500163}
164
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200165std::string Manager::install(const std::string filePath)
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500166{
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800167 if (certType != CertificateType::Authority && !installedCerts.empty())
Marri Devender Rao13965112019-02-27 08:47:12 -0600168 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800169 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Marri Devender Rao13965112019-02-27 08:47:12 -0600170 }
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800171 else if (certType == CertificateType::Authority &&
Nan Zhou718eef32021-12-28 11:03:30 -0800172 installedCerts.size() >= maxNumAuthorityCertificates)
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200173 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800174 elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200175 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500176
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100177 std::string certObjectPath;
178 if (isCertificateUnique(filePath))
179 {
180 certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
181 installedCerts.emplace_back(std::make_unique<Certificate>(
182 bus, certObjectPath, certType, certInstallPath, filePath,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800183 certWatchPtr.get(), *this));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100184 reloadOrReset(unitToRestart);
185 certIdCounter++;
186 }
187 else
188 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800189 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100190 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200191
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200192 return certObjectPath;
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500193}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500194
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200195void Manager::deleteAll()
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500196{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600197 // TODO: #Issue 4 when a certificate is deleted system auto generates
198 // certificate file. At present we are not supporting creation of
199 // certificate object for the auto-generated certificate file as
200 // deletion if only applicable for REST server and Bmcweb does not allow
201 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200202 installedCerts.clear();
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100203 storageUpdate();
204 reloadOrReset(unitToRestart);
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500205}
Marri Devender Raof4682712019-03-19 05:00:28 -0500206
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100207void Manager::deleteCertificate(const Certificate* const certificate)
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200208{
209 std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
210 std::find_if(installedCerts.begin(), installedCerts.end(),
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100211 [certificate](std::unique_ptr<Certificate> const& cert) {
212 return (cert.get() == certificate);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200213 });
214 if (certIt != installedCerts.end())
215 {
216 installedCerts.erase(certIt);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100217 storageUpdate();
218 reloadOrReset(unitToRestart);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200219 }
220 else
221 {
222 log<level::ERR>("Certificate does not exist",
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100223 entry("ID=%s", certificate->getCertId().c_str()));
224 elog<InternalFailure>();
225 }
226}
227
228void Manager::replaceCertificate(Certificate* const certificate,
229 const std::string& filePath)
230{
231 if (isCertificateUnique(filePath, certificate))
232 {
233 certificate->install(filePath);
234 storageUpdate();
235 reloadOrReset(unitToRestart);
236 }
237 else
238 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800239 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200240 }
241}
242
Marri Devender Raof4682712019-03-19 05:00:28 -0500243std::string Manager::generateCSR(
244 std::vector<std::string> alternativeNames, std::string challengePassword,
245 std::string city, std::string commonName, std::string contactPerson,
246 std::string country, std::string email, std::string givenName,
247 std::string initials, int64_t keyBitLength, std::string keyCurveId,
248 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
249 std::string organization, std::string organizationalUnit, std::string state,
250 std::string surname, std::string unstructuredName)
251{
252 // We support only one CSR.
253 csrPtr.reset(nullptr);
254 auto pid = fork();
255 if (pid == -1)
256 {
257 log<level::ERR>("Error occurred during forking process");
258 report<InternalFailure>();
259 }
260 else if (pid == 0)
261 {
262 try
263 {
264 generateCSRHelper(alternativeNames, challengePassword, city,
265 commonName, contactPerson, country, email,
266 givenName, initials, keyBitLength, keyCurveId,
267 keyPairAlgorithm, keyUsage, organization,
268 organizationalUnit, state, surname,
269 unstructuredName);
270 exit(EXIT_SUCCESS);
271 }
272 catch (const InternalFailure& e)
273 {
274 // commit the error reported in child process and exit
275 // Callback method from SDEvent Loop looks for exit status
276 exit(EXIT_FAILURE);
277 commit<InternalFailure>();
278 }
Ramesh Iyyard2393f22020-10-29 09:46:51 -0500279 catch (const InvalidArgument& e)
280 {
281 // commit the error reported in child process and exit
282 // Callback method from SDEvent Loop looks for exit status
283 exit(EXIT_FAILURE);
284 commit<InvalidArgument>();
285 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500286 }
287 else
288 {
289 using namespace sdeventplus::source;
290 Child::Callback callback = [this](Child& eventSource,
291 const siginfo_t* si) {
292 eventSource.set_enabled(Enabled::On);
293 if (si->si_status != 0)
294 {
295 this->createCSRObject(Status::FAILURE);
296 }
297 else
298 {
299 this->createCSRObject(Status::SUCCESS);
300 }
301 };
302 try
303 {
304 sigset_t ss;
305 if (sigemptyset(&ss) < 0)
306 {
307 log<level::ERR>("Unable to initialize signal set");
308 elog<InternalFailure>();
309 }
310 if (sigaddset(&ss, SIGCHLD) < 0)
311 {
312 log<level::ERR>("Unable to add signal to signal set");
313 elog<InternalFailure>();
314 }
315
316 // Block SIGCHLD first, so that the event loop can handle it
Nan Zhoucfb58022021-12-28 11:02:26 -0800317 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500318 {
319 log<level::ERR>("Unable to block signal");
320 elog<InternalFailure>();
321 }
322 if (childPtr)
323 {
324 childPtr.reset();
325 }
326 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
327 std::move(callback));
328 }
329 catch (const InternalFailure& e)
330 {
331 commit<InternalFailure>();
332 }
333 }
334 auto csrObjectPath = objectPath + '/' + "csr";
335 return csrObjectPath;
336}
337
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200338std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500339{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200340 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500341}
342
Marri Devender Raof4682712019-03-19 05:00:28 -0500343void Manager::generateCSRHelper(
344 std::vector<std::string> alternativeNames, std::string challengePassword,
345 std::string city, std::string commonName, std::string contactPerson,
346 std::string country, std::string email, std::string givenName,
347 std::string initials, int64_t keyBitLength, std::string keyCurveId,
348 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
349 std::string organization, std::string organizationalUnit, std::string state,
350 std::string surname, std::string unstructuredName)
351{
352 int ret = 0;
353
354 // set version of x509 req
355 int nVersion = 1;
356 // TODO: Issue#6 need to make version number configurable
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800357 X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
Marri Devender Raof4682712019-03-19 05:00:28 -0500358 ret = X509_REQ_set_version(x509Req.get(), nVersion);
359 if (ret == 0)
360 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800361 log<level::ERR>("Error occurred during X509_REQ_set_version call");
Marri Devender Raof4682712019-03-19 05:00:28 -0500362 elog<InternalFailure>();
363 }
364
365 // set subject of x509 req
366 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
367
368 if (!alternativeNames.empty())
369 {
370 for (auto& name : alternativeNames)
371 {
372 addEntry(x509Name, "subjectAltName", name);
373 }
374 }
375 addEntry(x509Name, "challengePassword", challengePassword);
376 addEntry(x509Name, "L", city);
377 addEntry(x509Name, "CN", commonName);
378 addEntry(x509Name, "name", contactPerson);
379 addEntry(x509Name, "C", country);
380 addEntry(x509Name, "emailAddress", email);
381 addEntry(x509Name, "GN", givenName);
382 addEntry(x509Name, "initials", initials);
383 addEntry(x509Name, "algorithm", keyPairAlgorithm);
384 if (!keyUsage.empty())
385 {
386 for (auto& usage : keyUsage)
387 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500388 if (isExtendedKeyUsage(usage))
389 {
390 addEntry(x509Name, "extendedKeyUsage", usage);
391 }
392 else
393 {
394 addEntry(x509Name, "keyUsage", usage);
395 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500396 }
397 }
398 addEntry(x509Name, "O", organization);
Jayanth Othayothdc91fb62021-05-04 23:17:47 -0500399 addEntry(x509Name, "OU", organizationalUnit);
Marri Devender Raof4682712019-03-19 05:00:28 -0500400 addEntry(x509Name, "ST", state);
401 addEntry(x509Name, "SN", surname);
402 addEntry(x509Name, "unstructuredName", unstructuredName);
403
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800404 EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500405
406 log<level::INFO>("Given Key pair algorithm",
407 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
408
409 // Used EC algorithm as default if user did not give algorithm type.
410 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500411 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500412 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500413 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500414 else
415 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500416 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
417 "RSA and EC only");
418 elog<InvalidArgument>(
419 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
420 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
421 }
422
423 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
424 if (ret == 0)
425 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800426 log<level::ERR>("Error occurred while setting Public key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500427 elog<InternalFailure>();
428 }
429
430 // Write private key to file
Nan Zhou718eef32021-12-28 11:03:30 -0800431 writePrivateKey(pKey, defaultPrivateKeyFileName);
Marri Devender Raof4682712019-03-19 05:00:28 -0500432
433 // set sign key of x509 req
434 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500435 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500436 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800437 log<level::ERR>("Error occurred while signing key of x509");
Marri Devender Raof4682712019-03-19 05:00:28 -0500438 elog<InternalFailure>();
439 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500440
Marri Devender Raof4682712019-03-19 05:00:28 -0500441 log<level::INFO>("Writing CSR to file");
Nan Zhou718eef32021-12-28 11:03:30 -0800442 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500443 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500444}
445
Marri Devender Rao76411052019-08-07 01:25:07 -0500446bool Manager::isExtendedKeyUsage(const std::string& usage)
447{
448 const static std::array<const char*, 6> usageList = {
449 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
450 "Timestamping", "CodeSigning", "EmailProtection"};
451 auto it = std::find_if(
452 usageList.begin(), usageList.end(),
453 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
454 return it != usageList.end();
455}
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800456EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500457{
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500458 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500459 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500460 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500461 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500462 log<level::INFO>(
463 "KeyBitLength is not given.Hence, using default KeyBitLength",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800464 entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
465 keyBitLen = defaultKeyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500466 }
Patrick Williams26fb83e2021-12-14 14:08:28 -0600467
468#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
469
470 // generate rsa key
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800471 BignumPtr bne(BN_new(), ::BN_free);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600472 auto ret = BN_set_word(bne.get(), RSA_F4);
473 if (ret == 0)
474 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800475 log<level::ERR>("Error occurred during BN_set_word call");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600476 elog<InternalFailure>();
477 }
Nan Zhou762da742022-01-14 17:21:44 -0800478 using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
479 RSAPtr rsa(RSA_new(), ::RSA_free);
480 ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500481 if (ret != 1)
482 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800483 log<level::ERR>("Error occurred during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500484 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500485 elog<InternalFailure>();
486 }
487
488 // set public key of x509 req
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800489 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Nan Zhou762da742022-01-14 17:21:44 -0800490 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
Marri Devender Raof4682712019-03-19 05:00:28 -0500491 if (ret == 0)
492 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800493 log<level::ERR>("Error occurred during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500494 elog<InternalFailure>();
495 }
Nan Zhou762da742022-01-14 17:21:44 -0800496 // Now |rsa| is managed by |pKey|
497 rsa.release();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500498 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600499
500#else
501 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
502 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
503 if (!ctx)
504 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800505 log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600506 elog<InternalFailure>();
507 }
508
509 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
510 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
511
512 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800513 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600514 elog<InternalFailure>();
515 }
516
517 EVP_PKEY* pKey = nullptr;
518 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
519 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800520 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600521 elog<InternalFailure>();
522 }
523
524 return {pKey, &::EVP_PKEY_free};
525#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500526}
527
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800528EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500529{
530 std::string curId(curveId);
531
532 if (curId.empty())
533 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500534 log<level::INFO>(
535 "KeyCurveId is not given. Hence using default curve id",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800536 entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
537 curId = defaultKeyCurveID;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500538 }
539
540 int ecGrp = OBJ_txt2nid(curId.c_str());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500541 if (ecGrp == NID_undef)
542 {
543 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800544 "Error occurred during convert the curve id string format into NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500545 entry("KEYCURVEID=%s", curId.c_str()));
546 elog<InternalFailure>();
547 }
548
Patrick Williams26fb83e2021-12-14 14:08:28 -0600549#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
550
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500551 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
552
Nan Zhoucfb58022021-12-28 11:02:26 -0800553 if (ecKey == nullptr)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500554 {
555 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800556 "Error occurred during create the EC_Key object from NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500557 entry("ECGROUP=%d", ecGrp));
558 elog<InternalFailure>();
559 }
560
561 // If you want to save a key and later load it with
562 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
563 // flag on the key.
564 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
565
566 int ret = EC_KEY_generate_key(ecKey);
567
568 if (ret == 0)
569 {
570 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800571 log<level::ERR>("Error occurred during generate EC key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500572 elog<InternalFailure>();
573 }
574
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800575 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500576 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
577 if (ret == 0)
578 {
579 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800580 log<level::ERR>("Error occurred during assign EC Key into EVP");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500581 elog<InternalFailure>();
582 }
583
584 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600585
586#else
587 auto holder_of_key = [](EVP_PKEY* key) {
588 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
589 key, &::EVP_PKEY_free};
590 };
591
592 // Create context to set up curve parameters.
593 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
594 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
595 if (!ctx)
596 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800597 log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600598 elog<InternalFailure>();
599 }
600
601 // Set up curve parameters.
602 EVP_PKEY* params = nullptr;
603
604 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
605 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
606 0) ||
607 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
608 (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
609 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800610 log<level::ERR>("Error occurred setting curve parameters");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600611 elog<InternalFailure>();
612 }
613
614 // Move parameters to RAII holder.
615 auto pparms = holder_of_key(params);
616
617 // Create new context for key.
618 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
619
620 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
621 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800622 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600623 elog<InternalFailure>();
624 }
625
626 EVP_PKEY* pKey = nullptr;
627 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
628 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800629 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600630 elog<InternalFailure>();
631 }
632
633 return holder_of_key(pKey);
634#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500635}
636
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800637void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500638 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500639{
640 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500641 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500642 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500643
644 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
Nan Zhoucfb58022021-12-28 11:02:26 -0800645 if (fp == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500646 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800647 log<level::ERR>("Error occurred creating private key file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500648 elog<InternalFailure>();
649 }
Nan Zhoucfb58022021-12-28 11:02:26 -0800650 int ret =
651 PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500652 std::fclose(fp);
653 if (ret == 0)
654 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800655 log<level::ERR>("Error occurred while writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500656 elog<InternalFailure>();
657 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500658}
659
660void Manager::addEntry(X509_NAME* x509Name, const char* field,
661 const std::string& bytes)
662{
663 if (bytes.empty())
664 {
665 return;
666 }
667 int ret = X509_NAME_add_entry_by_txt(
668 x509Name, field, MBSTRING_ASC,
669 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
670 if (ret != 1)
671 {
672 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
673 entry("VALUE=%s", bytes.c_str()));
674 elog<InternalFailure>();
675 }
676}
677
678void Manager::createCSRObject(const Status& status)
679{
680 if (csrPtr)
681 {
682 csrPtr.reset(nullptr);
683 }
684 auto csrObjectPath = objectPath + '/' + "csr";
685 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
686 certInstallPath.c_str(), status);
687}
688
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800689void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
Marri Devender Raof4682712019-03-19 05:00:28 -0500690{
691 if (fs::exists(filePath))
692 {
693 log<level::INFO>("Removing the existing file",
694 entry("FILENAME=%s", filePath.c_str()));
695 if (!fs::remove(filePath.c_str()))
696 {
697 log<level::ERR>("Unable to remove the file",
698 entry("FILENAME=%s", filePath.c_str()));
699 elog<InternalFailure>();
700 }
701 }
702
Nan Zhoucfb58022021-12-28 11:02:26 -0800703 FILE* fp = nullptr;
Marri Devender Raof4682712019-03-19 05:00:28 -0500704
Nan Zhoucfb58022021-12-28 11:02:26 -0800705 if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500706 {
707 log<level::ERR>("Error opening the file to write the CSR",
708 entry("FILENAME=%s", filePath.c_str()));
709 elog<InternalFailure>();
710 }
711
712 int rc = PEM_write_X509_REQ(fp, x509Req.get());
713 if (!rc)
714 {
715 log<level::ERR>("PEM write routine failed",
716 entry("FILENAME=%s", filePath.c_str()));
717 std::fclose(fp);
718 elog<InternalFailure>();
719 }
720 std::fclose(fp);
721}
722
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200723void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500724{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200725 auto certObjectPath = objectPath + '/';
726
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800727 if (certType == CertificateType::Authority)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500728 {
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100729 // Check whether install path is a directory.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200730 if (!fs::is_directory(certInstallPath))
731 {
732 log<level::ERR>("Certificate installation path exists and it is "
733 "not a directory");
734 elog<InternalFailure>();
735 return;
736 }
737
738 for (auto& path : fs::directory_iterator(certInstallPath))
739 {
740 try
741 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100742 // Assume here any regular file located in certificate directory
743 // contains certificates body. Do not want to use soft links
744 // would add value.
745 if (fs::is_regular_file(path))
746 {
747 installedCerts.emplace_back(std::make_unique<Certificate>(
748 bus, certObjectPath + std::to_string(certIdCounter++),
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800749 certType, certInstallPath, path.path(),
750 certWatchPtr.get(), *this));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100751 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200752 }
753 catch (const InternalFailure& e)
754 {
755 report<InternalFailure>();
756 }
757 catch (const InvalidCertificate& e)
758 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800759 report<InvalidCertificate>(InvalidCertificateReason(
760 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200761 }
762 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500763 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200764 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500765 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200766 try
767 {
768 installedCerts.emplace_back(std::make_unique<Certificate>(
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100769 bus, certObjectPath + '1', certType, certInstallPath,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800770 certInstallPath, certWatchPtr.get(), *this));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200771 }
772 catch (const InternalFailure& e)
773 {
774 report<InternalFailure>();
775 }
776 catch (const InvalidCertificate& e)
777 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800778 report<InvalidCertificate>(InvalidCertificateReason(
779 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200780 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500781 }
782}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500783
784void Manager::createRSAPrivateKeyFile()
785{
786 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -0800787 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500788
789 try
790 {
791 if (!fs::exists(rsaPrivateKeyFileName))
792 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800793 writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
Nan Zhou718eef32021-12-28 11:03:30 -0800794 defaultRSAPrivateKeyFileName);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500795 }
796 }
797 catch (const InternalFailure& e)
798 {
799 report<InternalFailure>();
800 }
801}
802
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800803EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500804{
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800805 if (keyBitLength != supportedKeyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500806 {
807 log<level::ERR>(
808 "Given Key bit length is not supported",
809 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800810 entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500811 elog<InvalidArgument>(
812 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
813 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
814 }
815 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -0800816 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500817
818 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
819 if (!privateKeyFile)
820 {
821 log<level::ERR>("Unable to open RSA private key file to read",
822 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
823 entry("ERRORREASON=%s", strerror(errno)));
824 elog<InternalFailure>();
825 }
826
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800827 EVPPkeyPtr privateKey(
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500828 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
829 ::EVP_PKEY_free);
830 std::fclose(privateKeyFile);
831
832 if (!privateKey)
833 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800834 log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500835 elog<InternalFailure>();
836 }
837 return privateKey;
838}
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100839
840void Manager::storageUpdate()
841{
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800842 if (certType == CertificateType::Authority)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100843 {
844 // Remove symbolic links in the certificate directory
845 for (auto& certPath : fs::directory_iterator(certInstallPath))
846 {
847 try
848 {
849 if (fs::is_symlink(certPath))
850 {
851 fs::remove(certPath);
852 }
853 }
854 catch (const std::exception& e)
855 {
856 log<level::ERR>(
857 "Failed to remove symlink for certificate",
858 entry("ERR=%s", e.what()),
859 entry("SYMLINK=%s", certPath.path().string().c_str()));
860 elog<InternalFailure>();
861 }
862 }
863 }
864
865 for (const auto& cert : installedCerts)
866 {
867 cert->storageUpdate();
868 }
869}
870
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800871void Manager::reloadOrReset(const std::string& unit)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100872{
873 if (!unit.empty())
874 {
875 try
876 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800877 constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
878 constexpr auto defaultSystemdObjectPath =
879 "/org/freedesktop/systemd1";
880 constexpr auto defaultSystemdInterface =
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100881 "org.freedesktop.systemd1.Manager";
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800882 auto method = bus.new_method_call(
883 defaultSystemdService, defaultSystemdObjectPath,
884 defaultSystemdInterface, "ReloadOrRestartUnit");
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100885 method.append(unit, "replace");
886 bus.call_noreply(method);
887 }
Patrick Williamsca128112021-09-02 09:36:07 -0500888 catch (const sdbusplus::exception::exception& e)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100889 {
890 log<level::ERR>("Failed to reload or restart service",
891 entry("ERR=%s", e.what()),
892 entry("UNIT=%s", unit.c_str()));
893 elog<InternalFailure>();
894 }
895 }
896}
897
898bool Manager::isCertificateUnique(const std::string& filePath,
899 const Certificate* const certToDrop)
900{
901 if (std::any_of(
902 installedCerts.begin(), installedCerts.end(),
903 [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
904 return cert.get() != certToDrop && cert->isSame(filePath);
905 }))
906 {
907 return false;
908 }
909 else
910 {
911 return true;
912 }
913}
914
Nan Zhoue1289ad2021-12-28 11:02:56 -0800915} // namespace phosphor::certs