blob: 76ce09fa577771f644f77f5e918e213ef1e86585 [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
Marri Devender Rao6ceec402019-02-01 03:15:19 -06006#include <phosphor-logging/elog-errors.hpp>
Marri Devender Rao13bf74e2019-03-26 01:52:17 -05007#include <xyz/openbmc_project/Certs/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05008#include <xyz/openbmc_project/Common/error.hpp>
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -05009namespace phosphor
10{
11namespace certs
12{
Marri Devender Rao13965112019-02-27 08:47:12 -060013using InternalFailure =
14 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050015using InvalidCertificate =
16 sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
17using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050018
Marri Devender Raof4682712019-03-19 05:00:28 -050019using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
20using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050021using InvalidArgument =
22 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
23using Argument = xyz::openbmc_project::Common::InvalidArgument;
24
25constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
Marri Devender Raof4682712019-03-19 05:00:28 -050026
27Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
28 const char* path, const CertificateType& type,
29 UnitsToRestart&& unit, CertInstallPath&& installPath) :
Marri Devender Rao6ceec402019-02-01 03:15:19 -060030 Ifaces(bus, path),
Marri Devender Raof4682712019-03-19 05:00:28 -050031 bus(bus), event(event), objectPath(path), certType(type),
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050032 unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
33 certParentInstallPath(fs::path(certInstallPath).parent_path())
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050034{
Marri Devender Raob57d75e2019-07-25 04:56:21 -050035 // create parent certificate path if not existing
36 try
37 {
38 if (!fs::exists(certParentInstallPath))
39 {
40 fs::create_directories(certParentInstallPath);
41 }
42 }
43 catch (fs::filesystem_error& e)
44 {
45 log<level::ERR>("Failed to create directory", entry("ERR=%s", e.what()),
46 entry("DIRECTORY=%s", certParentInstallPath.c_str()));
47 report<InternalFailure>();
48 }
49
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -050050 // Generating RSA private key file if certificate type is server/client
51 if (certType != AUTHORITY)
52 {
53 createRSAPrivateKeyFile();
54 }
55
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050056 // restore any existing certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +020057 createCertificates();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050058
59 // watch is not required for authority certificates
60 if (certType != AUTHORITY)
61 {
62 // watch for certificate file create/replace
63 certWatchPtr = std::make_unique<
64 Watch>(event, certInstallPath, [this]() {
65 try
66 {
67 // if certificate file existing update it
Kowalski, Kamildb029c92019-07-08 17:09:39 +020068 if (!installedCerts.empty())
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050069 {
70 log<level::INFO>(
71 "Inotify callback to update certificate properties");
Kowalski, Kamildb029c92019-07-08 17:09:39 +020072 installedCerts[0]->populateProperties();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050073 }
74 else
75 {
76 log<level::INFO>(
77 "Inotify callback to create certificate object");
Kowalski, Kamildb029c92019-07-08 17:09:39 +020078 createCertificates();
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050079 }
80 }
81 catch (const InternalFailure& e)
82 {
83 commit<InternalFailure>();
84 }
85 catch (const InvalidCertificate& e)
86 {
87 commit<InvalidCertificate>();
88 }
89 });
Marri Devender Raobf7c5882019-02-27 08:41:07 -060090 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +020091 else
92 {
93 const std::string signleCertPath = "/etc/ssl/certs/Root-CA.pem";
94 if (fs::exists(signleCertPath) && !fs::is_empty(signleCertPath))
95 {
96 log<level::NOTICE>(
97 "Legacy certificate detected, will be installed from: ",
98 entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
99 install(signleCertPath);
100 if (!fs::remove(signleCertPath))
101 {
102 log<level::ERR>(
103 "Unable to remove old certificate from: ",
104 entry("SINGLE_CERTPATH=%s", signleCertPath.c_str()));
105 elog<InternalFailure>();
106 }
107 }
108 }
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500109}
110
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200111std::string Manager::install(const std::string filePath)
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500112{
Marri Devender Rao13965112019-02-27 08:47:12 -0600113 using NotAllowed =
114 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
115 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200116
117 if (certType != phosphor::certs::AUTHORITY && !installedCerts.empty())
Marri Devender Rao13965112019-02-27 08:47:12 -0600118 {
119 elog<NotAllowed>(Reason("Certificate already exist"));
120 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500121
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200122 auto certObjectPath = objectPath + '/' + std::to_string(certIdCounter++);
123
124 installedCerts.emplace_back(std::make_unique<Certificate>(
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500125 bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200126 false, certWatchPtr));
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200127 return certObjectPath;
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500128}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500129
130void Manager::delete_()
131{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600132 // TODO: #Issue 4 when a certificate is deleted system auto generates
133 // certificate file. At present we are not supporting creation of
134 // certificate object for the auto-generated certificate file as
135 // deletion if only applicable for REST server and Bmcweb does not allow
136 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200137 installedCerts.clear();
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500138}
Marri Devender Raof4682712019-03-19 05:00:28 -0500139
140std::string Manager::generateCSR(
141 std::vector<std::string> alternativeNames, std::string challengePassword,
142 std::string city, std::string commonName, std::string contactPerson,
143 std::string country, std::string email, std::string givenName,
144 std::string initials, int64_t keyBitLength, std::string keyCurveId,
145 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
146 std::string organization, std::string organizationalUnit, std::string state,
147 std::string surname, std::string unstructuredName)
148{
149 // We support only one CSR.
150 csrPtr.reset(nullptr);
151 auto pid = fork();
152 if (pid == -1)
153 {
154 log<level::ERR>("Error occurred during forking process");
155 report<InternalFailure>();
156 }
157 else if (pid == 0)
158 {
159 try
160 {
161 generateCSRHelper(alternativeNames, challengePassword, city,
162 commonName, contactPerson, country, email,
163 givenName, initials, keyBitLength, keyCurveId,
164 keyPairAlgorithm, keyUsage, organization,
165 organizationalUnit, state, surname,
166 unstructuredName);
167 exit(EXIT_SUCCESS);
168 }
169 catch (const InternalFailure& e)
170 {
171 // commit the error reported in child process and exit
172 // Callback method from SDEvent Loop looks for exit status
173 exit(EXIT_FAILURE);
174 commit<InternalFailure>();
175 }
176 }
177 else
178 {
179 using namespace sdeventplus::source;
180 Child::Callback callback = [this](Child& eventSource,
181 const siginfo_t* si) {
182 eventSource.set_enabled(Enabled::On);
183 if (si->si_status != 0)
184 {
185 this->createCSRObject(Status::FAILURE);
186 }
187 else
188 {
189 this->createCSRObject(Status::SUCCESS);
190 }
191 };
192 try
193 {
194 sigset_t ss;
195 if (sigemptyset(&ss) < 0)
196 {
197 log<level::ERR>("Unable to initialize signal set");
198 elog<InternalFailure>();
199 }
200 if (sigaddset(&ss, SIGCHLD) < 0)
201 {
202 log<level::ERR>("Unable to add signal to signal set");
203 elog<InternalFailure>();
204 }
205
206 // Block SIGCHLD first, so that the event loop can handle it
207 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
208 {
209 log<level::ERR>("Unable to block signal");
210 elog<InternalFailure>();
211 }
212 if (childPtr)
213 {
214 childPtr.reset();
215 }
216 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
217 std::move(callback));
218 }
219 catch (const InternalFailure& e)
220 {
221 commit<InternalFailure>();
222 }
223 }
224 auto csrObjectPath = objectPath + '/' + "csr";
225 return csrObjectPath;
226}
227
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200228std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500229{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200230 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500231}
232
Marri Devender Raof4682712019-03-19 05:00:28 -0500233void Manager::generateCSRHelper(
234 std::vector<std::string> alternativeNames, std::string challengePassword,
235 std::string city, std::string commonName, std::string contactPerson,
236 std::string country, std::string email, std::string givenName,
237 std::string initials, int64_t keyBitLength, std::string keyCurveId,
238 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
239 std::string organization, std::string organizationalUnit, std::string state,
240 std::string surname, std::string unstructuredName)
241{
242 int ret = 0;
243
244 // set version of x509 req
245 int nVersion = 1;
246 // TODO: Issue#6 need to make version number configurable
247 X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
248 ret = X509_REQ_set_version(x509Req.get(), nVersion);
249 if (ret == 0)
250 {
251 log<level::ERR>("Error occured during X509_REQ_set_version call");
252 elog<InternalFailure>();
253 }
254
255 // set subject of x509 req
256 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
257
258 if (!alternativeNames.empty())
259 {
260 for (auto& name : alternativeNames)
261 {
262 addEntry(x509Name, "subjectAltName", name);
263 }
264 }
265 addEntry(x509Name, "challengePassword", challengePassword);
266 addEntry(x509Name, "L", city);
267 addEntry(x509Name, "CN", commonName);
268 addEntry(x509Name, "name", contactPerson);
269 addEntry(x509Name, "C", country);
270 addEntry(x509Name, "emailAddress", email);
271 addEntry(x509Name, "GN", givenName);
272 addEntry(x509Name, "initials", initials);
273 addEntry(x509Name, "algorithm", keyPairAlgorithm);
274 if (!keyUsage.empty())
275 {
276 for (auto& usage : keyUsage)
277 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500278 if (isExtendedKeyUsage(usage))
279 {
280 addEntry(x509Name, "extendedKeyUsage", usage);
281 }
282 else
283 {
284 addEntry(x509Name, "keyUsage", usage);
285 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500286 }
287 }
288 addEntry(x509Name, "O", organization);
289 addEntry(x509Name, "ST", state);
290 addEntry(x509Name, "SN", surname);
291 addEntry(x509Name, "unstructuredName", unstructuredName);
292
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500293 EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
294
295 log<level::INFO>("Given Key pair algorithm",
296 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
297
298 // Used EC algorithm as default if user did not give algorithm type.
299 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500300 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500301 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500302 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500303 else
304 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500305 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
306 "RSA and EC only");
307 elog<InvalidArgument>(
308 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
309 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
310 }
311
312 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
313 if (ret == 0)
314 {
315 log<level::ERR>("Error occured while setting Public key");
316 elog<InternalFailure>();
317 }
318
319 // Write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500320 writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
Marri Devender Raof4682712019-03-19 05:00:28 -0500321
322 // set sign key of x509 req
323 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500324 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500325 {
326 log<level::ERR>("Error occured while signing key of x509");
327 elog<InternalFailure>();
328 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500329
Marri Devender Raof4682712019-03-19 05:00:28 -0500330 log<level::INFO>("Writing CSR to file");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500331 fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
332 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500333}
334
Marri Devender Rao76411052019-08-07 01:25:07 -0500335bool Manager::isExtendedKeyUsage(const std::string& usage)
336{
337 const static std::array<const char*, 6> usageList = {
338 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
339 "Timestamping", "CodeSigning", "EmailProtection"};
340 auto it = std::find_if(
341 usageList.begin(), usageList.end(),
342 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
343 return it != usageList.end();
344}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500345EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500346{
347 int ret = 0;
348 // generate rsa key
349 BIGNUM_Ptr bne(BN_new(), ::BN_free);
350 ret = BN_set_word(bne.get(), RSA_F4);
351 if (ret == 0)
352 {
353 log<level::ERR>("Error occured during BN_set_word call");
354 elog<InternalFailure>();
355 }
356
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500357 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500358 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500359 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500360 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500361 constexpr auto DEFAULT_KEYBITLENGTH = 2048;
362 log<level::INFO>(
363 "KeyBitLength is not given.Hence, using default KeyBitLength",
364 entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
365 keyBitLen = DEFAULT_KEYBITLENGTH;
Marri Devender Raof4682712019-03-19 05:00:28 -0500366 }
367 RSA* rsa = RSA_new();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500368 ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500369 if (ret != 1)
370 {
371 free(rsa);
372 log<level::ERR>("Error occured during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500373 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500374 elog<InternalFailure>();
375 }
376
377 // set public key of x509 req
378 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500379 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
Marri Devender Raof4682712019-03-19 05:00:28 -0500380 if (ret == 0)
381 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500382 free(rsa);
383 log<level::ERR>("Error occured during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500384 elog<InternalFailure>();
385 }
386
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500387 return pKey;
388}
389
390EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
391{
392 std::string curId(curveId);
393
394 if (curId.empty())
395 {
396 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
397 constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
398 log<level::INFO>(
399 "KeyCurveId is not given. Hence using default curve id",
400 entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
401 curId = DEFAULT_KEYCURVEID;
402 }
403
404 int ecGrp = OBJ_txt2nid(curId.c_str());
405
406 if (ecGrp == NID_undef)
407 {
408 log<level::ERR>(
409 "Error occured during convert the curve id string format into NID",
410 entry("KEYCURVEID=%s", curId.c_str()));
411 elog<InternalFailure>();
412 }
413
414 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
415
416 if (ecKey == NULL)
417 {
418 log<level::ERR>(
419 "Error occured during create the EC_Key object from NID",
420 entry("ECGROUP=%d", ecGrp));
421 elog<InternalFailure>();
422 }
423
424 // If you want to save a key and later load it with
425 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
426 // flag on the key.
427 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
428
429 int ret = EC_KEY_generate_key(ecKey);
430
431 if (ret == 0)
432 {
433 EC_KEY_free(ecKey);
434 log<level::ERR>("Error occured during generate EC key");
435 elog<InternalFailure>();
436 }
437
438 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
439 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
440 if (ret == 0)
441 {
442 EC_KEY_free(ecKey);
443 log<level::ERR>("Error occured during assign EC Key into EVP");
444 elog<InternalFailure>();
445 }
446
447 return pKey;
448}
449
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500450void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
451 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500452{
453 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500454 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500455 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500456
457 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
458 if (fp == NULL)
459 {
Marri Devender Raof4682712019-03-19 05:00:28 -0500460 log<level::ERR>("Error occured creating private key file");
461 elog<InternalFailure>();
462 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500463 int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500464 std::fclose(fp);
465 if (ret == 0)
466 {
467 log<level::ERR>("Error occured while writing private key to file");
468 elog<InternalFailure>();
469 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500470}
471
472void Manager::addEntry(X509_NAME* x509Name, const char* field,
473 const std::string& bytes)
474{
475 if (bytes.empty())
476 {
477 return;
478 }
479 int ret = X509_NAME_add_entry_by_txt(
480 x509Name, field, MBSTRING_ASC,
481 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
482 if (ret != 1)
483 {
484 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
485 entry("VALUE=%s", bytes.c_str()));
486 elog<InternalFailure>();
487 }
488}
489
490void Manager::createCSRObject(const Status& status)
491{
492 if (csrPtr)
493 {
494 csrPtr.reset(nullptr);
495 }
496 auto csrObjectPath = objectPath + '/' + "csr";
497 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
498 certInstallPath.c_str(), status);
499}
500
501void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
502{
503 if (fs::exists(filePath))
504 {
505 log<level::INFO>("Removing the existing file",
506 entry("FILENAME=%s", filePath.c_str()));
507 if (!fs::remove(filePath.c_str()))
508 {
509 log<level::ERR>("Unable to remove the file",
510 entry("FILENAME=%s", filePath.c_str()));
511 elog<InternalFailure>();
512 }
513 }
514
515 FILE* fp = NULL;
516
517 if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
518 {
519 log<level::ERR>("Error opening the file to write the CSR",
520 entry("FILENAME=%s", filePath.c_str()));
521 elog<InternalFailure>();
522 }
523
524 int rc = PEM_write_X509_REQ(fp, x509Req.get());
525 if (!rc)
526 {
527 log<level::ERR>("PEM write routine failed",
528 entry("FILENAME=%s", filePath.c_str()));
529 std::fclose(fp);
530 elog<InternalFailure>();
531 }
532 std::fclose(fp);
533}
534
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200535void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500536{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200537 auto certObjectPath = objectPath + '/';
538
539 if (certType == phosphor::certs::AUTHORITY)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500540 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200541 // Create directory
542 fs::create_directories(certInstallPath);
543
544 // Check if above created proper path
545 if (!fs::is_directory(certInstallPath))
546 {
547 log<level::ERR>("Certificate installation path exists and it is "
548 "not a directory");
549 elog<InternalFailure>();
550 return;
551 }
552
553 for (auto& path : fs::directory_iterator(certInstallPath))
554 {
555 try
556 {
557 installedCerts.emplace_back(std::make_unique<Certificate>(
558 bus, certObjectPath + std::to_string(certIdCounter++),
559 certType, unitToRestart, certInstallPath, path.path(), true,
560 certWatchPtr));
561 }
562 catch (const InternalFailure& e)
563 {
564 report<InternalFailure>();
565 }
566 catch (const InvalidCertificate& e)
567 {
568 report<InvalidCertificate>(
569 Reason("Existing certificate file is corrupted"));
570 }
571 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500572 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200573 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500574 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200575 try
576 {
577 installedCerts.emplace_back(std::make_unique<Certificate>(
578 bus, certObjectPath + '1', certType, unitToRestart,
579 certInstallPath, certInstallPath, true, certWatchPtr));
580 }
581 catch (const InternalFailure& e)
582 {
583 report<InternalFailure>();
584 }
585 catch (const InvalidCertificate& e)
586 {
587 report<InvalidCertificate>(
588 Reason("Existing certificate file is corrupted"));
589 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500590 }
591}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500592
593void Manager::createRSAPrivateKeyFile()
594{
595 fs::path rsaPrivateKeyFileName =
596 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
597
598 try
599 {
600 if (!fs::exists(rsaPrivateKeyFileName))
601 {
602 writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
603 RSA_PRIV_KEY_FILE_NAME);
604 }
605 }
606 catch (const InternalFailure& e)
607 {
608 report<InternalFailure>();
609 }
610}
611
612EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
613{
614 if (keyBitLength != SUPPORTED_KEYBITLENGTH)
615 {
616 log<level::ERR>(
617 "Given Key bit length is not supported",
618 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
619 entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
620 elog<InvalidArgument>(
621 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
622 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
623 }
624 fs::path rsaPrivateKeyFileName =
625 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
626
627 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
628 if (!privateKeyFile)
629 {
630 log<level::ERR>("Unable to open RSA private key file to read",
631 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
632 entry("ERRORREASON=%s", strerror(errno)));
633 elog<InternalFailure>();
634 }
635
636 EVP_PKEY_Ptr privateKey(
637 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
638 ::EVP_PKEY_free);
639 std::fclose(privateKeyFile);
640
641 if (!privateKey)
642 {
643 log<level::ERR>("Error occured during PEM_read_PrivateKey call");
644 elog<InternalFailure>();
645 }
646 return privateKey;
647}
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500648} // namespace certs
649} // namespace phosphor