blob: 53a0bb31293798f04f680ced945af92dfd05cf6e [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>
Andrew Geissler8dbcc722023-12-08 10:15:42 -060010#include <openssl/err.h>
Patrick Williams26fb83e2021-12-14 14:08:28 -060011#include <openssl/evp.h>
Nan Zhou014be0b2021-12-28 18:00:14 -080012#include <openssl/obj_mac.h>
13#include <openssl/objects.h>
14#include <openssl/opensslv.h>
Marri Devender Raof4682712019-03-19 05:00:28 -050015#include <openssl/pem.h>
Nan Zhou014be0b2021-12-28 18:00:14 -080016#include <openssl/rsa.h>
Marri Devender Raof4682712019-03-19 05:00:28 -050017#include <unistd.h>
18
Patrick Williams223e4602023-05-10 07:51:11 -050019#include <phosphor-logging/elog-errors.hpp>
20#include <phosphor-logging/elog.hpp>
Ravi Tejaf2646272023-09-30 13:00:55 -050021#include <phosphor-logging/lg2.hpp>
Patrick Williams223e4602023-05-10 07:51:11 -050022#include <sdbusplus/bus.hpp>
23#include <sdbusplus/exception.hpp>
24#include <sdbusplus/message.hpp>
25#include <sdeventplus/source/base.hpp>
26#include <sdeventplus/source/child.hpp>
27#include <xyz/openbmc_project/Certs/error.hpp>
28#include <xyz/openbmc_project/Common/error.hpp>
29
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +020030#include <algorithm>
Nan Zhou014be0b2021-12-28 18:00:14 -080031#include <array>
32#include <cerrno>
33#include <chrono>
34#include <csignal>
35#include <cstdio>
36#include <cstdlib>
37#include <cstring>
38#include <exception>
Nan Zhou6ec13c82021-12-30 11:34:50 -080039#include <fstream>
Nan Zhou014be0b2021-12-28 18:00:14 -080040#include <utility>
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +010041
Nan Zhoue1289ad2021-12-28 11:02:56 -080042namespace phosphor::certs
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050043{
Nan Zhoucf06ccd2021-12-28 16:25:45 -080044namespace
45{
46namespace fs = std::filesystem;
47using ::phosphor::logging::commit;
48using ::phosphor::logging::elog;
Nan Zhoucf06ccd2021-12-28 16:25:45 -080049using ::phosphor::logging::report;
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050050
Nan Zhoucf06ccd2021-12-28 16:25:45 -080051using ::sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
52using ::sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
53using ::sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
54using NotAllowedReason =
55 ::phosphor::logging::xyz::openbmc_project::Common::NotAllowed::REASON;
56using InvalidCertificateReason = ::phosphor::logging::xyz::openbmc_project::
57 Certs::InvalidCertificate::REASON;
58using ::sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
59using Argument =
60 ::phosphor::logging::xyz::openbmc_project::Common::InvalidArgument;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050061
Nan Zhoucf06ccd2021-12-28 16:25:45 -080062// RAII support for openSSL functions.
63using X509ReqPtr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
64using EVPPkeyPtr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>;
65using BignumPtr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
Nan Zhou6ec13c82021-12-30 11:34:50 -080066using X509StorePtr = std::unique_ptr<X509_STORE, decltype(&::X509_STORE_free)>;
Nan Zhoucf06ccd2021-12-28 16:25:45 -080067
68constexpr int supportedKeyBitLength = 2048;
69constexpr int defaultKeyBitLength = 2048;
70// secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
71constexpr auto defaultKeyCurveID = "secp224r1";
Nan Zhou6ec13c82021-12-30 11:34:50 -080072// PEM certificate block markers, defined in go/rfc/7468.
73constexpr std::string_view beginCertificate = "-----BEGIN CERTIFICATE-----";
74constexpr std::string_view endCertificate = "-----END CERTIFICATE-----";
75
76/**
77 * @brief Splits the given authorities list file and returns an array of
78 * individual PEM encoded x509 certificate.
79 *
80 * @param[in] sourceFilePath - Path to the authorities list file.
81 *
82 * @return An array of individual PEM encoded x509 certificate
83 */
84std::vector<std::string> splitCertificates(const std::string& sourceFilePath)
85{
86 std::ifstream inputCertFileStream;
87 inputCertFileStream.exceptions(
88 std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
89
90 std::stringstream pemStream;
91 std::vector<std::string> certificatesList;
92 try
93 {
94 inputCertFileStream.open(sourceFilePath);
95 pemStream << inputCertFileStream.rdbuf();
96 inputCertFileStream.close();
97 }
98 catch (const std::exception& e)
99 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500100 lg2::error("Failed to read certificates list, ERR:{ERR}, SRC:{SRC}",
101 "ERR", e, "SRC", sourceFilePath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800102 elog<InternalFailure>();
103 }
104 std::string pem = pemStream.str();
105 size_t begin = 0;
106 // |begin| points to the current start position for searching the next
107 // |beginCertificate| block. When we find the beginning of the certificate,
108 // we extract the content between the beginning and the end of the current
109 // certificate. And finally we move |begin| to the end of the current
110 // certificate to start searching the next potential certificate.
111 for (begin = pem.find(beginCertificate, begin); begin != std::string::npos;
112 begin = pem.find(beginCertificate, begin))
113 {
114 size_t end = pem.find(endCertificate, begin);
115 if (end == std::string::npos)
116 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500117 lg2::error(
Nan Zhou6ec13c82021-12-30 11:34:50 -0800118 "invalid PEM contains a BEGIN identifier without an END");
119 elog<InvalidCertificate>(InvalidCertificateReason(
120 "invalid PEM contains a BEGIN identifier without an END"));
121 }
122 end += endCertificate.size();
123 certificatesList.emplace_back(pem.substr(begin, end - begin));
124 begin = end;
125 }
126 return certificatesList;
127}
128
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800129} // namespace
Marri Devender Raof4682712019-03-19 05:00:28 -0500130
Patrick Williamsb3dbfb32022-07-22 19:26:57 -0500131Manager::Manager(sdbusplus::bus_t& bus, sdeventplus::Event& event,
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800132 const char* path, CertificateType type,
133 const std::string& unit, const std::string& installPath) :
134 internal::ManagerInterface(bus, path),
Marri Devender Raof4682712019-03-19 05:00:28 -0500135 bus(bus), event(event), objectPath(path), certType(type),
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500136 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
137 certParentInstallPath(fs::path(certInstallPath).parent_path())
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500138{
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500139 try
140 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500141 // Create certificate directory if not existing.
Nan Zhoubf3cf752021-12-28 11:02:07 -0800142 // Set correct certificate directory permissions.
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500143 fs::path certDirectory;
144 try
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500145 {
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000146 if (certType == CertificateType::authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500147 {
148 certDirectory = certInstallPath;
149 }
150 else
151 {
152 certDirectory = certParentInstallPath;
153 }
154
155 if (!fs::exists(certDirectory))
156 {
157 fs::create_directories(certDirectory);
158 }
159
160 auto permission = fs::perms::owner_read | fs::perms::owner_write |
161 fs::perms::owner_exec;
162 fs::permissions(certDirectory, permission,
163 fs::perm_options::replace);
164 storageUpdate();
165 }
Patrick Williams71957992021-10-06 14:42:52 -0500166 catch (const fs::filesystem_error& e)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500167 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500168 lg2::error(
169 "Failed to create directory, ERR:{ERR}, DIRECTORY:{DIRECTORY}",
170 "ERR", e, "DIRECTORY", certParentInstallPath);
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500171 report<InternalFailure>();
172 }
173
174 // Generating RSA private key file if certificate type is server/client
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000175 if (certType != CertificateType::authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500176 {
177 createRSAPrivateKeyFile();
178 }
179
180 // restore any existing certificates
181 createCertificates();
182
183 // watch is not required for authority certificates
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000184 if (certType != CertificateType::authority)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500185 {
186 // watch for certificate file create/replace
Patrick Williams223e4602023-05-10 07:51:11 -0500187 certWatchPtr = std::make_unique<Watch>(event, certInstallPath,
188 [this]() {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500189 try
190 {
191 // if certificate file existing update it
192 if (!installedCerts.empty())
193 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500194 lg2::info("Inotify callback to update "
195 "certificate properties");
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500196 installedCerts[0]->populateProperties();
197 }
198 else
199 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500200 lg2::info(
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500201 "Inotify callback to create certificate object");
202 createCertificates();
203 }
204 }
205 catch (const InternalFailure& e)
206 {
207 commit<InternalFailure>();
208 }
209 catch (const InvalidCertificate& e)
210 {
211 commit<InvalidCertificate>();
212 }
213 });
Marri Devender Raob57d75e2019-07-25 04:56:21 -0500214 }
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100215 else
216 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500217 try
218 {
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500219 const std::string singleCertPath = "/etc/ssl/certs/Root-CA.pem";
220 if (fs::exists(singleCertPath) && !fs::is_empty(singleCertPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500221 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500222 lg2::notice(
223 "Legacy certificate detected, will be installed from,"
224 "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
225 "SINGLE_CERTPATH", singleCertPath);
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500226 install(singleCertPath);
227 if (!fs::remove(singleCertPath))
228 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500229 lg2::error("Unable to remove old certificate from,"
230 "SINGLE_CERTPATH:{SINGLE_CERTPATH}",
231 "SINGLE_CERTPATH", singleCertPath);
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500232 elog<InternalFailure>();
233 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500234 }
235 }
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500236 catch (const std::exception& ex)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500237 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500238 lg2::error(
239 "Error in restoring legacy certificate, ERROR_STR:{ERROR_STR}",
240 "ERROR_STR", ex);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200241 }
242 }
243 }
Patrick Williams71957992021-10-06 14:42:52 -0500244 catch (const std::exception& ex)
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500245 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500246 lg2::error(
247 "Error in certificate manager constructor, ERROR_STR:{ERROR_STR}",
248 "ERROR_STR", ex);
Marri Devender Raodb5c6fc2020-03-10 13:27:49 -0500249 }
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 Zhoue3d47cd2022-09-16 03:41:53 +0000254 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 Zhoue3d47cd2022-09-16 03:41:53 +0000258 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,
Willy Tu698a5742022-09-23 21:33:01 +0000270 certWatchPtr.get(), *this, /*restore=*/false));
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{
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000285 if (certType != CertificateType::authority)
Nan Zhou6ec13c82021-12-30 11:34:50 -0800286 {
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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500302 lg2::error("File is Missing, FILE:{FILE}", "FILE", filePath);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800303 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
Ravi Tejaf2646272023-09-30 13:00:55 -0500311 lg2::info("Starts authority list install");
Nan Zhou78357b02022-06-09 22:33:35 +0000312
Nan Zhou6ec13c82021-12-30 11:34:50 -0800313 fs::path authorityStore(certInstallPath);
Patrick Williams223e4602023-05-10 07:51:11 -0500314 fs::path authoritiesListFile = authorityStore /
315 defaultAuthoritiesListFileName;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800316
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 {
Patrick Williams223e4602023-05-10 07:51:11 -0500328 std::string certObjectPath = objectPath + '/' +
329 std::to_string(tempCertIdCounter);
Nan Zhou6ec13c82021-12-30 11:34:50 -0800330 tempCertificates.emplace_back(std::make_unique<Certificate>(
331 bus, certObjectPath, certType, tempPath, *x509Store, authority,
Willy Tu698a5742022-09-23 21:33:01 +0000332 certWatchPtr.get(), *this, /*restore=*/false));
Nan Zhou6ec13c82021-12-30 11:34:50 -0800333 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
Ravi Tejaf2646272023-09-30 13:00:55 -0500365 lg2::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
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000388 if (certType == CertificateType::authority)
Nan Zhou6ec13c82021-12-30 11:34:50 -0800389 {
Patrick Williams223e4602023-05-10 07:51:11 -0500390 if (fs::path authoritiesList = fs::path(certInstallPath) /
391 defaultAuthoritiesListFileName;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800392 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{
Patrick Williams223e4602023-05-10 07:51:11 -0500404 const std::vector<std::unique_ptr<Certificate>>::iterator& certIt =
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200405 std::find_if(installedCerts.begin(), installedCerts.end(),
Patrick Williams223e4602023-05-10 07:51:11 -0500406 [certificate](const std::unique_ptr<Certificate>& cert) {
407 return (cert.get() == certificate);
Patrick Williamsd96b81c2023-10-20 11:19:39 -0500408 });
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200409 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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500417 lg2::error("Certificate does not exist, ID:{ID}", "ID",
418 certificate->getCertId());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100419 elog<InternalFailure>();
420 }
421}
422
423void Manager::replaceCertificate(Certificate* const certificate,
424 const std::string& filePath)
425{
426 if (isCertificateUnique(filePath, certificate))
427 {
Willy Tu698a5742022-09-23 21:33:01 +0000428 certificate->install(filePath, false);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100429 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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500452 lg2::error("Error occurred during forking process");
Marri Devender Raof4682712019-03-19 05:00:28 -0500453 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;
Patrick Williamsd96b81c2023-10-20 11:19:39 -0500485 Child::Callback callback = [this](Child& eventSource,
486 const siginfo_t* si) {
Marri Devender Raof4682712019-03-19 05:00:28 -0500487 eventSource.set_enabled(Enabled::On);
488 if (si->si_status != 0)
489 {
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000490 this->createCSRObject(Status::failure);
Marri Devender Raof4682712019-03-19 05:00:28 -0500491 }
492 else
493 {
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000494 this->createCSRObject(Status::success);
Marri Devender Raof4682712019-03-19 05:00:28 -0500495 }
496 };
497 try
498 {
499 sigset_t ss;
500 if (sigemptyset(&ss) < 0)
501 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500502 lg2::error("Unable to initialize signal set");
Marri Devender Raof4682712019-03-19 05:00:28 -0500503 elog<InternalFailure>();
504 }
505 if (sigaddset(&ss, SIGCHLD) < 0)
506 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500507 lg2::error("Unable to add signal to signal set");
Marri Devender Raof4682712019-03-19 05:00:28 -0500508 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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500514 lg2::error("Unable to block signal");
Marri Devender Raof4682712019-03-19 05:00:28 -0500515 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;
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800551 X509ReqPtr x509Req(X509_REQ_new(), ::X509_REQ_free);
Marri Devender Raof4682712019-03-19 05:00:28 -0500552 ret = X509_REQ_set_version(x509Req.get(), nVersion);
553 if (ret == 0)
554 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500555 lg2::error("Error occurred during X509_REQ_set_version call");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600556 ERR_print_errors_fp(stderr);
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
Ravi Tejaf2646272023-09-30 13:00:55 -0500601 lg2::info("Given Key pair algorithm, KEYPAIRALGORITHM:{KEYPAIRALGORITHM}",
602 "KEYPAIRALGORITHM", keyPairAlgorithm);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500603
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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500611 lg2::error("Given Key pair algorithm is not supported. Supporting "
612 "RSA and EC only");
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500613 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 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500621 lg2::error("Error occurred while setting Public key");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600622 ERR_print_errors_fp(stderr);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500623 elog<InternalFailure>();
624 }
625
626 // Write private key to file
Nan Zhou718eef32021-12-28 11:03:30 -0800627 writePrivateKey(pKey, defaultPrivateKeyFileName);
Marri Devender Raof4682712019-03-19 05:00:28 -0500628
629 // set sign key of x509 req
630 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500631 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500632 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500633 lg2::error("Error occurred while signing key of x509");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600634 ERR_print_errors_fp(stderr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500635 elog<InternalFailure>();
636 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500637
Ravi Tejaf2646272023-09-30 13:00:55 -0500638 lg2::info("Writing CSR to file");
Nan Zhou718eef32021-12-28 11:03:30 -0800639 fs::path csrFilePath = certParentInstallPath / defaultCSRFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500640 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500641}
642
Marri Devender Rao76411052019-08-07 01:25:07 -0500643bool Manager::isExtendedKeyUsage(const std::string& usage)
644{
645 const static std::array<const char*, 6> usageList = {
646 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
647 "Timestamping", "CodeSigning", "EmailProtection"};
Patrick Williamsd96b81c2023-10-20 11:19:39 -0500648 auto it = std::find_if(
649 usageList.begin(), usageList.end(),
650 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
Marri Devender Rao76411052019-08-07 01:25:07 -0500651 return it != usageList.end();
652}
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800653EVPPkeyPtr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500654{
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500655 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500656 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500657 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500658 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500659 lg2::info("KeyBitLength is not given.Hence, using default KeyBitLength:"
660 "{DEFAULTKEYBITLENGTH}",
661 "DEFAULTKEYBITLENGTH", defaultKeyBitLength);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800662 keyBitLen = defaultKeyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500663 }
Patrick Williams26fb83e2021-12-14 14:08:28 -0600664
665#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
666
667 // generate rsa key
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800668 BignumPtr bne(BN_new(), ::BN_free);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600669 auto ret = BN_set_word(bne.get(), RSA_F4);
670 if (ret == 0)
671 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500672 lg2::error("Error occurred during BN_set_word call");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600673 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600674 elog<InternalFailure>();
675 }
Nan Zhou762da742022-01-14 17:21:44 -0800676 using RSAPtr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
677 RSAPtr rsa(RSA_new(), ::RSA_free);
678 ret = RSA_generate_key_ex(rsa.get(), keyBitLen, bne.get(), nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500679 if (ret != 1)
680 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500681 lg2::error(
682 "Error occurred during RSA_generate_key_ex call: {KEYBITLENGTH}",
683 "KEYBITLENGTH", keyBitLen);
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600684 ERR_print_errors_fp(stderr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500685 elog<InternalFailure>();
686 }
687
688 // set public key of x509 req
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800689 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Nan Zhou762da742022-01-14 17:21:44 -0800690 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa.get());
Marri Devender Raof4682712019-03-19 05:00:28 -0500691 if (ret == 0)
692 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500693 lg2::error("Error occurred during assign rsa key into EVP");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600694 ERR_print_errors_fp(stderr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500695 elog<InternalFailure>();
696 }
Nan Zhou762da742022-01-14 17:21:44 -0800697 // Now |rsa| is managed by |pKey|
698 rsa.release();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500699 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600700
701#else
702 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
703 EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr), &::EVP_PKEY_CTX_free);
704 if (!ctx)
705 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500706 lg2::error("Error occurred creating EVP_PKEY_CTX from algorithm");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600707 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600708 elog<InternalFailure>();
709 }
710
711 if ((EVP_PKEY_keygen_init(ctx.get()) <= 0) ||
712 (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), keyBitLen) <= 0))
713
714 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500715 lg2::error("Error occurred initializing keygen context");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600716 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600717 elog<InternalFailure>();
718 }
719
720 EVP_PKEY* pKey = nullptr;
721 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
722 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500723 lg2::error("Error occurred during generate EC key");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600724 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600725 elog<InternalFailure>();
726 }
727
728 return {pKey, &::EVP_PKEY_free};
729#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500730}
731
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800732EVPPkeyPtr Manager::generateECKeyPair(const std::string& curveId)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500733{
734 std::string curId(curveId);
735
736 if (curId.empty())
737 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500738 lg2::info("KeyCurveId is not given. Hence using default curve id,"
739 "DEFAULTKEYCURVEID:{DEFAULTKEYCURVEID}",
740 "DEFAULTKEYCURVEID", defaultKeyCurveID);
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800741 curId = defaultKeyCurveID;
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500742 }
743
744 int ecGrp = OBJ_txt2nid(curId.c_str());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500745 if (ecGrp == NID_undef)
746 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500747 lg2::error(
748 "Error occurred during convert the curve id string format into NID,"
749 "KEYCURVEID:{KEYCURVEID}",
750 "KEYCURVEID", curId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500751 elog<InternalFailure>();
752 }
753
Patrick Williams26fb83e2021-12-14 14:08:28 -0600754#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
755
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500756 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
757
Nan Zhoucfb58022021-12-28 11:02:26 -0800758 if (ecKey == nullptr)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500759 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500760 lg2::error(
761 "Error occurred during create the EC_Key object from NID, ECGROUP:{ECGROUP}",
762 "ECGROUP", ecGrp);
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600763 ERR_print_errors_fp(stderr);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500764 elog<InternalFailure>();
765 }
766
767 // If you want to save a key and later load it with
768 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
769 // flag on the key.
770 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
771
772 int ret = EC_KEY_generate_key(ecKey);
773
774 if (ret == 0)
775 {
776 EC_KEY_free(ecKey);
Ravi Tejaf2646272023-09-30 13:00:55 -0500777 lg2::error("Error occurred during generate EC key");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600778 ERR_print_errors_fp(stderr);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500779 elog<InternalFailure>();
780 }
781
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800782 EVPPkeyPtr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500783 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
784 if (ret == 0)
785 {
786 EC_KEY_free(ecKey);
Ravi Tejaf2646272023-09-30 13:00:55 -0500787 lg2::error("Error occurred during assign EC Key into EVP");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600788 ERR_print_errors_fp(stderr);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500789 elog<InternalFailure>();
790 }
791
792 return pKey;
Patrick Williams26fb83e2021-12-14 14:08:28 -0600793
794#else
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000795 auto holderOfKey = [](EVP_PKEY* key) {
Patrick Williams26fb83e2021-12-14 14:08:28 -0600796 return std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>{
797 key, &::EVP_PKEY_free};
798 };
799
800 // Create context to set up curve parameters.
801 auto ctx = std::unique_ptr<EVP_PKEY_CTX, decltype(&::EVP_PKEY_CTX_free)>(
802 EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr), &::EVP_PKEY_CTX_free);
803 if (!ctx)
804 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500805 lg2::error("Error occurred creating EVP_PKEY_CTX for params");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600806 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600807 elog<InternalFailure>();
808 }
809
810 // Set up curve parameters.
811 EVP_PKEY* params = nullptr;
812
813 if ((EVP_PKEY_paramgen_init(ctx.get()) <= 0) ||
814 (EVP_PKEY_CTX_set_ec_param_enc(ctx.get(), OPENSSL_EC_NAMED_CURVE) <=
815 0) ||
816 (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(), ecGrp) <= 0) ||
817 (EVP_PKEY_paramgen(ctx.get(), &params) <= 0))
818 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500819 lg2::error("Error occurred setting curve parameters");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600820 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600821 elog<InternalFailure>();
822 }
823
824 // Move parameters to RAII holder.
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000825 auto pparms = holderOfKey(params);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600826
827 // Create new context for key.
828 ctx.reset(EVP_PKEY_CTX_new_from_pkey(nullptr, params, nullptr));
829
830 if (!ctx || (EVP_PKEY_keygen_init(ctx.get()) <= 0))
831 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500832 lg2::error("Error occurred initializing keygen context");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600833 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600834 elog<InternalFailure>();
835 }
836
837 EVP_PKEY* pKey = nullptr;
838 if (EVP_PKEY_keygen(ctx.get(), &pKey) <= 0)
839 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500840 lg2::error("Error occurred during generate EC key");
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600841 ERR_print_errors_fp(stderr);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600842 elog<InternalFailure>();
843 }
844
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000845 return holderOfKey(pKey);
Patrick Williams26fb83e2021-12-14 14:08:28 -0600846#endif
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500847}
848
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800849void Manager::writePrivateKey(const EVPPkeyPtr& pKey,
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500850 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500851{
Ravi Tejaf2646272023-09-30 13:00:55 -0500852 lg2::info("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500853 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500854 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500855
856 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
Nan Zhoucfb58022021-12-28 11:02:26 -0800857 if (fp == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500858 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500859 lg2::error("Error occurred creating private key file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500860 elog<InternalFailure>();
861 }
Patrick Williams223e4602023-05-10 07:51:11 -0500862 int ret = PEM_write_PrivateKey(fp, pKey.get(), nullptr, nullptr, 0, 0,
863 nullptr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500864 std::fclose(fp);
865 if (ret == 0)
866 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500867 lg2::error("Error occurred while writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500868 elog<InternalFailure>();
869 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500870}
871
872void Manager::addEntry(X509_NAME* x509Name, const char* field,
873 const std::string& bytes)
874{
875 if (bytes.empty())
876 {
877 return;
878 }
879 int ret = X509_NAME_add_entry_by_txt(
880 x509Name, field, MBSTRING_ASC,
881 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
882 if (ret != 1)
883 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500884 lg2::error("Unable to set entry, FIELD:{FIELD}, VALUE:{VALUE}", "FIELD",
885 field, "VALUE", bytes);
Andrew Geissler8dbcc722023-12-08 10:15:42 -0600886 ERR_print_errors_fp(stderr);
Marri Devender Raof4682712019-03-19 05:00:28 -0500887 elog<InternalFailure>();
888 }
889}
890
891void Manager::createCSRObject(const Status& status)
892{
893 if (csrPtr)
894 {
895 csrPtr.reset(nullptr);
896 }
897 auto csrObjectPath = objectPath + '/' + "csr";
898 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
899 certInstallPath.c_str(), status);
900}
901
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800902void Manager::writeCSR(const std::string& filePath, const X509ReqPtr& x509Req)
Marri Devender Raof4682712019-03-19 05:00:28 -0500903{
904 if (fs::exists(filePath))
905 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500906 lg2::info("Removing the existing file, FILENAME:{FILENAME}", "FILENAME",
907 filePath);
Marri Devender Raof4682712019-03-19 05:00:28 -0500908 if (!fs::remove(filePath.c_str()))
909 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500910 lg2::error("Unable to remove the file, FILENAME:{FILENAME}",
911 "FILENAME", filePath);
Marri Devender Raof4682712019-03-19 05:00:28 -0500912 elog<InternalFailure>();
913 }
914 }
915
Nan Zhoucfb58022021-12-28 11:02:26 -0800916 FILE* fp = nullptr;
Marri Devender Raof4682712019-03-19 05:00:28 -0500917
Nan Zhoucfb58022021-12-28 11:02:26 -0800918 if ((fp = std::fopen(filePath.c_str(), "w")) == nullptr)
Marri Devender Raof4682712019-03-19 05:00:28 -0500919 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500920 lg2::error(
921 "Error opening the file to write the CSR, FILENAME:{FILENAME}",
922 "FILENAME", filePath);
Marri Devender Raof4682712019-03-19 05:00:28 -0500923 elog<InternalFailure>();
924 }
925
926 int rc = PEM_write_X509_REQ(fp, x509Req.get());
927 if (!rc)
928 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500929 lg2::error("PEM write routine failed, FILENAME:{FILENAME}", "FILENAME",
930 filePath);
Marri Devender Raof4682712019-03-19 05:00:28 -0500931 std::fclose(fp);
932 elog<InternalFailure>();
933 }
934 std::fclose(fp);
935}
936
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200937void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500938{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200939 auto certObjectPath = objectPath + '/';
940
Nan Zhoue3d47cd2022-09-16 03:41:53 +0000941 if (certType == CertificateType::authority)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500942 {
Zbigniew Lukwinskife590c42019-12-10 12:33:50 +0100943 // Check whether install path is a directory.
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200944 if (!fs::is_directory(certInstallPath))
945 {
Ravi Tejaf2646272023-09-30 13:00:55 -0500946 lg2::error("Certificate installation path exists and it is "
947 "not a directory");
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200948 elog<InternalFailure>();
Nan Zhou6ec13c82021-12-30 11:34:50 -0800949 }
950
951 // If the authorities list exists, recover from it and return
Patrick Williams223e4602023-05-10 07:51:11 -0500952 if (fs::path authoritiesListFilePath = fs::path(certInstallPath) /
953 defaultAuthoritiesListFileName;
Nan Zhou6ec13c82021-12-30 11:34:50 -0800954 fs::exists(authoritiesListFilePath))
955 {
956 // remove all other files and directories
957 for (auto& path : fs::directory_iterator(certInstallPath))
958 {
959 if (path.path() != authoritiesListFilePath)
960 {
961 fs::remove_all(path);
962 }
963 }
964 installAll(authoritiesListFilePath);
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200965 return;
966 }
967
968 for (auto& path : fs::directory_iterator(certInstallPath))
969 {
970 try
971 {
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100972 // Assume here any regular file located in certificate directory
973 // contains certificates body. Do not want to use soft links
974 // would add value.
975 if (fs::is_regular_file(path))
976 {
977 installedCerts.emplace_back(std::make_unique<Certificate>(
978 bus, certObjectPath + std::to_string(certIdCounter++),
Nan Zhoucf06ccd2021-12-28 16:25:45 -0800979 certType, certInstallPath, path.path(),
Willy Tu698a5742022-09-23 21:33:01 +0000980 certWatchPtr.get(), *this, /*restore=*/true));
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100981 }
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 }
992 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500993 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200994 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500995 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200996 try
997 {
998 installedCerts.emplace_back(std::make_unique<Certificate>(
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +0100999 bus, certObjectPath + '1', certType, certInstallPath,
Willy Tu698a5742022-09-23 21:33:01 +00001000 certInstallPath, certWatchPtr.get(), *this, /*restore=*/false));
Kowalski, Kamildb029c92019-07-08 17:09:39 +02001001 }
1002 catch (const InternalFailure& e)
1003 {
1004 report<InternalFailure>();
1005 }
1006 catch (const InvalidCertificate& e)
1007 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001008 report<InvalidCertificate>(InvalidCertificateReason(
1009 "Existing certificate file is corrupted"));
Kowalski, Kamildb029c92019-07-08 17:09:39 +02001010 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -05001011 }
1012}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001013
1014void Manager::createRSAPrivateKeyFile()
1015{
Patrick Williams223e4602023-05-10 07:51:11 -05001016 fs::path rsaPrivateKeyFileName = certParentInstallPath /
1017 defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001018
1019 try
1020 {
1021 if (!fs::exists(rsaPrivateKeyFileName))
1022 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001023 writePrivateKey(generateRSAKeyPair(supportedKeyBitLength),
Nan Zhou718eef32021-12-28 11:03:30 -08001024 defaultRSAPrivateKeyFileName);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001025 }
1026 }
1027 catch (const InternalFailure& e)
1028 {
1029 report<InternalFailure>();
1030 }
1031}
1032
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001033EVPPkeyPtr Manager::getRSAKeyPair(const int64_t keyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001034{
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001035 if (keyBitLength != supportedKeyBitLength)
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001036 {
Ravi Tejaf2646272023-09-30 13:00:55 -05001037 lg2::error(
1038 "Given Key bit length is not supported, GIVENKEYBITLENGTH:"
1039 "{GIVENKEYBITLENGTH}, SUPPORTEDKEYBITLENGTH:{SUPPORTEDKEYBITLENGTH}",
1040 "GIVENKEYBITLENGTH", keyBitLength, "SUPPORTEDKEYBITLENGTH",
1041 supportedKeyBitLength);
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001042 elog<InvalidArgument>(
1043 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
1044 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
1045 }
Patrick Williams223e4602023-05-10 07:51:11 -05001046 fs::path rsaPrivateKeyFileName = certParentInstallPath /
1047 defaultRSAPrivateKeyFileName;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001048
1049 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
1050 if (!privateKeyFile)
1051 {
Ravi Tejaf2646272023-09-30 13:00:55 -05001052 lg2::error(
1053 "Unable to open RSA private key file to read, RSAKEYFILE:{RSAKEYFILE},"
1054 "ERRORREASON:{ERRORREASON}",
1055 "RSAKEYFILE", rsaPrivateKeyFileName, "ERRORREASON",
1056 strerror(errno));
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001057 elog<InternalFailure>();
1058 }
1059
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001060 EVPPkeyPtr privateKey(
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001061 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
1062 ::EVP_PKEY_free);
1063 std::fclose(privateKeyFile);
1064
1065 if (!privateKey)
1066 {
Ravi Tejaf2646272023-09-30 13:00:55 -05001067 lg2::error("Error occurred during PEM_read_PrivateKey call");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -05001068 elog<InternalFailure>();
1069 }
1070 return privateKey;
1071}
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001072
1073void Manager::storageUpdate()
1074{
Nan Zhoue3d47cd2022-09-16 03:41:53 +00001075 if (certType == CertificateType::authority)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001076 {
1077 // Remove symbolic links in the certificate directory
1078 for (auto& certPath : fs::directory_iterator(certInstallPath))
1079 {
1080 try
1081 {
1082 if (fs::is_symlink(certPath))
1083 {
1084 fs::remove(certPath);
1085 }
1086 }
1087 catch (const std::exception& e)
1088 {
Ravi Tejaf2646272023-09-30 13:00:55 -05001089 lg2::error(
1090 "Failed to remove symlink for certificate, ERR:{ERR} SYMLINK:{SYMLINK}",
1091 "ERR", e, "SYMLINK", certPath.path().string());
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001092 elog<InternalFailure>();
1093 }
1094 }
1095 }
1096
1097 for (const auto& cert : installedCerts)
1098 {
1099 cert->storageUpdate();
1100 }
1101}
1102
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001103void Manager::reloadOrReset(const std::string& unit)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001104{
1105 if (!unit.empty())
1106 {
1107 try
1108 {
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001109 constexpr auto defaultSystemdService = "org.freedesktop.systemd1";
1110 constexpr auto defaultSystemdObjectPath =
1111 "/org/freedesktop/systemd1";
1112 constexpr auto defaultSystemdInterface =
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001113 "org.freedesktop.systemd1.Manager";
Nan Zhoucf06ccd2021-12-28 16:25:45 -08001114 auto method = bus.new_method_call(
1115 defaultSystemdService, defaultSystemdObjectPath,
1116 defaultSystemdInterface, "ReloadOrRestartUnit");
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001117 method.append(unit, "replace");
1118 bus.call_noreply(method);
1119 }
Patrick Williamsb3dbfb32022-07-22 19:26:57 -05001120 catch (const sdbusplus::exception_t& e)
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001121 {
Ravi Tejaf2646272023-09-30 13:00:55 -05001122 lg2::error(
1123 "Failed to reload or restart service, ERR:{ERR}, UNIT:{UNIT}",
1124 "ERR", e, "UNIT", unit);
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001125 elog<InternalFailure>();
1126 }
1127 }
1128}
1129
1130bool Manager::isCertificateUnique(const std::string& filePath,
1131 const Certificate* const certToDrop)
1132{
1133 if (std::any_of(
1134 installedCerts.begin(), installedCerts.end(),
Patrick Williams223e4602023-05-10 07:51:11 -05001135 [&filePath, certToDrop](const std::unique_ptr<Certificate>& cert) {
1136 return cert.get() != certToDrop && cert->isSame(filePath);
Patrick Williamsd96b81c2023-10-20 11:19:39 -05001137 }))
Zbigniew Lukwinski2f3563c2020-01-08 12:35:23 +01001138 {
1139 return false;
1140 }
1141 else
1142 {
1143 return true;
1144 }
1145}
1146
Nan Zhoue1289ad2021-12-28 11:02:56 -08001147} // namespace phosphor::certs