blob: e1774b695388cf70b76d7e1969da9ffff0ac596c [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 }
Zbigniew Lukwinski3b07b772019-10-09 11:43:34 +0200121 else if (certType == phosphor::certs::AUTHORITY &&
122 installedCerts.size() >= AUTHORITY_CERTIFICATES_LIMIT)
123 {
124 elog<NotAllowed>(Reason("Certificates limit reached"));
125 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500126
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200127 auto certObjectPath = objectPath + '/' + std::to_string(certIdCounter++);
128
129 installedCerts.emplace_back(std::make_unique<Certificate>(
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500130 bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200131 false, certWatchPtr));
Zbigniew Kurzynski06a69d72019-09-27 10:57:38 +0200132 return certObjectPath;
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500133}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500134
135void Manager::delete_()
136{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600137 // TODO: #Issue 4 when a certificate is deleted system auto generates
138 // certificate file. At present we are not supporting creation of
139 // certificate object for the auto-generated certificate file as
140 // deletion if only applicable for REST server and Bmcweb does not allow
141 // deletion of certificates
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200142 installedCerts.clear();
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500143}
Marri Devender Raof4682712019-03-19 05:00:28 -0500144
145std::string Manager::generateCSR(
146 std::vector<std::string> alternativeNames, std::string challengePassword,
147 std::string city, std::string commonName, std::string contactPerson,
148 std::string country, std::string email, std::string givenName,
149 std::string initials, int64_t keyBitLength, std::string keyCurveId,
150 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
151 std::string organization, std::string organizationalUnit, std::string state,
152 std::string surname, std::string unstructuredName)
153{
154 // We support only one CSR.
155 csrPtr.reset(nullptr);
156 auto pid = fork();
157 if (pid == -1)
158 {
159 log<level::ERR>("Error occurred during forking process");
160 report<InternalFailure>();
161 }
162 else if (pid == 0)
163 {
164 try
165 {
166 generateCSRHelper(alternativeNames, challengePassword, city,
167 commonName, contactPerson, country, email,
168 givenName, initials, keyBitLength, keyCurveId,
169 keyPairAlgorithm, keyUsage, organization,
170 organizationalUnit, state, surname,
171 unstructuredName);
172 exit(EXIT_SUCCESS);
173 }
174 catch (const InternalFailure& e)
175 {
176 // commit the error reported in child process and exit
177 // Callback method from SDEvent Loop looks for exit status
178 exit(EXIT_FAILURE);
179 commit<InternalFailure>();
180 }
181 }
182 else
183 {
184 using namespace sdeventplus::source;
185 Child::Callback callback = [this](Child& eventSource,
186 const siginfo_t* si) {
187 eventSource.set_enabled(Enabled::On);
188 if (si->si_status != 0)
189 {
190 this->createCSRObject(Status::FAILURE);
191 }
192 else
193 {
194 this->createCSRObject(Status::SUCCESS);
195 }
196 };
197 try
198 {
199 sigset_t ss;
200 if (sigemptyset(&ss) < 0)
201 {
202 log<level::ERR>("Unable to initialize signal set");
203 elog<InternalFailure>();
204 }
205 if (sigaddset(&ss, SIGCHLD) < 0)
206 {
207 log<level::ERR>("Unable to add signal to signal set");
208 elog<InternalFailure>();
209 }
210
211 // Block SIGCHLD first, so that the event loop can handle it
212 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
213 {
214 log<level::ERR>("Unable to block signal");
215 elog<InternalFailure>();
216 }
217 if (childPtr)
218 {
219 childPtr.reset();
220 }
221 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
222 std::move(callback));
223 }
224 catch (const InternalFailure& e)
225 {
226 commit<InternalFailure>();
227 }
228 }
229 auto csrObjectPath = objectPath + '/' + "csr";
230 return csrObjectPath;
231}
232
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200233std::vector<std::unique_ptr<Certificate>>& Manager::getCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500234{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200235 return installedCerts;
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500236}
237
Marri Devender Raof4682712019-03-19 05:00:28 -0500238void Manager::generateCSRHelper(
239 std::vector<std::string> alternativeNames, std::string challengePassword,
240 std::string city, std::string commonName, std::string contactPerson,
241 std::string country, std::string email, std::string givenName,
242 std::string initials, int64_t keyBitLength, std::string keyCurveId,
243 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
244 std::string organization, std::string organizationalUnit, std::string state,
245 std::string surname, std::string unstructuredName)
246{
247 int ret = 0;
248
249 // set version of x509 req
250 int nVersion = 1;
251 // TODO: Issue#6 need to make version number configurable
252 X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
253 ret = X509_REQ_set_version(x509Req.get(), nVersion);
254 if (ret == 0)
255 {
256 log<level::ERR>("Error occured during X509_REQ_set_version call");
257 elog<InternalFailure>();
258 }
259
260 // set subject of x509 req
261 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
262
263 if (!alternativeNames.empty())
264 {
265 for (auto& name : alternativeNames)
266 {
267 addEntry(x509Name, "subjectAltName", name);
268 }
269 }
270 addEntry(x509Name, "challengePassword", challengePassword);
271 addEntry(x509Name, "L", city);
272 addEntry(x509Name, "CN", commonName);
273 addEntry(x509Name, "name", contactPerson);
274 addEntry(x509Name, "C", country);
275 addEntry(x509Name, "emailAddress", email);
276 addEntry(x509Name, "GN", givenName);
277 addEntry(x509Name, "initials", initials);
278 addEntry(x509Name, "algorithm", keyPairAlgorithm);
279 if (!keyUsage.empty())
280 {
281 for (auto& usage : keyUsage)
282 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500283 if (isExtendedKeyUsage(usage))
284 {
285 addEntry(x509Name, "extendedKeyUsage", usage);
286 }
287 else
288 {
289 addEntry(x509Name, "keyUsage", usage);
290 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500291 }
292 }
293 addEntry(x509Name, "O", organization);
294 addEntry(x509Name, "ST", state);
295 addEntry(x509Name, "SN", surname);
296 addEntry(x509Name, "unstructuredName", unstructuredName);
297
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500298 EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
299
300 log<level::INFO>("Given Key pair algorithm",
301 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
302
303 // Used EC algorithm as default if user did not give algorithm type.
304 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500305 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500306 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500307 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500308 else
309 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500310 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
311 "RSA and EC only");
312 elog<InvalidArgument>(
313 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
314 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
315 }
316
317 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
318 if (ret == 0)
319 {
320 log<level::ERR>("Error occured while setting Public key");
321 elog<InternalFailure>();
322 }
323
324 // Write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500325 writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
Marri Devender Raof4682712019-03-19 05:00:28 -0500326
327 // set sign key of x509 req
328 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500329 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500330 {
331 log<level::ERR>("Error occured while signing key of x509");
332 elog<InternalFailure>();
333 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500334
Marri Devender Raof4682712019-03-19 05:00:28 -0500335 log<level::INFO>("Writing CSR to file");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500336 fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
337 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500338}
339
Marri Devender Rao76411052019-08-07 01:25:07 -0500340bool Manager::isExtendedKeyUsage(const std::string& usage)
341{
342 const static std::array<const char*, 6> usageList = {
343 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
344 "Timestamping", "CodeSigning", "EmailProtection"};
345 auto it = std::find_if(
346 usageList.begin(), usageList.end(),
347 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
348 return it != usageList.end();
349}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500350EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500351{
352 int ret = 0;
353 // generate rsa key
354 BIGNUM_Ptr bne(BN_new(), ::BN_free);
355 ret = BN_set_word(bne.get(), RSA_F4);
356 if (ret == 0)
357 {
358 log<level::ERR>("Error occured during BN_set_word call");
359 elog<InternalFailure>();
360 }
361
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500362 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500363 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500364 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500365 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500366 constexpr auto DEFAULT_KEYBITLENGTH = 2048;
367 log<level::INFO>(
368 "KeyBitLength is not given.Hence, using default KeyBitLength",
369 entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
370 keyBitLen = DEFAULT_KEYBITLENGTH;
Marri Devender Raof4682712019-03-19 05:00:28 -0500371 }
372 RSA* rsa = RSA_new();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500373 ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500374 if (ret != 1)
375 {
376 free(rsa);
377 log<level::ERR>("Error occured during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500378 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500379 elog<InternalFailure>();
380 }
381
382 // set public key of x509 req
383 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500384 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
Marri Devender Raof4682712019-03-19 05:00:28 -0500385 if (ret == 0)
386 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500387 free(rsa);
388 log<level::ERR>("Error occured during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500389 elog<InternalFailure>();
390 }
391
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500392 return pKey;
393}
394
395EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
396{
397 std::string curId(curveId);
398
399 if (curId.empty())
400 {
401 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
402 constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
403 log<level::INFO>(
404 "KeyCurveId is not given. Hence using default curve id",
405 entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
406 curId = DEFAULT_KEYCURVEID;
407 }
408
409 int ecGrp = OBJ_txt2nid(curId.c_str());
410
411 if (ecGrp == NID_undef)
412 {
413 log<level::ERR>(
414 "Error occured during convert the curve id string format into NID",
415 entry("KEYCURVEID=%s", curId.c_str()));
416 elog<InternalFailure>();
417 }
418
419 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
420
421 if (ecKey == NULL)
422 {
423 log<level::ERR>(
424 "Error occured during create the EC_Key object from NID",
425 entry("ECGROUP=%d", ecGrp));
426 elog<InternalFailure>();
427 }
428
429 // If you want to save a key and later load it with
430 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
431 // flag on the key.
432 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
433
434 int ret = EC_KEY_generate_key(ecKey);
435
436 if (ret == 0)
437 {
438 EC_KEY_free(ecKey);
439 log<level::ERR>("Error occured during generate EC key");
440 elog<InternalFailure>();
441 }
442
443 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
444 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
445 if (ret == 0)
446 {
447 EC_KEY_free(ecKey);
448 log<level::ERR>("Error occured during assign EC Key into EVP");
449 elog<InternalFailure>();
450 }
451
452 return pKey;
453}
454
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500455void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
456 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500457{
458 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500459 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500460 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500461
462 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
463 if (fp == NULL)
464 {
Marri Devender Raof4682712019-03-19 05:00:28 -0500465 log<level::ERR>("Error occured creating private key file");
466 elog<InternalFailure>();
467 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500468 int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500469 std::fclose(fp);
470 if (ret == 0)
471 {
472 log<level::ERR>("Error occured while writing private key to file");
473 elog<InternalFailure>();
474 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500475}
476
477void Manager::addEntry(X509_NAME* x509Name, const char* field,
478 const std::string& bytes)
479{
480 if (bytes.empty())
481 {
482 return;
483 }
484 int ret = X509_NAME_add_entry_by_txt(
485 x509Name, field, MBSTRING_ASC,
486 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
487 if (ret != 1)
488 {
489 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
490 entry("VALUE=%s", bytes.c_str()));
491 elog<InternalFailure>();
492 }
493}
494
495void Manager::createCSRObject(const Status& status)
496{
497 if (csrPtr)
498 {
499 csrPtr.reset(nullptr);
500 }
501 auto csrObjectPath = objectPath + '/' + "csr";
502 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
503 certInstallPath.c_str(), status);
504}
505
506void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
507{
508 if (fs::exists(filePath))
509 {
510 log<level::INFO>("Removing the existing file",
511 entry("FILENAME=%s", filePath.c_str()));
512 if (!fs::remove(filePath.c_str()))
513 {
514 log<level::ERR>("Unable to remove the file",
515 entry("FILENAME=%s", filePath.c_str()));
516 elog<InternalFailure>();
517 }
518 }
519
520 FILE* fp = NULL;
521
522 if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
523 {
524 log<level::ERR>("Error opening the file to write the CSR",
525 entry("FILENAME=%s", filePath.c_str()));
526 elog<InternalFailure>();
527 }
528
529 int rc = PEM_write_X509_REQ(fp, x509Req.get());
530 if (!rc)
531 {
532 log<level::ERR>("PEM write routine failed",
533 entry("FILENAME=%s", filePath.c_str()));
534 std::fclose(fp);
535 elog<InternalFailure>();
536 }
537 std::fclose(fp);
538}
539
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200540void Manager::createCertificates()
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500541{
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200542 auto certObjectPath = objectPath + '/';
543
544 if (certType == phosphor::certs::AUTHORITY)
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500545 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200546 // Create directory
547 fs::create_directories(certInstallPath);
548
549 // Check if above created proper path
550 if (!fs::is_directory(certInstallPath))
551 {
552 log<level::ERR>("Certificate installation path exists and it is "
553 "not a directory");
554 elog<InternalFailure>();
555 return;
556 }
557
558 for (auto& path : fs::directory_iterator(certInstallPath))
559 {
560 try
561 {
562 installedCerts.emplace_back(std::make_unique<Certificate>(
563 bus, certObjectPath + std::to_string(certIdCounter++),
564 certType, unitToRestart, certInstallPath, path.path(), true,
565 certWatchPtr));
566 }
567 catch (const InternalFailure& e)
568 {
569 report<InternalFailure>();
570 }
571 catch (const InvalidCertificate& e)
572 {
573 report<InvalidCertificate>(
574 Reason("Existing certificate file is corrupted"));
575 }
576 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500577 }
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200578 else if (fs::exists(certInstallPath))
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500579 {
Kowalski, Kamildb029c92019-07-08 17:09:39 +0200580 try
581 {
582 installedCerts.emplace_back(std::make_unique<Certificate>(
583 bus, certObjectPath + '1', certType, unitToRestart,
584 certInstallPath, certInstallPath, true, certWatchPtr));
585 }
586 catch (const InternalFailure& e)
587 {
588 report<InternalFailure>();
589 }
590 catch (const InvalidCertificate& e)
591 {
592 report<InvalidCertificate>(
593 Reason("Existing certificate file is corrupted"));
594 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500595 }
596}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500597
598void Manager::createRSAPrivateKeyFile()
599{
600 fs::path rsaPrivateKeyFileName =
601 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
602
603 try
604 {
605 if (!fs::exists(rsaPrivateKeyFileName))
606 {
607 writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
608 RSA_PRIV_KEY_FILE_NAME);
609 }
610 }
611 catch (const InternalFailure& e)
612 {
613 report<InternalFailure>();
614 }
615}
616
617EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
618{
619 if (keyBitLength != SUPPORTED_KEYBITLENGTH)
620 {
621 log<level::ERR>(
622 "Given Key bit length is not supported",
623 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
624 entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
625 elog<InvalidArgument>(
626 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
627 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
628 }
629 fs::path rsaPrivateKeyFileName =
630 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
631
632 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
633 if (!privateKeyFile)
634 {
635 log<level::ERR>("Unable to open RSA private key file to read",
636 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
637 entry("ERRORREASON=%s", strerror(errno)));
638 elog<InternalFailure>();
639 }
640
641 EVP_PKEY_Ptr privateKey(
642 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
643 ::EVP_PKEY_free);
644 std::fclose(privateKeyFile);
645
646 if (!privateKey)
647 {
648 log<level::ERR>("Error occured during PEM_read_PrivateKey call");
649 elog<InternalFailure>();
650 }
651 return privateKey;
652}
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500653} // namespace certs
654} // namespace phosphor