blob: 6469f2af43d06a2891d0236e79e8435b85516300 [file] [log] [blame]
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05001#include "certs_manager.hpp"
2
Marri Devender Raof4682712019-03-19 05:00:28 -05003#include <openssl/pem.h>
4#include <unistd.h>
5
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +02006#include <algorithm>
Marri Devender Rao6ceec402019-02-01 03:15:19 -06007#include <phosphor-logging/elog-errors.hpp>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -05008#include <xyz/openbmc_project/Certs/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05009#include <xyz/openbmc_project/Common/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050010namespace phosphor
11{
12namespace certs
13{
Marri Devender Rao13965112019-02-27 08:47:12 -060014using InternalFailure =
15 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050016using InvalidCertificate =
17 sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
18using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050019
Marri Devender Raof4682712019-03-19 05:00:28 -050020using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
21using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050022using InvalidArgument =
23 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
24using Argument = xyz::openbmc_project::Common::InvalidArgument;
25
26constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
Marri Devender Raof4682712019-03-19 05:00:28 -050027
28Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
29 const char* path, const CertificateType& type,
30 UnitsToRestart&& unit, CertInstallPath&& installPath) :
Marri Devender Rao6ceec402019-02-01 03:15:19 -060031 Ifaces(bus, path),
Marri Devender Raof4682712019-03-19 05:00:28 -050032 bus(bus), event(event), objectPath(path), certType(type),
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050033 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
34 certParentInstallPath(fs::path(certInstallPath).parent_path())
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050035{
Marri Devender Raob57d75e2019-07-25 04:56:21 -050036 // create parent certificate path if not existing
37 try
38 {
39 if (!fs::exists(certParentInstallPath))
40 {
41 fs::create_directories(certParentInstallPath);
42 }
Marri Devender Rao667286e2019-10-29 03:22:46 -050043 auto permission = fs::perms::owner_read | fs::perms::owner_write |
44 fs::perms::owner_exec;
45 fs::permissions(certParentInstallPath, permission,
46 fs::perm_options::replace);
Marri Devender Raob57d75e2019-07-25 04:56:21 -050047 }
48 catch (fs::filesystem_error& e)
49 {
50 log<level::ERR>("Failed to create directory", entry("ERR=%s", e.what()),
51 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
52 report<InternalFailure>();
53 }
54
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050055 // Generating RSA private key file if certificate type is server/client
56 if (certType != AUTHORITY)
57 {
58 createRSAPrivateKeyFile();
59 }
60
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050061 // restore any existing certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +020062 createCertificates();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050063
64 // watch is not required for authority certificates
65 if (certType != AUTHORITY)
66 {
67 // watch for certificate file create/replace
68 certWatchPtr = std::make_unique<
69 Watch>(event, certInstallPath, [this]() {
70 try
71 {
72 // if certificate file existing update it
Kowalski, Kamildb029c92019-07-08 17:09:39 +020073 if (!installedCerts.empty())
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050074 {
75 log<level::INFO>(
76 "Inotify callback to update certificate properties");
Kowalski, Kamildb029c92019-07-08 17:09:39 +020077 installedCerts[0]->populateProperties();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050078 }
79 else
80 {
81 log<level::INFO>(
82 "Inotify callback to create certificate object");
Kowalski, Kamildb029c92019-07-08 17:09:39 +020083 createCertificates();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050084 }
85 }
86 catch (const InternalFailure& e)
87 {
88 commit<InternalFailure>();
89 }
90 catch (const InvalidCertificate& e)
91 {
92 commit<InvalidCertificate>();
93 }
94 });
Marri Devender Raobf7c5882019-02-27 08:41:07 -060095 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +020096 else
97 {
98 const std::string signleCertPath = "/etc/ssl/certs/Root-CA.pem";
99 if (fs::exists(signleCertPath) && !fs::is_empty(signleCertPath))
100 {
101 log<level::NOTICE>(
102 "Legacy certificate detected, will be installed from: ",
103 entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
104 install(signleCertPath);
105 if (!fs::remove(signleCertPath))
106 {
107 log<level::ERR>(
108 "Unable to remove old certificate from: ",
109 entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
110 elog<InternalFailure>();
111 }
112 }
113 }
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500114}
115
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200116std::string Manager::install(const std::string filePath)
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500117{
Marri Devender Rao13965112019-02-27 08:47:12 -0600118 using NotAllowed =
119 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
120 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200121
122 if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
Marri Devender Rao13965112019-02-27 08:47:12 -0600123 {
124 elog<NotAllowed>(Reason("Certificate already exist"));
125 }
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200126 else if (certType == phosphor::certs::AUTHORITY &&
127 installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
128 {
129 elog<NotAllowed>(Reason("Certificates limit reached"));
130 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500131
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200132 auto certObjectPath = objectPath + '/' + std::to_string(certIdCounter++);
133
134 installedCerts.emplace_back(std::make_unique<Certificate>(
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500135 bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200136 false, certWatchPtr, *this));
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200137 return certObjectPath;
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500138}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500139
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200140void Manager::deleteAll()
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500141{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600142 // TODO: #Issue 4 when a certificate is deleted system auto generates
143 // certificate file. At present we are not supporting creation of
144 // certificate object for the auto-generated certificate file as
145 // deletion if only applicable for REST server and Bmcweb does not allow
146 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200147 installedCerts.clear();
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500148}
Marri Devender Raof4682712019-03-19 05:00:28 -0500149
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200150void Manager::deleteCertificate(const std::string& certHash)
151{
152 std::vector<std::unique_ptr<Certificate>>::iterator const& certIt =
153 std::find_if(installedCerts.begin(), installedCerts.end(),
154 [certHash](std::unique_ptr<Certificate> const& cert) {
155 return cert->getHash().compare(certHash) == 0;
156 });
157 if (certIt != installedCerts.end())
158 {
159 installedCerts.erase(certIt);
160 }
161 else
162 {
163 log<level::ERR>("Certificate does not exist",
164 entry("HASH=%s", certHash.c_str()));
165 elog<InternalFailure>();
166 }
167}
168
Marri Devender Raof4682712019-03-19 05:00:28 -0500169std::string Manager::generateCSR(
170 std::vector<std::string> alternativeNames, std::string challengePassword,
171 std::string city, std::string commonName, std::string contactPerson,
172 std::string country, std::string email, std::string givenName,
173 std::string initials, int64_t keyBitLength, std::string keyCurveId,
174 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
175 std::string organization, std::string organizationalUnit, std::string state,
176 std::string surname, std::string unstructuredName)
177{
178 // We support only one CSR.
179 csrPtr.reset(nullptr);
180 auto pid = fork();
181 if (pid == -1)
182 {
183 log<level::ERR>("Error occurred during forking process");
184 report<InternalFailure>();
185 }
186 else if (pid == 0)
187 {
188 try
189 {
190 generateCSRHelper(alternativeNames, challengePassword, city,
191 commonName, contactPerson, country, email,
192 givenName, initials, keyBitLength, keyCurveId,
193 keyPairAlgorithm, keyUsage, organization,
194 organizationalUnit, state, surname,
195 unstructuredName);
196 exit(EXIT_SUCCESS);
197 }
198 catch (const InternalFailure& e)
199 {
200 // commit the error reported in child process and exit
201 // Callback method from SDEvent Loop looks for exit status
202 exit(EXIT_FAILURE);
203 commit<InternalFailure>();
204 }
205 }
206 else
207 {
208 using namespace sdeventplus::source;
209 Child::Callback callback = [this](Child& eventSource,
210 const siginfo_t* si) {
211 eventSource.set_enabled(Enabled::On);
212 if (si->si_status != 0)
213 {
214 this->createCSRObject(Status::FAILURE);
215 }
216 else
217 {
218 this->createCSRObject(Status::SUCCESS);
219 }
220 };
221 try
222 {
223 sigset_t ss;
224 if (sigemptyset(&ss) < 0)
225 {
226 log<level::ERR>("Unable to initialize signal set");
227 elog<InternalFailure>();
228 }
229 if (sigaddset(&ss, SIGCHLD) < 0)
230 {
231 log<level::ERR>("Unable to add signal to signal set");
232 elog<InternalFailure>();
233 }
234
235 // Block SIGCHLD first, so that the event loop can handle it
236 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
237 {
238 log<level::ERR>("Unable to block signal");
239 elog<InternalFailure>();
240 }
241 if (childPtr)
242 {
243 childPtr.reset();
244 }
245 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
246 std::move(callback));
247 }
248 catch (const InternalFailure& e)
249 {
250 commit<InternalFailure>();
251 }
252 }
253 auto csrObjectPath = objectPath + '/' + "csr";
254 return csrObjectPath;
255}
256
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200257std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500258{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200259 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500260}
261
Marri Devender Raof4682712019-03-19 05:00:28 -0500262void Manager::generateCSRHelper(
263 std::vector<std::string> alternativeNames, std::string challengePassword,
264 std::string city, std::string commonName, std::string contactPerson,
265 std::string country, std::string email, std::string givenName,
266 std::string initials, int64_t keyBitLength, std::string keyCurveId,
267 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
268 std::string organization, std::string organizationalUnit, std::string state,
269 std::string surname, std::string unstructuredName)
270{
271 int ret = 0;
272
273 // set version of x509 req
274 int nVersion = 1;
275 // TODO: Issue#6 need to make version number configurable
276 X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
277 ret = X509_REQ_set_version(x509Req.get(), nVersion);
278 if (ret == 0)
279 {
280 log<level::ERR>("Error occured during X509_REQ_set_version call");
281 elog<InternalFailure>();
282 }
283
284 // set subject of x509 req
285 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
286
287 if (!alternativeNames.empty())
288 {
289 for (auto& name : alternativeNames)
290 {
291 addEntry(x509Name, "subjectAltName", name);
292 }
293 }
294 addEntry(x509Name, "challengePassword", challengePassword);
295 addEntry(x509Name, "L", city);
296 addEntry(x509Name, "CN", commonName);
297 addEntry(x509Name, "name", contactPerson);
298 addEntry(x509Name, "C", country);
299 addEntry(x509Name, "emailAddress", email);
300 addEntry(x509Name, "GN", givenName);
301 addEntry(x509Name, "initials", initials);
302 addEntry(x509Name, "algorithm", keyPairAlgorithm);
303 if (!keyUsage.empty())
304 {
305 for (auto& usage : keyUsage)
306 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500307 if (isExtendedKeyUsage(usage))
308 {
309 addEntry(x509Name, "extendedKeyUsage", usage);
310 }
311 else
312 {
313 addEntry(x509Name, "keyUsage", usage);
314 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500315 }
316 }
317 addEntry(x509Name, "O", organization);
318 addEntry(x509Name, "ST", state);
319 addEntry(x509Name, "SN", surname);
320 addEntry(x509Name, "unstructuredName", unstructuredName);
321
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500322 EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
323
324 log<level::INFO>("Given Key pair algorithm",
325 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
326
327 // Used EC algorithm as default if user did not give algorithm type.
328 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500329 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500330 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500331 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500332 else
333 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500334 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
335 "RSA and EC only");
336 elog<InvalidArgument>(
337 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
338 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
339 }
340
341 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
342 if (ret == 0)
343 {
344 log<level::ERR>("Error occured while setting Public key");
345 elog<InternalFailure>();
346 }
347
348 // Write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500349 writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
Marri Devender Raof4682712019-03-19 05:00:28 -0500350
351 // set sign key of x509 req
352 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500353 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500354 {
355 log<level::ERR>("Error occured while signing key of x509");
356 elog<InternalFailure>();
357 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500358
Marri Devender Raof4682712019-03-19 05:00:28 -0500359 log<level::INFO>("Writing CSR to file");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500360 fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
361 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500362}
363
Marri Devender Rao76411052019-08-07 01:25:07 -0500364bool Manager::isExtendedKeyUsage(const std::string& usage)
365{
366 const static std::array<const char*, 6> usageList = {
367 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
368 "Timestamping", "CodeSigning", "EmailProtection"};
369 auto it = std::find_if(
370 usageList.begin(), usageList.end(),
371 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
372 return it != usageList.end();
373}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500374EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500375{
376 int ret = 0;
377 // generate rsa key
378 BIGNUM_Ptr bne(BN_new(), ::BN_free);
379 ret = BN_set_word(bne.get(), RSA_F4);
380 if (ret == 0)
381 {
382 log<level::ERR>("Error occured during BN_set_word call");
383 elog<InternalFailure>();
384 }
385
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500386 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500387 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500388 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500389 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500390 constexpr auto DEFAULT_KEYBITLENGTH = 2048;
391 log<level::INFO>(
392 "KeyBitLength is not given.Hence, using default KeyBitLength",
393 entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
394 keyBitLen = DEFAULT_KEYBITLENGTH;
Marri Devender Raof4682712019-03-19 05:00:28 -0500395 }
396 RSA* rsa = RSA_new();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500397 ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500398 if (ret != 1)
399 {
400 free(rsa);
401 log<level::ERR>("Error occured during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500402 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500403 elog<InternalFailure>();
404 }
405
406 // set public key of x509 req
407 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500408 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
Marri Devender Raof4682712019-03-19 05:00:28 -0500409 if (ret == 0)
410 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500411 free(rsa);
412 log<level::ERR>("Error occured during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500413 elog<InternalFailure>();
414 }
415
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500416 return pKey;
417}
418
419EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
420{
421 std::string curId(curveId);
422
423 if (curId.empty())
424 {
425 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
426 constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
427 log<level::INFO>(
428 "KeyCurveId is not given. Hence using default curve id",
429 entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
430 curId = DEFAULT_KEYCURVEID;
431 }
432
433 int ecGrp = OBJ_txt2nid(curId.c_str());
434
435 if (ecGrp == NID_undef)
436 {
437 log<level::ERR>(
438 "Error occured during convert the curve id string format into NID",
439 entry("KEYCURVEID=%s", curId.c_str()));
440 elog<InternalFailure>();
441 }
442
443 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
444
445 if (ecKey == NULL)
446 {
447 log<level::ERR>(
448 "Error occured during create the EC_Key object from NID",
449 entry("ECGROUP=%d", ecGrp));
450 elog<InternalFailure>();
451 }
452
453 // If you want to save a key and later load it with
454 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
455 // flag on the key.
456 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
457
458 int ret = EC_KEY_generate_key(ecKey);
459
460 if (ret == 0)
461 {
462 EC_KEY_free(ecKey);
463 log<level::ERR>("Error occured during generate EC key");
464 elog<InternalFailure>();
465 }
466
467 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
468 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
469 if (ret == 0)
470 {
471 EC_KEY_free(ecKey);
472 log<level::ERR>("Error occured during assign EC Key into EVP");
473 elog<InternalFailure>();
474 }
475
476 return pKey;
477}
478
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500479void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
480 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500481{
482 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500483 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500484 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500485
486 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
487 if (fp == NULL)
488 {
Marri Devender Raof4682712019-03-19 05:00:28 -0500489 log<level::ERR>("Error occured creating private key file");
490 elog<InternalFailure>();
491 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500492 int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500493 std::fclose(fp);
494 if (ret == 0)
495 {
496 log<level::ERR>("Error occured while writing private key to file");
497 elog<InternalFailure>();
498 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500499}
500
501void Manager::addEntry(X509_NAME* x509Name, const char* field,
502 const std::string& bytes)
503{
504 if (bytes.empty())
505 {
506 return;
507 }
508 int ret = X509_NAME_add_entry_by_txt(
509 x509Name, field, MBSTRING_ASC,
510 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
511 if (ret != 1)
512 {
513 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
514 entry("VALUE=%s", bytes.c_str()));
515 elog<InternalFailure>();
516 }
517}
518
519void Manager::createCSRObject(const Status& status)
520{
521 if (csrPtr)
522 {
523 csrPtr.reset(nullptr);
524 }
525 auto csrObjectPath = objectPath + '/' + "csr";
526 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
527 certInstallPath.c_str(), status);
528}
529
530void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
531{
532 if (fs::exists(filePath))
533 {
534 log<level::INFO>("Removing the existing file",
535 entry("FILENAME=%s", filePath.c_str()));
536 if (!fs::remove(filePath.c_str()))
537 {
538 log<level::ERR>("Unable to remove the file",
539 entry("FILENAME=%s", filePath.c_str()));
540 elog<InternalFailure>();
541 }
542 }
543
544 FILE* fp = NULL;
545
546 if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
547 {
548 log<level::ERR>("Error opening the file to write the CSR",
549 entry("FILENAME=%s", filePath.c_str()));
550 elog<InternalFailure>();
551 }
552
553 int rc = PEM_write_X509_REQ(fp, x509Req.get());
554 if (!rc)
555 {
556 log<level::ERR>("PEM write routine failed",
557 entry("FILENAME=%s", filePath.c_str()));
558 std::fclose(fp);
559 elog<InternalFailure>();
560 }
561 std::fclose(fp);
562}
563
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200564void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500565{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200566 auto certObjectPath = objectPath + '/';
567
568 if (certType == phosphor::certs::AUTHORITY)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500569 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200570 // Create directory
571 fs::create_directories(certInstallPath);
572
573 // Check if above created proper path
574 if (!fs::is_directory(certInstallPath))
575 {
576 log<level::ERR>("Certificate installation path exists and it is "
577 "not a directory");
578 elog<InternalFailure>();
579 return;
580 }
581
582 for (auto& path : fs::directory_iterator(certInstallPath))
583 {
584 try
585 {
586 installedCerts.emplace_back(std::make_unique<Certificate>(
587 bus, certObjectPath + std::to_string(certIdCounter++),
588 certType, unitToRestart, certInstallPath, path.path(), true,
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200589 certWatchPtr, *this));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200590 }
591 catch (const InternalFailure& e)
592 {
593 report<InternalFailure>();
594 }
595 catch (const InvalidCertificate& e)
596 {
597 report<InvalidCertificate>(
598 Reason("Existing certificate file is corrupted"));
599 }
600 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500601 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200602 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500603 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200604 try
605 {
606 installedCerts.emplace_back(std::make_unique<Certificate>(
607 bus, certObjectPath + '1', certType, unitToRestart,
Zbigniew Kurzynskia3bb38f2019-09-17 13:34:25 +0200608 certInstallPath, certInstallPath, true, certWatchPtr, *this));
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200609 }
610 catch (const InternalFailure& e)
611 {
612 report<InternalFailure>();
613 }
614 catch (const InvalidCertificate& e)
615 {
616 report<InvalidCertificate>(
617 Reason("Existing certificate file is corrupted"));
618 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500619 }
620}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500621
622void Manager::createRSAPrivateKeyFile()
623{
624 fs::path rsaPrivateKeyFileName =
625 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
626
627 try
628 {
629 if (!fs::exists(rsaPrivateKeyFileName))
630 {
631 writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
632 RSA_PRIV_KEY_FILE_NAME);
633 }
634 }
635 catch (const InternalFailure& e)
636 {
637 report<InternalFailure>();
638 }
639}
640
641EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
642{
643 if (keyBitLength != SUPPORTED_KEYBITLENGTH)
644 {
645 log<level::ERR>(
646 "Given Key bit length is not supported",
647 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
648 entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
649 elog<InvalidArgument>(
650 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
651 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
652 }
653 fs::path rsaPrivateKeyFileName =
654 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
655
656 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
657 if (!privateKeyFile)
658 {
659 log<level::ERR>("Unable to open RSA private key file to read",
660 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
661 entry("ERRORREASON=%s", strerror(errno)));
662 elog<InternalFailure>();
663 }
664
665 EVP_PKEY_Ptr privateKey(
666 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
667 ::EVP_PKEY_free);
668 std::fclose(privateKeyFile);
669
670 if (!privateKey)
671 {
672 log<level::ERR>("Error occured during PEM_read_PrivateKey call");
673 elog<InternalFailure>();
674 }
675 return privateKey;
676}
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500677} // namespace certs
678} // namespace phosphor