blob: d8e99b73890fa16dec9270807103ff9f25208e87 [file] [log] [blame]
Nan Zhou014be0b2021-12-28 18:00:14 -08001#include "config.h"
2
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05003#include "certs_manager.hpp"
4
Nan Zhou6ec13c82021-12-30 11:34:50 -08005#include "x509_utils.hpp"
6
Nan Zhou014be0b2021-12-28 18:00:14 -08007#include <openssl/asn1.h>
8#include <openssl/bn.h>
9#include <openssl/ec.h>
Patrick Williams26fb83e2021-12-14 14:08:28 -060010#include <openssl/evp.h>
Nan Zhou014be0b2021-12-28 18:00:14 -080011#include <openssl/obj_mac.h>
12#include <openssl/objects.h>
13#include <openssl/opensslv.h>
Marri Devender Raof4682712019-03-19 05:00:28 -050014#include <openssl/pem.h>
Nan Zhou014be0b2021-12-28 18:00:14 -080015#include <openssl/rsa.h>
Marri Devender Raof4682712019-03-19 05:00:28 -050016#include <unistd.h>
17
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +020018#include <algorithm>
Nan Zhou014be0b2021-12-28 18:00:14 -080019#include <array>
20#include <cerrno>
21#include <chrono>
22#include <csignal>
23#include <cstdio>
24#include <cstdlib>
25#include <cstring>
26#include <exception>
Nan Zhou6ec13c82021-12-30 11:34:50 -080027#include <fstream>
Marri Devender Rao6ceec402019-02-01 03:15:19 -060028#include <phosphor-logging/elog-errors.hpp>
Nan Zhou014be0b2021-12-28 18:00:14 -080029#include <phosphor-logging/elog.hpp>
30#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
32#include <sdbusplus/exception.hpp>
33#include <sdbusplus/message.hpp>
34#include <sdeventplus/source/base.hpp>
35#include <sdeventplus/source/child.hpp>
36#include <utility>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -050037#include <xyz/openbmc_project/Certs/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050038#include <xyz/openbmc_project/Common/error.hpp>
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +010039
Nan Zhoue1289ad2021-12-28 11:02:56 -080040namespace phosphor::certs
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050041{
Nan Zhoucf06ccd2021-12-28 16:25:45 -080042namespace
43{
44namespace fs = std::filesystem;
45using ::phosphor::logging::commit;
46using ::phosphor::logging::elog;
47using ::phosphor::logging::entry;
48using ::phosphor::logging::level;
49using ::phosphor::logging::log;
50using ::phosphor::logging::report;
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050051
Nan Zhoucf06ccd2021-12-28 16:25:45 -080052using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
53using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
54using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
55using NotAllowedReason =
56 ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
57using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
58 Certs::InvalidCertificate::REASON;
59using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
60using Argument =
61 ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050062
Nan Zhoucf06ccd2021-12-28 16:25:45 -080063// RAII support for openSSL functions.
64using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
65using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
66using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
Nan Zhou6ec13c82021-12-30 11:34:50 -080067using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
Nan Zhoucf06ccd2021-12-28 16:25:45 -080068
69constexpr int supportedKeyBitLength = 2048;
70constexpr int defaultKeyBitLength = 2048;
71// secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
72constexpr auto defaultKeyCurveID = "secp224r1";
Nan Zhou6ec13c82021-12-30 11:34:50 -080073// PEM certificate block markers, defined in go/rfc/7468.
74constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
75constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
76
77/**
78 * @brief Splits the given authorities list file and returns an array of
79 * individual PEM encoded x509 certificate.
80 *
81 * @param[in] sourceFilePath - Path to the authorities list file.
82 *
83 * @return An array of individual PEM encoded x509 certificate
84 */
85std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
86{
87 std::ifstream inputCertFileStream;
88 inputCertFileStream.exceptions(
89 std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
90
91 std::stringstream pemStream;
92 std::vector<std::string> certificatesList;
93 try
94 {
95 inputCertFileStream.open(sourceFilePath);
96 pemStream << inputCertFileStream.rdbuf();
97 inputCertFileStream.close();
98 }
99 catch (const std::exception& e)
100 {
101 log<level::ERR>("Failed to read certificates list",
102 entry("ERR=%s", e.what()),
103 entry("SRC=%s", sourceFilePath.c_str()));
104 elog<InternalFailure>();
105 }
106 std::string pem = pemStream.str();
107 size_t begin = 0;
108 // |begin| points to the current start position for searching the next
109 // |beginCertificate| block. When we find the beginning of the certificate,
110 // we extract the content between the beginning and the end of the current
111 // certificate. And finally we move |begin| to the end of the current
112 // certificate to start searching the next potential certificate.
113 for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
114 begin = pem.find(beginCertificate, begin))
115 {
116 size_t end = pem.find(endCertificate, begin);
117 if (end == std::string::npos)
118 {
119 log<level::ERR>(
120 "invalid PEM contains a BEGIN identifier without an END");
121 elog<InvalidCertificate>(InvalidCertificateReason(
122 "invalid PEM contains a BEGIN identifier without an END"));
123 }
124 end += endCertificate.size();
125 certificatesList.emplace_back(pem.substr(begin, end - begin));
126 begin = end;
127 }
128 return certificatesList;
129}
130
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800131} // namespace
Marri Devender Raof4682712019-03-19 05:00:28 -0500132
133Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800134 const char* path, CertificateType type,
135 const std::string& unit, const std::string& installPath) :
136 internal::ManagerInterface(bus, path),
Marri Devender Raof4682712019-03-19 05:00:28 -0500137 bus(bus), event(event), objectPath(path), certType(type),
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500138 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
139 certParentInstallPath(fs::path(certInstallPath).parent_path())
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500140{
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500141 try
142 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500143 // Create certificate directory if not existing.
Nan Zhoubf3cf752021-12-28 11:02:07 -0800144 // Set correct certificate directory permissions.
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500145 fs::path certDirectory;
146 try
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500147 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800148 if (certType == CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500149 {
150 certDirectory = certInstallPath;
151 }
152 else
153 {
154 certDirectory = certParentInstallPath;
155 }
156
157 if (!fs::exists(certDirectory))
158 {
159 fs::create_directories(certDirectory);
160 }
161
162 auto permission = fs::perms::owner_read | fs::perms::owner_write |
163 fs::perms::owner_exec;
164 fs::permissions(certDirectory, permission,
165 fs::perm_options::replace);
166 storageUpdate();
167 }
Patrick Williams71957992021-10-06 14:42:52 -0500168 catch (const fs::filesystem_error& e)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500169 {
170 log<level::ERR>(
171 "Failed to create directory", entry("ERR=%s", e.what()),
172 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
173 report<InternalFailure>();
174 }
175
176 // Generating RSA private key file if certificate type is server/client
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800177 if (certType != CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500178 {
179 createRSAPrivateKeyFile();
180 }
181
182 // restore any existing certificates
183 createCertificates();
184
185 // watch is not required for authority certificates
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800186 if (certType != CertificateType::Authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500187 {
188 // watch for certificate file create/replace
189 certWatchPtr = std::make_unique<
190 Watch>(event, certInstallPath, [this]() {
191 try
192 {
193 // if certificate file existing update it
194 if (!installedCerts.empty())
195 {
196 log<level::INFO>("Inotify callback to update "
197 "certificate properties");
198 installedCerts[0]->populateProperties();
199 }
200 else
201 {
202 log<level::INFO>(
203 "Inotify callback to create certificate object");
204 createCertificates();
205 }
206 }
207 catch (const InternalFailure& e)
208 {
209 commit<InternalFailure>();
210 }
211 catch (const InvalidCertificate& e)
212 {
213 commit<InvalidCertificate>();
214 }
215 });
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500216 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100217 else
218 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500219 try
220 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500221 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
222 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500223 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500224 log<level::NOTICE>(
225 "Legacy certificate detected, will be installed from: ",
226 entry("SINGLE_CERTPATH=%s", singleCertPath.c_str()));
227 install(singleCertPath);
228 if (!fs::remove(singleCertPath))
229 {
230 log<level::ERR>(
231 "Unable to remove old certificate from: ",
232 entry("SINGLE_CERTPATH=%s",
233 singleCertPath.c_str()));
234 elog<InternalFailure>();
235 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500236 }
237 }
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500238 catch (const std::exception& ex)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500239 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500240 log<level::ERR>("Error in restoring legacy certificate",
241 entry("ERROR_STR=%s", ex.what()));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200242 }
243 }
244 }
Patrick Williams71957992021-10-06 14:42:52 -0500245 catch (const std::exception& ex)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500246 {
247 log<level::ERR>("Error in certificate manager constructor",
248 entry("ERROR_STR=%s", ex.what()));
249 }
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500250}
251
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200252std::string Manager::install(const std::string filePath)
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500253{
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800254 if (certType != CertificateType::Authority && !installedCerts.empty())
Marri Devender Rao13965112019-02-27 08:47:12 -0600255 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800256 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Marri Devender Rao13965112019-02-27 08:47:12 -0600257 }
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800258 else if (certType == CertificateType::Authority &&
Nan Zhou718eef32021-12-28 11:03:30 -0800259 installedCerts.size() >= maxNumAuthorityCertificates)
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200260 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800261 elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200262 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500263
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100264 std::string certObjectPath;
265 if (isCertificateUnique(filePath))
266 {
267 certObjectPath = objectPath + '/' + std::to_string(certIdCounter);
268 installedCerts.emplace_back(std::make_unique<Certificate>(
269 bus, certObjectPath, certType, certInstallPath, filePath,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800270 certWatchPtr.get(), *this));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100271 reloadOrReset(unitToRestart);
272 certIdCounter++;
273 }
274 else
275 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800276 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100277 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200278
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200279 return certObjectPath;
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500280}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500281
Nan Zhou6ec13c82021-12-30 11:34:50 -0800282std::vector<sdbusplus::message::object_path>
283 Manager::installAll(const std::string filePath)
284{
285 if (certType != CertificateType::Authority)
286 {
287 elog<NotAllowed>(
288 NotAllowedReason("The InstallAll interface is only allowed for "
289 "Authority certificates"));
290 }
291
292 if (!installedCerts.empty())
293 {
294 elog<NotAllowed>(NotAllowedReason(
295 "There are already root certificates; Call DeleteAll then "
296 "InstallAll, or use ReplaceAll"));
297 }
298
299 fs::path sourceFile(filePath);
300 if (!fs::exists(sourceFile))
301 {
302 log<level::ERR>("File is Missing", entry("FILE=%s", filePath.c_str()));
303 elog<InternalFailure>();
304 }
305 std::vector<std::string> authorities = splitCertificates(sourceFile);
306 if (authorities.size() > maxNumAuthorityCertificates)
307 {
308 elog<NotAllowed>(NotAllowedReason("Certificates limit reached"));
309 }
310
311 fs::path authorityStore(certInstallPath);
312 fs::path authoritiesListFile =
313 authorityStore / defaultAuthoritiesListFileName;
314
315 // Atomically install all the certificates
316 fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
317 fs::create_directory(tempPath);
318 // Copies the authorities list
319 Certificate::copyCertificate(sourceFile,
320 tempPath / defaultAuthoritiesListFileName);
321 std::vector<std::unique_ptr<Certificate>> tempCertificates;
322 uint64_t tempCertIdCounter = certIdCounter;
323 X509StorePtr x509Store = getX509Store(sourceFile);
324 for (const auto& authority : authorities)
325 {
326 std::string certObjectPath =
327 objectPath + '/' + std::to_string(tempCertIdCounter);
328 tempCertificates.emplace_back(std::make_unique<Certificate>(
329 bus, certObjectPath, certType, tempPath, *x509Store, authority,
330 certWatchPtr.get(), *this));
331 tempCertIdCounter++;
332 }
333
334 // We are good now, issue swap
335 installedCerts = std::move(tempCertificates);
336 certIdCounter = tempCertIdCounter;
337 // Rename all the certificates including the authorities list
338 for (const fs::path& f : fs::directory_iterator(tempPath))
339 {
340 if (fs::is_symlink(f))
341 {
342 continue;
343 }
344 fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
345 }
346 // Update file locations and create symbol links
347 for (const auto& cert : installedCerts)
348 {
349 cert->setCertInstallPath(certInstallPath);
350 cert->setCertFilePath(certInstallPath /
351 fs::path(cert->getCertFilePath()).filename());
352 cert->storageUpdate();
353 }
354 // Remove the temporary folder
355 fs::remove_all(tempPath);
356
357 std::vector<sdbusplus::message::object_path> objects;
358 for (const auto& certificate : installedCerts)
359 {
360 objects.emplace_back(certificate->getObjectPath());
361 }
362
363 reloadOrReset(unitToRestart);
364 return objects;
365}
366
367std::vector<sdbusplus::message::object_path>
368 Manager::replaceAll(std::string filePath)
369{
370 installedCerts.clear();
371 certIdCounter = 1;
372 storageUpdate();
373 return installAll(std::move(filePath));
374}
375
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200376void Manager::deleteAll()
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500377{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600378 // TODO: #Issue 4 when a certificate is deleted system auto generates
379 // certificate file. At present we are not supporting creation of
380 // certificate object for the auto-generated certificate file as
381 // deletion if only applicable for REST server and Bmcweb does not allow
382 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200383 installedCerts.clear();
Nan Zhou6ec13c82021-12-30 11:34:50 -0800384 // If the authorities list exists, delete it as well
385 if (certType == CertificateType::Authority)
386 {
387 if (fs::path authoritiesList =
388 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
389 fs::exists(authoritiesList))
390 {
391 fs::remove(authoritiesList);
392 }
393 }
394 certIdCounter = 1;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100395 storageUpdate();
396 reloadOrReset(unitToRestart);
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500397}
Marri Devender Raof4682712019-03-19 05:00:28 -0500398
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100399void Manager::deleteCertificate(const Certificate* const certificate)
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200400{
401 std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
402 std::find_if(installedCerts.begin(), installedCerts.end(),
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100403 [certificate](std::unique_ptr<Certificate> const& cert) {
404 return (cert.get() == certificate);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200405 });
406 if (certIt != installedCerts.end())
407 {
408 installedCerts.erase(certIt);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100409 storageUpdate();
410 reloadOrReset(unitToRestart);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200411 }
412 else
413 {
414 log<level::ERR>("Certificate does not exist",
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100415 entry("ID=%s", certificate->getCertId().c_str()));
416 elog<InternalFailure>();
417 }
418}
419
420void Manager::replaceCertificate(Certificate* const certificate,
421 const std::string& filePath)
422{
423 if (isCertificateUnique(filePath, certificate))
424 {
425 certificate->install(filePath);
426 storageUpdate();
427 reloadOrReset(unitToRestart);
428 }
429 else
430 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800431 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200432 }
433}
434
Marri Devender Raof4682712019-03-19 05:00:28 -0500435std::string Manager::generateCSR(
436 std::vector<std::string> alternativeNames, std::string challengePassword,
437 std::string city, std::string commonName, std::string contactPerson,
438 std::string country, std::string email, std::string givenName,
439 std::string initials, int64_t keyBitLength, std::string keyCurveId,
440 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
441 std::string organization, std::string organizationalUnit, std::string state,
442 std::string surname, std::string unstructuredName)
443{
444 // We support only one CSR.
445 csrPtr.reset(nullptr);
446 auto pid = fork();
447 if (pid == -1)
448 {
449 log<level::ERR>("Error occurred during forking process");
450 report<InternalFailure>();
451 }
452 else if (pid == 0)
453 {
454 try
455 {
456 generateCSRHelper(alternativeNames, challengePassword, city,
457 commonName, contactPerson, country, email,
458 givenName, initials, keyBitLength, keyCurveId,
459 keyPairAlgorithm, keyUsage, organization,
460 organizationalUnit, state, surname,
461 unstructuredName);
462 exit(EXIT_SUCCESS);
463 }
464 catch (const InternalFailure& e)
465 {
466 // commit the error reported in child process and exit
467 // Callback method from SDEvent Loop looks for exit status
468 exit(EXIT_FAILURE);
469 commit<InternalFailure>();
470 }
Ramesh Iyyard2393f22020-10-29 09:46:51 -0500471 catch (const InvalidArgument& e)
472 {
473 // commit the error reported in child process and exit
474 // Callback method from SDEvent Loop looks for exit status
475 exit(EXIT_FAILURE);
476 commit<InvalidArgument>();
477 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500478 }
479 else
480 {
481 using namespace sdeventplus::source;
482 Child::Callback callback = [this](Child& eventSource,
483 const siginfo_t* si) {
484 eventSource.set_enabled(Enabled::On);
485 if (si->si_status != 0)
486 {
487 this->createCSRObject(Status::FAILURE);
488 }
489 else
490 {
491 this->createCSRObject(Status::SUCCESS);
492 }
493 };
494 try
495 {
496 sigset_t ss;
497 if (sigemptyset(&ss) < 0)
498 {
499 log<level::ERR>("Unable to initialize signal set");
500 elog<InternalFailure>();
501 }
502 if (sigaddset(&ss, SIGCHLD) < 0)
503 {
504 log<level::ERR>("Unable to add signal to signal set");
505 elog<InternalFailure>();
506 }
507
508 // Block SIGCHLD first, so that the event loop can handle it
Nan Zhoucfb58022021-12-28 11:02:26 -0800509 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500510 {
511 log<level::ERR>("Unable to block signal");
512 elog<InternalFailure>();
513 }
514 if (childPtr)
515 {
516 childPtr.reset();
517 }
518 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
519 std::move(callback));
520 }
521 catch (const InternalFailure& e)
522 {
523 commit<InternalFailure>();
524 }
525 }
526 auto csrObjectPath = objectPath + '/' + "csr";
527 return csrObjectPath;
528}
529
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200530std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500531{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200532 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500533}
534
Marri Devender Raof4682712019-03-19 05:00:28 -0500535void Manager::generateCSRHelper(
536 std::vector<std::string> alternativeNames, std::string challengePassword,
537 std::string city, std::string commonName, std::string contactPerson,
538 std::string country, std::string email, std::string givenName,
539 std::string initials, int64_t keyBitLength, std::string keyCurveId,
540 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
541 std::string organization, std::string organizationalUnit, std::string state,
542 std::string surname, std::string unstructuredName)
543{
544 int ret = 0;
545
546 // set version of x509 req
547 int nVersion = 1;
548 // TODO: Issue#6 need to make version number configurable
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800549 X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
Marri Devender Raof4682712019-03-19 05:00:28 -0500550 ret = X509_REQ_set_version(x509Req.get(), nVersion);
551 if (ret == 0)
552 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800553 log<level::ERR>("Error occurred during X509_REQ_set_version call");
Marri Devender Raof4682712019-03-19 05:00:28 -0500554 elog<InternalFailure>();
555 }
556
557 // set subject of x509 req
558 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
559
560 if (!alternativeNames.empty())
561 {
562 for (auto& name : alternativeNames)
563 {
564 addEntry(x509Name, "subjectAltName", name);
565 }
566 }
567 addEntry(x509Name, "challengePassword", challengePassword);
568 addEntry(x509Name, "L", city);
569 addEntry(x509Name, "CN", commonName);
570 addEntry(x509Name, "name", contactPerson);
571 addEntry(x509Name, "C", country);
572 addEntry(x509Name, "emailAddress", email);
573 addEntry(x509Name, "GN", givenName);
574 addEntry(x509Name, "initials", initials);
575 addEntry(x509Name, "algorithm", keyPairAlgorithm);
576 if (!keyUsage.empty())
577 {
578 for (auto& usage : keyUsage)
579 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500580 if (isExtendedKeyUsage(usage))
581 {
582 addEntry(x509Name, "extendedKeyUsage", usage);
583 }
584 else
585 {
586 addEntry(x509Name, "keyUsage", usage);
587 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500588 }
589 }
590 addEntry(x509Name, "O", organization);
Jayanth Othayothdc91fb62021-05-04 23:17:47 -0500591 addEntry(x509Name, "OU", organizationalUnit);
Marri Devender Raof4682712019-03-19 05:00:28 -0500592 addEntry(x509Name, "ST", state);
593 addEntry(x509Name, "SN", surname);
594 addEntry(x509Name, "unstructuredName", unstructuredName);
595
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800596 EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500597
598 log<level::INFO>("Given Key pair algorithm",
599 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
600
601 // Used EC algorithm as default if user did not give algorithm type.
602 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500603 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500604 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500605 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500606 else
607 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500608 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
609 "RSA and EC only");
610 elog<InvalidArgument>(
611 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
612 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
613 }
614
615 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
616 if (ret == 0)
617 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800618 log<level::ERR>("Error occurred while setting Public key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500619 elog<InternalFailure>();
620 }
621
622 // Write private key to file
Nan Zhou718eef32021-12-28 11:03:30 -0800623 writePrivateKey(pKey, defaultPrivateKeyFileName);
Marri Devender Raof4682712019-03-19 05:00:28 -0500624
625 // set sign key of x509 req
626 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500627 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500628 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800629 log<level::ERR>("Error occurred while signing key of x509");
Marri Devender Raof4682712019-03-19 05:00:28 -0500630 elog<InternalFailure>();
631 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500632
Marri Devender Raof4682712019-03-19 05:00:28 -0500633 log<level::INFO>("Writing CSR to file");
Nan Zhou718eef32021-12-28 11:03:30 -0800634 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500635 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500636}
637
Marri Devender Rao76411052019-08-07 01:25:07 -0500638bool Manager::isExtendedKeyUsage(const std::string& usage)
639{
640 const static std::array<const char*, 6> usageList = {
641 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
642 "Timestamping", "CodeSigning", "EmailProtection"};
643 auto it = std::find_if(
644 usageList.begin(), usageList.end(),
645 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
646 return it != usageList.end();
647}
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800648EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500649{
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500650 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500651 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500652 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500653 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500654 log<level::INFO>(
655 "KeyBitLength is not given.Hence, using default KeyBitLength",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800656 entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
657 keyBitLen = defaultKeyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500658 }
Patrick Williams26fb83e2021-12-14 14:08:28 -0600659
660#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
661
662 // generate rsa key
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800663 BignumPtr bne(BN_new(), ::BN_free);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600664 auto ret = BN_set_word(bne.get(), RSA_F4);
665 if (ret == 0)
666 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800667 log<level::ERR>("Error occurred during BN_set_word call");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600668 elog<InternalFailure>();
669 }
Nan Zhou762da742022-01-14 17:21:44 -0800670 using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
671 RSAPtr rsa(RSA_new(), ::RSA_free);
672 ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500673 if (ret != 1)
674 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800675 log<level::ERR>("Error occurred during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500676 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500677 elog<InternalFailure>();
678 }
679
680 // set public key of x509 req
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800681 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Nan Zhou762da742022-01-14 17:21:44 -0800682 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
Marri Devender Raof4682712019-03-19 05:00:28 -0500683 if (ret == 0)
684 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800685 log<level::ERR>("Error occurred during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500686 elog<InternalFailure>();
687 }
Nan Zhou762da742022-01-14 17:21:44 -0800688 // Now |rsa| is managed by |pKey|
689 rsa.release();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500690 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600691
692#else
693 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
694 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
695 if (!ctx)
696 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800697 log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600698 elog<InternalFailure>();
699 }
700
701 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
702 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
703
704 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800705 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600706 elog<InternalFailure>();
707 }
708
709 EVP_PKEY* pKey = nullptr;
710 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
711 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800712 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600713 elog<InternalFailure>();
714 }
715
716 return {pKey, &::EVP_PKEY_free};
717#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500718}
719
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800720EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500721{
722 std::string curId(curveId);
723
724 if (curId.empty())
725 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500726 log<level::INFO>(
727 "KeyCurveId is not given. Hence using default curve id",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800728 entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
729 curId = defaultKeyCurveID;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500730 }
731
732 int ecGrp = OBJ_txt2nid(curId.c_str());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500733 if (ecGrp == NID_undef)
734 {
735 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800736 "Error occurred during convert the curve id string format into NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500737 entry("KEYCURVEID=%s", curId.c_str()));
738 elog<InternalFailure>();
739 }
740
Patrick Williams26fb83e2021-12-14 14:08:28 -0600741#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
742
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500743 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
744
Nan Zhoucfb58022021-12-28 11:02:26 -0800745 if (ecKey == nullptr)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500746 {
747 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800748 "Error occurred during create the EC_Key object from NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500749 entry("ECGROUP=%d", ecGrp));
750 elog<InternalFailure>();
751 }
752
753 // If you want to save a key and later load it with
754 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
755 // flag on the key.
756 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
757
758 int ret = EC_KEY_generate_key(ecKey);
759
760 if (ret == 0)
761 {
762 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800763 log<level::ERR>("Error occurred during generate EC key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500764 elog<InternalFailure>();
765 }
766
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800767 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500768 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
769 if (ret == 0)
770 {
771 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800772 log<level::ERR>("Error occurred during assign EC Key into EVP");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500773 elog<InternalFailure>();
774 }
775
776 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600777
778#else
779 auto holder_of_key = [](EVP_PKEY* key) {
780 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
781 key, &::EVP_PKEY_free};
782 };
783
784 // Create context to set up curve parameters.
785 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
786 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
787 if (!ctx)
788 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800789 log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600790 elog<InternalFailure>();
791 }
792
793 // Set up curve parameters.
794 EVP_PKEY* params = nullptr;
795
796 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
797 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
798 0) ||
799 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
800 (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
801 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800802 log<level::ERR>("Error occurred setting curve parameters");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600803 elog<InternalFailure>();
804 }
805
806 // Move parameters to RAII holder.
807 auto pparms = holder_of_key(params);
808
809 // Create new context for key.
810 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
811
812 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
813 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800814 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600815 elog<InternalFailure>();
816 }
817
818 EVP_PKEY* pKey = nullptr;
819 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
820 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800821 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600822 elog<InternalFailure>();
823 }
824
825 return holder_of_key(pKey);
826#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500827}
828
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800829void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500830 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500831{
832 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500833 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500834 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500835
836 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
Nan Zhoucfb58022021-12-28 11:02:26 -0800837 if (fp == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500838 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800839 log<level::ERR>("Error occurred creating private key file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500840 elog<InternalFailure>();
841 }
Nan Zhoucfb58022021-12-28 11:02:26 -0800842 int ret =
843 PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500844 std::fclose(fp);
845 if (ret == 0)
846 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800847 log<level::ERR>("Error occurred while writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500848 elog<InternalFailure>();
849 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500850}
851
852void Manager::addEntry(X509_NAME* x509Name, const char* field,
853 const std::string& bytes)
854{
855 if (bytes.empty())
856 {
857 return;
858 }
859 int ret = X509_NAME_add_entry_by_txt(
860 x509Name, field, MBSTRING_ASC,
861 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
862 if (ret != 1)
863 {
864 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
865 entry("VALUE=%s", bytes.c_str()));
866 elog<InternalFailure>();
867 }
868}
869
870void Manager::createCSRObject(const Status& status)
871{
872 if (csrPtr)
873 {
874 csrPtr.reset(nullptr);
875 }
876 auto csrObjectPath = objectPath + '/' + "csr";
877 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
878 certInstallPath.c_str(), status);
879}
880
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800881void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
Marri Devender Raof4682712019-03-19 05:00:28 -0500882{
883 if (fs::exists(filePath))
884 {
885 log<level::INFO>("Removing the existing file",
886 entry("FILENAME=%s", filePath.c_str()));
887 if (!fs::remove(filePath.c_str()))
888 {
889 log<level::ERR>("Unable to remove the file",
890 entry("FILENAME=%s", filePath.c_str()));
891 elog<InternalFailure>();
892 }
893 }
894
Nan Zhoucfb58022021-12-28 11:02:26 -0800895 FILE* fp = nullptr;
Marri Devender Raof4682712019-03-19 05:00:28 -0500896
Nan Zhoucfb58022021-12-28 11:02:26 -0800897 if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500898 {
899 log<level::ERR>("Error opening the file to write the CSR",
900 entry("FILENAME=%s", filePath.c_str()));
901 elog<InternalFailure>();
902 }
903
904 int rc = PEM_write_X509_REQ(fp, x509Req.get());
905 if (!rc)
906 {
907 log<level::ERR>("PEM write routine failed",
908 entry("FILENAME=%s", filePath.c_str()));
909 std::fclose(fp);
910 elog<InternalFailure>();
911 }
912 std::fclose(fp);
913}
914
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200915void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500916{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200917 auto certObjectPath = objectPath + '/';
918
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800919 if (certType == CertificateType::Authority)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500920 {
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100921 // Check whether install path is a directory.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200922 if (!fs::is_directory(certInstallPath))
923 {
924 log<level::ERR>("Certificate installation path exists and it is "
925 "not a directory");
926 elog<InternalFailure>();
Nan Zhou6ec13c82021-12-30 11:34:50 -0800927 }
928
929 // If the authorities list exists, recover from it and return
930 if (fs::path authoritiesListFilePath =
931 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
932 fs::exists(authoritiesListFilePath))
933 {
934 // remove all other files and directories
935 for (auto& path : fs::directory_iterator(certInstallPath))
936 {
937 if (path.path() != authoritiesListFilePath)
938 {
939 fs::remove_all(path);
940 }
941 }
942 installAll(authoritiesListFilePath);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200943 return;
944 }
945
946 for (auto& path : fs::directory_iterator(certInstallPath))
947 {
948 try
949 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100950 // Assume here any regular file located in certificate directory
951 // contains certificates body. Do not want to use soft links
952 // would add value.
953 if (fs::is_regular_file(path))
954 {
955 installedCerts.emplace_back(std::make_unique<Certificate>(
956 bus, certObjectPath + std::to_string(certIdCounter++),
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800957 certType, certInstallPath, path.path(),
958 certWatchPtr.get(), *this));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100959 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200960 }
961 catch (const InternalFailure& e)
962 {
963 report<InternalFailure>();
964 }
965 catch (const InvalidCertificate& e)
966 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800967 report<InvalidCertificate>(InvalidCertificateReason(
968 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200969 }
970 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500971 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200972 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500973 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200974 try
975 {
976 installedCerts.emplace_back(std::make_unique<Certificate>(
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100977 bus, certObjectPath + '1', certType, certInstallPath,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800978 certInstallPath, certWatchPtr.get(), *this));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200979 }
980 catch (const InternalFailure& e)
981 {
982 report<InternalFailure>();
983 }
984 catch (const InvalidCertificate& e)
985 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800986 report<InvalidCertificate>(InvalidCertificateReason(
987 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200988 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500989 }
990}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500991
992void Manager::createRSAPrivateKeyFile()
993{
994 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -0800995 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500996
997 try
998 {
999 if (!fs::exists(rsaPrivateKeyFileName))
1000 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001001 writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
Nan Zhou718eef32021-12-28 11:03:30 -08001002 defaultRSAPrivateKeyFileName);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001003 }
1004 }
1005 catch (const InternalFailure& e)
1006 {
1007 report<InternalFailure>();
1008 }
1009}
1010
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001011EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001012{
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001013 if (keyBitLength != supportedKeyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001014 {
1015 log<level::ERR>(
1016 "Given Key bit length is not supported",
1017 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001018 entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001019 elog<InvalidArgument>(
1020 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1021 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1022 }
1023 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -08001024 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001025
1026 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1027 if (!privateKeyFile)
1028 {
1029 log<level::ERR>("Unable to open RSA private key file to read",
1030 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
1031 entry("ERRORREASON=%s", strerror(errno)));
1032 elog<InternalFailure>();
1033 }
1034
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001035 EVPPkeyPtr privateKey(
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001036 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1037 ::EVP_PKEY_free);
1038 std::fclose(privateKeyFile);
1039
1040 if (!privateKey)
1041 {
Nan Zhoubf3cf752021-12-28 11:02:07 -08001042 log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001043 elog<InternalFailure>();
1044 }
1045 return privateKey;
1046}
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001047
1048void Manager::storageUpdate()
1049{
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001050 if (certType == CertificateType::Authority)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001051 {
1052 // Remove symbolic links in the certificate directory
1053 for (auto& certPath : fs::directory_iterator(certInstallPath))
1054 {
1055 try
1056 {
1057 if (fs::is_symlink(certPath))
1058 {
1059 fs::remove(certPath);
1060 }
1061 }
1062 catch (const std::exception& e)
1063 {
1064 log<level::ERR>(
1065 "Failed to remove symlink for certificate",
1066 entry("ERR=%s", e.what()),
1067 entry("SYMLINK=%s", certPath.path().string().c_str()));
1068 elog<InternalFailure>();
1069 }
1070 }
1071 }
1072
1073 for (const auto& cert : installedCerts)
1074 {
1075 cert->storageUpdate();
1076 }
1077}
1078
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001079void Manager::reloadOrReset(const std::string& unit)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001080{
1081 if (!unit.empty())
1082 {
1083 try
1084 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001085 constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1086 constexpr auto defaultSystemdObjectPath =
1087 "/org/freedesktop/systemd1";
1088 constexpr auto defaultSystemdInterface =
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001089 "org.freedesktop.systemd1.Manager";
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001090 auto method = bus.new_method_call(
1091 defaultSystemdService, defaultSystemdObjectPath,
1092 defaultSystemdInterface, "ReloadOrRestartUnit");
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001093 method.append(unit, "replace");
1094 bus.call_noreply(method);
1095 }
Patrick Williamsca128112021-09-02 09:36:07 -05001096 catch (const sdbusplus::exception::exception& e)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001097 {
1098 log<level::ERR>("Failed to reload or restart service",
1099 entry("ERR=%s", e.what()),
1100 entry("UNIT=%s", unit.c_str()));
1101 elog<InternalFailure>();
1102 }
1103 }
1104}
1105
1106bool Manager::isCertificateUnique(const std::string& filePath,
1107 const Certificate* const certToDrop)
1108{
1109 if (std::any_of(
1110 installedCerts.begin(), installedCerts.end(),
1111 [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
1112 return cert.get() != certToDrop && cert->isSame(filePath);
1113 }))
1114 {
1115 return false;
1116 }
1117 else
1118 {
1119 return true;
1120 }
1121}
1122
Nan Zhoue1289ad2021-12-28 11:02:56 -08001123} // namespace phosphor::certs