blob: 936b470a90c04035cd2eadad001b1ed5e3b2ba05 [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
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500133Manager::Manager(sdbusplus::bus_t& 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
Nan Zhou78357b02022-06-09 22:33:35 +0000311 log<level::INFO>("Starts authority list install");
312
Nan Zhou6ec13c82021-12-30 11:34:50 -0800313 fs::path authorityStore(certInstallPath);
314 fs::path authoritiesListFile =
315 authorityStore / defaultAuthoritiesListFileName;
316
317 // Atomically install all the certificates
318 fs::path tempPath = Certificate::generateUniqueFilePath(authorityStore);
319 fs::create_directory(tempPath);
320 // Copies the authorities list
321 Certificate::copyCertificate(sourceFile,
322 tempPath / defaultAuthoritiesListFileName);
323 std::vector<std::unique_ptr<Certificate>> tempCertificates;
324 uint64_t tempCertIdCounter = certIdCounter;
325 X509StorePtr x509Store = getX509Store(sourceFile);
326 for (const auto& authority : authorities)
327 {
328 std::string certObjectPath =
329 objectPath + '/' + std::to_string(tempCertIdCounter);
330 tempCertificates.emplace_back(std::make_unique<Certificate>(
331 bus, certObjectPath, certType, tempPath, *x509Store, authority,
332 certWatchPtr.get(), *this));
333 tempCertIdCounter++;
334 }
335
336 // We are good now, issue swap
337 installedCerts = std::move(tempCertificates);
338 certIdCounter = tempCertIdCounter;
339 // Rename all the certificates including the authorities list
340 for (const fs::path& f : fs::directory_iterator(tempPath))
341 {
342 if (fs::is_symlink(f))
343 {
344 continue;
345 }
346 fs::rename(/*from=*/f, /*to=*/certInstallPath / f.filename());
347 }
348 // Update file locations and create symbol links
349 for (const auto& cert : installedCerts)
350 {
351 cert->setCertInstallPath(certInstallPath);
352 cert->setCertFilePath(certInstallPath /
353 fs::path(cert->getCertFilePath()).filename());
354 cert->storageUpdate();
355 }
356 // Remove the temporary folder
357 fs::remove_all(tempPath);
358
359 std::vector<sdbusplus::message::object_path> objects;
360 for (const auto& certificate : installedCerts)
361 {
362 objects.emplace_back(certificate->getObjectPath());
363 }
364
Nan Zhou78357b02022-06-09 22:33:35 +0000365 log<level::INFO>("Finishes authority list install; reload units starts");
Nan Zhou6ec13c82021-12-30 11:34:50 -0800366 reloadOrReset(unitToRestart);
367 return objects;
368}
369
370std::vector<sdbusplus::message::object_path>
371 Manager::replaceAll(std::string filePath)
372{
373 installedCerts.clear();
374 certIdCounter = 1;
375 storageUpdate();
376 return installAll(std::move(filePath));
377}
378
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200379void Manager::deleteAll()
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500380{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600381 // TODO: #Issue 4 when a certificate is deleted system auto generates
382 // certificate file. At present we are not supporting creation of
383 // certificate object for the auto-generated certificate file as
384 // deletion if only applicable for REST server and Bmcweb does not allow
385 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200386 installedCerts.clear();
Nan Zhou6ec13c82021-12-30 11:34:50 -0800387 // If the authorities list exists, delete it as well
388 if (certType == CertificateType::Authority)
389 {
390 if (fs::path authoritiesList =
391 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
392 fs::exists(authoritiesList))
393 {
394 fs::remove(authoritiesList);
395 }
396 }
397 certIdCounter = 1;
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100398 storageUpdate();
399 reloadOrReset(unitToRestart);
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500400}
Marri Devender Raof4682712019-03-19 05:00:28 -0500401
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100402void Manager::deleteCertificate(const Certificate* const certificate)
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200403{
404 std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
405 std::find_if(installedCerts.begin(), installedCerts.end(),
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100406 [certificate](std::unique_ptr<Certificate> const& cert) {
407 return (cert.get() == certificate);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200408 });
409 if (certIt != installedCerts.end())
410 {
411 installedCerts.erase(certIt);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100412 storageUpdate();
413 reloadOrReset(unitToRestart);
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200414 }
415 else
416 {
417 log<level::ERR>("Certificate does not exist",
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100418 entry("ID=%s", certificate->getCertId().c_str()));
419 elog<InternalFailure>();
420 }
421}
422
423void Manager::replaceCertificate(Certificate* const certificate,
424 const std::string& filePath)
425{
426 if (isCertificateUnique(filePath, certificate))
427 {
428 certificate->install(filePath);
429 storageUpdate();
430 reloadOrReset(unitToRestart);
431 }
432 else
433 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800434 elog<NotAllowed>(NotAllowedReason("Certificate already exist"));
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200435 }
436}
437
Marri Devender Raof4682712019-03-19 05:00:28 -0500438std::string Manager::generateCSR(
439 std::vector<std::string> alternativeNames, std::string challengePassword,
440 std::string city, std::string commonName, std::string contactPerson,
441 std::string country, std::string email, std::string givenName,
442 std::string initials, int64_t keyBitLength, std::string keyCurveId,
443 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
444 std::string organization, std::string organizationalUnit, std::string state,
445 std::string surname, std::string unstructuredName)
446{
447 // We support only one CSR.
448 csrPtr.reset(nullptr);
449 auto pid = fork();
450 if (pid == -1)
451 {
452 log<level::ERR>("Error occurred during forking process");
453 report<InternalFailure>();
454 }
455 else if (pid == 0)
456 {
457 try
458 {
459 generateCSRHelper(alternativeNames, challengePassword, city,
460 commonName, contactPerson, country, email,
461 givenName, initials, keyBitLength, keyCurveId,
462 keyPairAlgorithm, keyUsage, organization,
463 organizationalUnit, state, surname,
464 unstructuredName);
465 exit(EXIT_SUCCESS);
466 }
467 catch (const InternalFailure& e)
468 {
469 // commit the error reported in child process and exit
470 // Callback method from SDEvent Loop looks for exit status
471 exit(EXIT_FAILURE);
472 commit<InternalFailure>();
473 }
Ramesh Iyyard2393f22020-10-29 09:46:51 -0500474 catch (const InvalidArgument& e)
475 {
476 // commit the error reported in child process and exit
477 // Callback method from SDEvent Loop looks for exit status
478 exit(EXIT_FAILURE);
479 commit<InvalidArgument>();
480 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500481 }
482 else
483 {
484 using namespace sdeventplus::source;
485 Child::Callback callback = [this](Child& eventSource,
486 const siginfo_t* si) {
487 eventSource.set_enabled(Enabled::On);
488 if (si->si_status != 0)
489 {
490 this->createCSRObject(Status::FAILURE);
491 }
492 else
493 {
494 this->createCSRObject(Status::SUCCESS);
495 }
496 };
497 try
498 {
499 sigset_t ss;
500 if (sigemptyset(&ss) < 0)
501 {
502 log<level::ERR>("Unable to initialize signal set");
503 elog<InternalFailure>();
504 }
505 if (sigaddset(&ss, SIGCHLD) < 0)
506 {
507 log<level::ERR>("Unable to add signal to signal set");
508 elog<InternalFailure>();
509 }
510
511 // Block SIGCHLD first, so that the event loop can handle it
Nan Zhoucfb58022021-12-28 11:02:26 -0800512 if (sigprocmask(SIG_BLOCK, &ss, nullptr) < 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500513 {
514 log<level::ERR>("Unable to block signal");
515 elog<InternalFailure>();
516 }
517 if (childPtr)
518 {
519 childPtr.reset();
520 }
521 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
522 std::move(callback));
523 }
524 catch (const InternalFailure& e)
525 {
526 commit<InternalFailure>();
527 }
528 }
529 auto csrObjectPath = objectPath + '/' + "csr";
530 return csrObjectPath;
531}
532
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200533std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500534{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200535 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500536}
537
Marri Devender Raof4682712019-03-19 05:00:28 -0500538void Manager::generateCSRHelper(
539 std::vector<std::string> alternativeNames, std::string challengePassword,
540 std::string city, std::string commonName, std::string contactPerson,
541 std::string country, std::string email, std::string givenName,
542 std::string initials, int64_t keyBitLength, std::string keyCurveId,
543 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
544 std::string organization, std::string organizationalUnit, std::string state,
545 std::string surname, std::string unstructuredName)
546{
547 int ret = 0;
548
549 // set version of x509 req
550 int nVersion = 1;
551 // TODO: Issue#6 need to make version number configurable
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800552 X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
Marri Devender Raof4682712019-03-19 05:00:28 -0500553 ret = X509_REQ_set_version(x509Req.get(), nVersion);
554 if (ret == 0)
555 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800556 log<level::ERR>("Error occurred during X509_REQ_set_version call");
Marri Devender Raof4682712019-03-19 05:00:28 -0500557 elog<InternalFailure>();
558 }
559
560 // set subject of x509 req
561 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
562
563 if (!alternativeNames.empty())
564 {
565 for (auto& name : alternativeNames)
566 {
567 addEntry(x509Name, "subjectAltName", name);
568 }
569 }
570 addEntry(x509Name, "challengePassword", challengePassword);
571 addEntry(x509Name, "L", city);
572 addEntry(x509Name, "CN", commonName);
573 addEntry(x509Name, "name", contactPerson);
574 addEntry(x509Name, "C", country);
575 addEntry(x509Name, "emailAddress", email);
576 addEntry(x509Name, "GN", givenName);
577 addEntry(x509Name, "initials", initials);
578 addEntry(x509Name, "algorithm", keyPairAlgorithm);
579 if (!keyUsage.empty())
580 {
581 for (auto& usage : keyUsage)
582 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500583 if (isExtendedKeyUsage(usage))
584 {
585 addEntry(x509Name, "extendedKeyUsage", usage);
586 }
587 else
588 {
589 addEntry(x509Name, "keyUsage", usage);
590 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500591 }
592 }
593 addEntry(x509Name, "O", organization);
Jayanth Othayothdc91fb62021-05-04 23:17:47 -0500594 addEntry(x509Name, "OU", organizationalUnit);
Marri Devender Raof4682712019-03-19 05:00:28 -0500595 addEntry(x509Name, "ST", state);
596 addEntry(x509Name, "SN", surname);
597 addEntry(x509Name, "unstructuredName", unstructuredName);
598
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800599 EVPPkeyPtr pKey(nullptr, ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500600
601 log<level::INFO>("Given Key pair algorithm",
602 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
603
604 // Used EC algorithm as default if user did not give algorithm type.
605 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500606 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500607 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500608 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500609 else
610 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500611 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
612 "RSA and EC only");
613 elog<InvalidArgument>(
614 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
615 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
616 }
617
618 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
619 if (ret == 0)
620 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800621 log<level::ERR>("Error occurred while setting Public key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500622 elog<InternalFailure>();
623 }
624
625 // Write private key to file
Nan Zhou718eef32021-12-28 11:03:30 -0800626 writePrivateKey(pKey, defaultPrivateKeyFileName);
Marri Devender Raof4682712019-03-19 05:00:28 -0500627
628 // set sign key of x509 req
629 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500630 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500631 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800632 log<level::ERR>("Error occurred while signing key of x509");
Marri Devender Raof4682712019-03-19 05:00:28 -0500633 elog<InternalFailure>();
634 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500635
Marri Devender Raof4682712019-03-19 05:00:28 -0500636 log<level::INFO>("Writing CSR to file");
Nan Zhou718eef32021-12-28 11:03:30 -0800637 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500638 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500639}
640
Marri Devender Rao76411052019-08-07 01:25:07 -0500641bool Manager::isExtendedKeyUsage(const std::string& usage)
642{
643 const static std::array<const char*, 6> usageList = {
644 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
645 "Timestamping", "CodeSigning", "EmailProtection"};
646 auto it = std::find_if(
647 usageList.begin(), usageList.end(),
648 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
649 return it != usageList.end();
650}
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800651EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500652{
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500653 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500654 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500655 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500656 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500657 log<level::INFO>(
658 "KeyBitLength is not given.Hence, using default KeyBitLength",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800659 entry("DEFAULTKEYBITLENGTH=%d", defaultKeyBitLength));
660 keyBitLen = defaultKeyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500661 }
Patrick Williams26fb83e2021-12-14 14:08:28 -0600662
663#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
664
665 // generate rsa key
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800666 BignumPtr bne(BN_new(), ::BN_free);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600667 auto ret = BN_set_word(bne.get(), RSA_F4);
668 if (ret == 0)
669 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800670 log<level::ERR>("Error occurred during BN_set_word call");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600671 elog<InternalFailure>();
672 }
Nan Zhou762da742022-01-14 17:21:44 -0800673 using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
674 RSAPtr rsa(RSA_new(), ::RSA_free);
675 ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500676 if (ret != 1)
677 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800678 log<level::ERR>("Error occurred during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500679 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500680 elog<InternalFailure>();
681 }
682
683 // set public key of x509 req
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800684 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Nan Zhou762da742022-01-14 17:21:44 -0800685 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
Marri Devender Raof4682712019-03-19 05:00:28 -0500686 if (ret == 0)
687 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800688 log<level::ERR>("Error occurred during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500689 elog<InternalFailure>();
690 }
Nan Zhou762da742022-01-14 17:21:44 -0800691 // Now |rsa| is managed by |pKey|
692 rsa.release();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500693 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600694
695#else
696 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
697 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
698 if (!ctx)
699 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800700 log<level::ERR>("Error occurred creating EVP_PKEY_CTX from algorithm");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600701 elog<InternalFailure>();
702 }
703
704 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
705 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
706
707 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800708 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600709 elog<InternalFailure>();
710 }
711
712 EVP_PKEY* pKey = nullptr;
713 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
714 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800715 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600716 elog<InternalFailure>();
717 }
718
719 return {pKey, &::EVP_PKEY_free};
720#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500721}
722
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800723EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500724{
725 std::string curId(curveId);
726
727 if (curId.empty())
728 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500729 log<level::INFO>(
730 "KeyCurveId is not given. Hence using default curve id",
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800731 entry("DEFAULTKEYCURVEID=%s", defaultKeyCurveID));
732 curId = defaultKeyCurveID;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500733 }
734
735 int ecGrp = OBJ_txt2nid(curId.c_str());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500736 if (ecGrp == NID_undef)
737 {
738 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800739 "Error occurred during convert the curve id string format into NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500740 entry("KEYCURVEID=%s", curId.c_str()));
741 elog<InternalFailure>();
742 }
743
Patrick Williams26fb83e2021-12-14 14:08:28 -0600744#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
745
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500746 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
747
Nan Zhoucfb58022021-12-28 11:02:26 -0800748 if (ecKey == nullptr)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500749 {
750 log<level::ERR>(
Nan Zhoubf3cf752021-12-28 11:02:07 -0800751 "Error occurred during create the EC_Key object from NID",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500752 entry("ECGROUP=%d", ecGrp));
753 elog<InternalFailure>();
754 }
755
756 // If you want to save a key and later load it with
757 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
758 // flag on the key.
759 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
760
761 int ret = EC_KEY_generate_key(ecKey);
762
763 if (ret == 0)
764 {
765 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800766 log<level::ERR>("Error occurred during generate EC key");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500767 elog<InternalFailure>();
768 }
769
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800770 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500771 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
772 if (ret == 0)
773 {
774 EC_KEY_free(ecKey);
Nan Zhoubf3cf752021-12-28 11:02:07 -0800775 log<level::ERR>("Error occurred during assign EC Key into EVP");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500776 elog<InternalFailure>();
777 }
778
779 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600780
781#else
782 auto holder_of_key = [](EVP_PKEY* key) {
783 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
784 key, &::EVP_PKEY_free};
785 };
786
787 // Create context to set up curve parameters.
788 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
789 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
790 if (!ctx)
791 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800792 log<level::ERR>("Error occurred creating EVP_PKEY_CTX for params");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600793 elog<InternalFailure>();
794 }
795
796 // Set up curve parameters.
797 EVP_PKEY* params = nullptr;
798
799 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
800 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
801 0) ||
802 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
803 (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
804 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800805 log<level::ERR>("Error occurred setting curve parameters");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600806 elog<InternalFailure>();
807 }
808
809 // Move parameters to RAII holder.
810 auto pparms = holder_of_key(params);
811
812 // Create new context for key.
813 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
814
815 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
816 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800817 log<level::ERR>("Error occurred initializing keygen context");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600818 elog<InternalFailure>();
819 }
820
821 EVP_PKEY* pKey = nullptr;
822 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
823 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800824 log<level::ERR>("Error occurred during generate EC key");
Patrick Williams26fb83e2021-12-14 14:08:28 -0600825 elog<InternalFailure>();
826 }
827
828 return holder_of_key(pKey);
829#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500830}
831
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800832void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500833 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500834{
835 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500836 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500837 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500838
839 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
Nan Zhoucfb58022021-12-28 11:02:26 -0800840 if (fp == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500841 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800842 log<level::ERR>("Error occurred creating private key file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500843 elog<InternalFailure>();
844 }
Nan Zhoucfb58022021-12-28 11:02:26 -0800845 int ret =
846 PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0, nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500847 std::fclose(fp);
848 if (ret == 0)
849 {
Nan Zhoubf3cf752021-12-28 11:02:07 -0800850 log<level::ERR>("Error occurred while writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500851 elog<InternalFailure>();
852 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500853}
854
855void Manager::addEntry(X509_NAME* x509Name, const char* field,
856 const std::string& bytes)
857{
858 if (bytes.empty())
859 {
860 return;
861 }
862 int ret = X509_NAME_add_entry_by_txt(
863 x509Name, field, MBSTRING_ASC,
864 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
865 if (ret != 1)
866 {
867 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
868 entry("VALUE=%s", bytes.c_str()));
869 elog<InternalFailure>();
870 }
871}
872
873void Manager::createCSRObject(const Status& status)
874{
875 if (csrPtr)
876 {
877 csrPtr.reset(nullptr);
878 }
879 auto csrObjectPath = objectPath + '/' + "csr";
880 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
881 certInstallPath.c_str(), status);
882}
883
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800884void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
Marri Devender Raof4682712019-03-19 05:00:28 -0500885{
886 if (fs::exists(filePath))
887 {
888 log<level::INFO>("Removing the existing file",
889 entry("FILENAME=%s", filePath.c_str()));
890 if (!fs::remove(filePath.c_str()))
891 {
892 log<level::ERR>("Unable to remove the file",
893 entry("FILENAME=%s", filePath.c_str()));
894 elog<InternalFailure>();
895 }
896 }
897
Nan Zhoucfb58022021-12-28 11:02:26 -0800898 FILE* fp = nullptr;
Marri Devender Raof4682712019-03-19 05:00:28 -0500899
Nan Zhoucfb58022021-12-28 11:02:26 -0800900 if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500901 {
902 log<level::ERR>("Error opening the file to write the CSR",
903 entry("FILENAME=%s", filePath.c_str()));
904 elog<InternalFailure>();
905 }
906
907 int rc = PEM_write_X509_REQ(fp, x509Req.get());
908 if (!rc)
909 {
910 log<level::ERR>("PEM write routine failed",
911 entry("FILENAME=%s", filePath.c_str()));
912 std::fclose(fp);
913 elog<InternalFailure>();
914 }
915 std::fclose(fp);
916}
917
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200918void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500919{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200920 auto certObjectPath = objectPath + '/';
921
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800922 if (certType == CertificateType::Authority)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500923 {
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100924 // Check whether install path is a directory.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200925 if (!fs::is_directory(certInstallPath))
926 {
927 log<level::ERR>("Certificate installation path exists and it is "
928 "not a directory");
929 elog<InternalFailure>();
Nan Zhou6ec13c82021-12-30 11:34:50 -0800930 }
931
932 // If the authorities list exists, recover from it and return
933 if (fs::path authoritiesListFilePath =
934 fs::path(certInstallPath) / defaultAuthoritiesListFileName;
935 fs::exists(authoritiesListFilePath))
936 {
937 // remove all other files and directories
938 for (auto& path : fs::directory_iterator(certInstallPath))
939 {
940 if (path.path() != authoritiesListFilePath)
941 {
942 fs::remove_all(path);
943 }
944 }
945 installAll(authoritiesListFilePath);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200946 return;
947 }
948
949 for (auto& path : fs::directory_iterator(certInstallPath))
950 {
951 try
952 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100953 // Assume here any regular file located in certificate directory
954 // contains certificates body. Do not want to use soft links
955 // would add value.
956 if (fs::is_regular_file(path))
957 {
958 installedCerts.emplace_back(std::make_unique<Certificate>(
959 bus, certObjectPath + std::to_string(certIdCounter++),
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800960 certType, certInstallPath, path.path(),
961 certWatchPtr.get(), *this));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100962 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200963 }
964 catch (const InternalFailure& e)
965 {
966 report<InternalFailure>();
967 }
968 catch (const InvalidCertificate& e)
969 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800970 report<InvalidCertificate>(InvalidCertificateReason(
971 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200972 }
973 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500974 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200975 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500976 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200977 try
978 {
979 installedCerts.emplace_back(std::make_unique<Certificate>(
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100980 bus, certObjectPath + '1', certType, certInstallPath,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800981 certInstallPath, certWatchPtr.get(), *this));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200982 }
983 catch (const InternalFailure& e)
984 {
985 report<InternalFailure>();
986 }
987 catch (const InvalidCertificate& e)
988 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800989 report<InvalidCertificate>(InvalidCertificateReason(
990 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200991 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500992 }
993}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500994
995void Manager::createRSAPrivateKeyFile()
996{
997 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -0800998 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500999
1000 try
1001 {
1002 if (!fs::exists(rsaPrivateKeyFileName))
1003 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001004 writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
Nan Zhou718eef32021-12-28 11:03:30 -08001005 defaultRSAPrivateKeyFileName);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001006 }
1007 }
1008 catch (const InternalFailure& e)
1009 {
1010 report<InternalFailure>();
1011 }
1012}
1013
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001014EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001015{
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001016 if (keyBitLength != supportedKeyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001017 {
1018 log<level::ERR>(
1019 "Given Key bit length is not supported",
1020 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001021 entry("SUPPORTEDKEYBITLENGTH=%d", supportedKeyBitLength));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001022 elog<InvalidArgument>(
1023 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1024 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1025 }
1026 fs::path rsaPrivateKeyFileName =
Nan Zhou718eef32021-12-28 11:03:30 -08001027 certParentInstallPath / defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001028
1029 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1030 if (!privateKeyFile)
1031 {
1032 log<level::ERR>("Unable to open RSA private key file to read",
1033 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
1034 entry("ERRORREASON=%s", strerror(errno)));
1035 elog<InternalFailure>();
1036 }
1037
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001038 EVPPkeyPtr privateKey(
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001039 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1040 ::EVP_PKEY_free);
1041 std::fclose(privateKeyFile);
1042
1043 if (!privateKey)
1044 {
Nan Zhoubf3cf752021-12-28 11:02:07 -08001045 log<level::ERR>("Error occurred during PEM_read_PrivateKey call");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001046 elog<InternalFailure>();
1047 }
1048 return privateKey;
1049}
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001050
1051void Manager::storageUpdate()
1052{
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001053 if (certType == CertificateType::Authority)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001054 {
1055 // Remove symbolic links in the certificate directory
1056 for (auto& certPath : fs::directory_iterator(certInstallPath))
1057 {
1058 try
1059 {
1060 if (fs::is_symlink(certPath))
1061 {
1062 fs::remove(certPath);
1063 }
1064 }
1065 catch (const std::exception& e)
1066 {
1067 log<level::ERR>(
1068 "Failed to remove symlink for certificate",
1069 entry("ERR=%s", e.what()),
1070 entry("SYMLINK=%s", certPath.path().string().c_str()));
1071 elog<InternalFailure>();
1072 }
1073 }
1074 }
1075
1076 for (const auto& cert : installedCerts)
1077 {
1078 cert->storageUpdate();
1079 }
1080}
1081
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001082void Manager::reloadOrReset(const std::string& unit)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001083{
1084 if (!unit.empty())
1085 {
1086 try
1087 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001088 constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1089 constexpr auto defaultSystemdObjectPath =
1090 "/org/freedesktop/systemd1";
1091 constexpr auto defaultSystemdInterface =
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001092 "org.freedesktop.systemd1.Manager";
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001093 auto method = bus.new_method_call(
1094 defaultSystemdService, defaultSystemdObjectPath,
1095 defaultSystemdInterface, "ReloadOrRestartUnit");
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001096 method.append(unit, "replace");
1097 bus.call_noreply(method);
1098 }
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001099 catch (const sdbusplus::exception_t& e)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001100 {
1101 log<level::ERR>("Failed to reload or restart service",
1102 entry("ERR=%s", e.what()),
1103 entry("UNIT=%s", unit.c_str()));
1104 elog<InternalFailure>();
1105 }
1106 }
1107}
1108
1109bool Manager::isCertificateUnique(const std::string& filePath,
1110 const Certificate* const certToDrop)
1111{
1112 if (std::any_of(
1113 installedCerts.begin(), installedCerts.end(),
1114 [&filePath, certToDrop](std::unique_ptr<Certificate> const& cert) {
1115 return cert.get() != certToDrop && cert->isSame(filePath);
1116 }))
1117 {
1118 return false;
1119 }
1120 else
1121 {
1122 return true;
1123 }
1124}
1125
Nan Zhoue1289ad2021-12-28 11:02:56 -08001126} // namespace phosphor::certs