blob: a03088de546e442372eabe30c18de894a574fd64 [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
Marri Devender Raobf7c5882019-02-27 08:41:07 -060057 if (fs::exists(certInstallPath))
58 {
Marri Devender Raoffad1ef2019-06-03 04:54:12 -050059 createCertificate();
60 }
61
62 // watch is not required for authority certificates
63 if (certType != AUTHORITY)
64 {
65 // watch for certificate file create/replace
66 certWatchPtr = std::make_unique<
67 Watch>(event, certInstallPath, [this]() {
68 try
69 {
70 // if certificate file existing update it
71 if (certificatePtr != nullptr)
72 {
73 log<level::INFO>(
74 "Inotify callback to update certificate properties");
75 certificatePtr->populateProperties();
76 }
77 else
78 {
79 log<level::INFO>(
80 "Inotify callback to create certificate object");
81 createCertificate();
82 }
83 }
84 catch (const InternalFailure& e)
85 {
86 commit<InternalFailure>();
87 }
88 catch (const InvalidCertificate& e)
89 {
90 commit<InvalidCertificate>();
91 }
92 });
Marri Devender Raobf7c5882019-02-27 08:41:07 -060093 }
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050094}
95
Marri Devender Rao6ceec402019-02-01 03:15:19 -060096void Manager::install(const std::string filePath)
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -050097{
Marri Devender Rao13965112019-02-27 08:47:12 -060098 using NotAllowed =
99 sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
100 using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
101 // TODO: Issue#3 At present supporting only one certificate to be
102 // uploaded this need to be revisited to support multiple
103 // certificates
104 if (certificatePtr != nullptr)
105 {
106 elog<NotAllowed>(Reason("Certificate already exist"));
107 }
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500108
Marri Devender Rao13965112019-02-27 08:47:12 -0600109 auto certObjectPath = objectPath + '/' + '1';
Marri Devender Rao8f80c352019-05-13 00:53:01 -0500110 certificatePtr = std::make_unique<Certificate>(
111 bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500112 false, certWatchPtr);
Jayanth Othayoth589159f2018-09-28 08:32:39 -0500113}
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500114
115void Manager::delete_()
116{
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600117 // TODO: #Issue 4 when a certificate is deleted system auto generates
118 // certificate file. At present we are not supporting creation of
119 // certificate object for the auto-generated certificate file as
120 // deletion if only applicable for REST server and Bmcweb does not allow
121 // deletion of certificates
122 if (certificatePtr != nullptr)
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500123 {
Marri Devender Rao6ceec402019-02-01 03:15:19 -0600124 certificatePtr.reset(nullptr);
Deepak Kodihalliae70b3d2018-09-30 05:42:00 -0500125 }
126}
Marri Devender Raof4682712019-03-19 05:00:28 -0500127
128std::string Manager::generateCSR(
129 std::vector<std::string> alternativeNames, std::string challengePassword,
130 std::string city, std::string commonName, std::string contactPerson,
131 std::string country, std::string email, std::string givenName,
132 std::string initials, int64_t keyBitLength, std::string keyCurveId,
133 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
134 std::string organization, std::string organizationalUnit, std::string state,
135 std::string surname, std::string unstructuredName)
136{
137 // We support only one CSR.
138 csrPtr.reset(nullptr);
139 auto pid = fork();
140 if (pid == -1)
141 {
142 log<level::ERR>("Error occurred during forking process");
143 report<InternalFailure>();
144 }
145 else if (pid == 0)
146 {
147 try
148 {
149 generateCSRHelper(alternativeNames, challengePassword, city,
150 commonName, contactPerson, country, email,
151 givenName, initials, keyBitLength, keyCurveId,
152 keyPairAlgorithm, keyUsage, organization,
153 organizationalUnit, state, surname,
154 unstructuredName);
155 exit(EXIT_SUCCESS);
156 }
157 catch (const InternalFailure& e)
158 {
159 // commit the error reported in child process and exit
160 // Callback method from SDEvent Loop looks for exit status
161 exit(EXIT_FAILURE);
162 commit<InternalFailure>();
163 }
164 }
165 else
166 {
167 using namespace sdeventplus::source;
168 Child::Callback callback = [this](Child& eventSource,
169 const siginfo_t* si) {
170 eventSource.set_enabled(Enabled::On);
171 if (si->si_status != 0)
172 {
173 this->createCSRObject(Status::FAILURE);
174 }
175 else
176 {
177 this->createCSRObject(Status::SUCCESS);
178 }
179 };
180 try
181 {
182 sigset_t ss;
183 if (sigemptyset(&ss) < 0)
184 {
185 log<level::ERR>("Unable to initialize signal set");
186 elog<InternalFailure>();
187 }
188 if (sigaddset(&ss, SIGCHLD) < 0)
189 {
190 log<level::ERR>("Unable to add signal to signal set");
191 elog<InternalFailure>();
192 }
193
194 // Block SIGCHLD first, so that the event loop can handle it
195 if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
196 {
197 log<level::ERR>("Unable to block signal");
198 elog<InternalFailure>();
199 }
200 if (childPtr)
201 {
202 childPtr.reset();
203 }
204 childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
205 std::move(callback));
206 }
207 catch (const InternalFailure& e)
208 {
209 commit<InternalFailure>();
210 }
211 }
212 auto csrObjectPath = objectPath + '/' + "csr";
213 return csrObjectPath;
214}
215
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500216CertificatePtr& Manager::getCertificate()
217{
218 return certificatePtr;
219}
220
Marri Devender Raof4682712019-03-19 05:00:28 -0500221void Manager::generateCSRHelper(
222 std::vector<std::string> alternativeNames, std::string challengePassword,
223 std::string city, std::string commonName, std::string contactPerson,
224 std::string country, std::string email, std::string givenName,
225 std::string initials, int64_t keyBitLength, std::string keyCurveId,
226 std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
227 std::string organization, std::string organizationalUnit, std::string state,
228 std::string surname, std::string unstructuredName)
229{
230 int ret = 0;
231
232 // set version of x509 req
233 int nVersion = 1;
234 // TODO: Issue#6 need to make version number configurable
235 X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
236 ret = X509_REQ_set_version(x509Req.get(), nVersion);
237 if (ret == 0)
238 {
239 log<level::ERR>("Error occured during X509_REQ_set_version call");
240 elog<InternalFailure>();
241 }
242
243 // set subject of x509 req
244 X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
245
246 if (!alternativeNames.empty())
247 {
248 for (auto& name : alternativeNames)
249 {
250 addEntry(x509Name, "subjectAltName", name);
251 }
252 }
253 addEntry(x509Name, "challengePassword", challengePassword);
254 addEntry(x509Name, "L", city);
255 addEntry(x509Name, "CN", commonName);
256 addEntry(x509Name, "name", contactPerson);
257 addEntry(x509Name, "C", country);
258 addEntry(x509Name, "emailAddress", email);
259 addEntry(x509Name, "GN", givenName);
260 addEntry(x509Name, "initials", initials);
261 addEntry(x509Name, "algorithm", keyPairAlgorithm);
262 if (!keyUsage.empty())
263 {
264 for (auto& usage : keyUsage)
265 {
Marri Devender Rao76411052019-08-07 01:25:07 -0500266 if (isExtendedKeyUsage(usage))
267 {
268 addEntry(x509Name, "extendedKeyUsage", usage);
269 }
270 else
271 {
272 addEntry(x509Name, "keyUsage", usage);
273 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500274 }
275 }
276 addEntry(x509Name, "O", organization);
277 addEntry(x509Name, "ST", state);
278 addEntry(x509Name, "SN", surname);
279 addEntry(x509Name, "unstructuredName", unstructuredName);
280
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500281 EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
282
283 log<level::INFO>("Given Key pair algorithm",
284 entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
285
286 // Used EC algorithm as default if user did not give algorithm type.
287 if (keyPairAlgorithm == "RSA")
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500288 pKey = getRSAKeyPair(keyBitLength);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500289 else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500290 pKey = generateECKeyPair(keyCurveId);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500291 else
292 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500293 log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
294 "RSA and EC only");
295 elog<InvalidArgument>(
296 Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
297 Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
298 }
299
300 ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
301 if (ret == 0)
302 {
303 log<level::ERR>("Error occured while setting Public key");
304 elog<InternalFailure>();
305 }
306
307 // Write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500308 writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
Marri Devender Raof4682712019-03-19 05:00:28 -0500309
310 // set sign key of x509 req
311 ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500312 if (ret == 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500313 {
314 log<level::ERR>("Error occured while signing key of x509");
315 elog<InternalFailure>();
316 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500317
Marri Devender Raof4682712019-03-19 05:00:28 -0500318 log<level::INFO>("Writing CSR to file");
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500319 fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
320 writeCSR(csrFilePath.string(), x509Req);
Marri Devender Raof4682712019-03-19 05:00:28 -0500321}
322
Marri Devender Rao76411052019-08-07 01:25:07 -0500323bool Manager::isExtendedKeyUsage(const std::string& usage)
324{
325 const static std::array<const char*, 6> usageList = {
326 "ServerAuthentication", "ClientAuthentication", "OCSPSigning",
327 "Timestamping", "CodeSigning", "EmailProtection"};
328 auto it = std::find_if(
329 usageList.begin(), usageList.end(),
330 [&usage](const char* s) { return (strcmp(s, usage.c_str()) == 0); });
331 return it != usageList.end();
332}
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500333EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
Marri Devender Raof4682712019-03-19 05:00:28 -0500334{
335 int ret = 0;
336 // generate rsa key
337 BIGNUM_Ptr bne(BN_new(), ::BN_free);
338 ret = BN_set_word(bne.get(), RSA_F4);
339 if (ret == 0)
340 {
341 log<level::ERR>("Error occured during BN_set_word call");
342 elog<InternalFailure>();
343 }
344
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500345 int64_t keyBitLen = keyBitLength;
Marri Devender Raof4682712019-03-19 05:00:28 -0500346 // set keybit length to default value if not set
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500347 if (keyBitLen <= 0)
Marri Devender Raof4682712019-03-19 05:00:28 -0500348 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500349 constexpr auto DEFAULT_KEYBITLENGTH = 2048;
350 log<level::INFO>(
351 "KeyBitLength is not given.Hence, using default KeyBitLength",
352 entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
353 keyBitLen = DEFAULT_KEYBITLENGTH;
Marri Devender Raof4682712019-03-19 05:00:28 -0500354 }
355 RSA* rsa = RSA_new();
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500356 ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500357 if (ret != 1)
358 {
359 free(rsa);
360 log<level::ERR>("Error occured during RSA_generate_key_ex call",
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500361 entry("KEYBITLENGTH=%PRIu64", keyBitLen));
Marri Devender Raof4682712019-03-19 05:00:28 -0500362 elog<InternalFailure>();
363 }
364
365 // set public key of x509 req
366 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500367 ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
Marri Devender Raof4682712019-03-19 05:00:28 -0500368 if (ret == 0)
369 {
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500370 free(rsa);
371 log<level::ERR>("Error occured during assign rsa key into EVP");
Marri Devender Raof4682712019-03-19 05:00:28 -0500372 elog<InternalFailure>();
373 }
374
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500375 return pKey;
376}
377
378EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
379{
380 std::string curId(curveId);
381
382 if (curId.empty())
383 {
384 // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
385 constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
386 log<level::INFO>(
387 "KeyCurveId is not given. Hence using default curve id",
388 entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
389 curId = DEFAULT_KEYCURVEID;
390 }
391
392 int ecGrp = OBJ_txt2nid(curId.c_str());
393
394 if (ecGrp == NID_undef)
395 {
396 log<level::ERR>(
397 "Error occured during convert the curve id string format into NID",
398 entry("KEYCURVEID=%s", curId.c_str()));
399 elog<InternalFailure>();
400 }
401
402 EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
403
404 if (ecKey == NULL)
405 {
406 log<level::ERR>(
407 "Error occured during create the EC_Key object from NID",
408 entry("ECGROUP=%d", ecGrp));
409 elog<InternalFailure>();
410 }
411
412 // If you want to save a key and later load it with
413 // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
414 // flag on the key.
415 EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
416
417 int ret = EC_KEY_generate_key(ecKey);
418
419 if (ret == 0)
420 {
421 EC_KEY_free(ecKey);
422 log<level::ERR>("Error occured during generate EC key");
423 elog<InternalFailure>();
424 }
425
426 EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
427 ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
428 if (ret == 0)
429 {
430 EC_KEY_free(ecKey);
431 log<level::ERR>("Error occured during assign EC Key into EVP");
432 elog<InternalFailure>();
433 }
434
435 return pKey;
436}
437
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500438void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
439 const std::string& privKeyFileName)
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500440{
441 log<level::INFO>("Writing private key to file");
Marri Devender Raof4682712019-03-19 05:00:28 -0500442 // write private key to file
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500443 fs::path privKeyPath = certParentInstallPath / privKeyFileName;
Marri Devender Raof4682712019-03-19 05:00:28 -0500444
445 FILE* fp = std::fopen(privKeyPath.c_str(), "w");
446 if (fp == NULL)
447 {
Marri Devender Raof4682712019-03-19 05:00:28 -0500448 log<level::ERR>("Error occured creating private key file");
449 elog<InternalFailure>();
450 }
Ramesh Iyyar8a09b522019-06-07 05:23:29 -0500451 int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
Marri Devender Raof4682712019-03-19 05:00:28 -0500452 std::fclose(fp);
453 if (ret == 0)
454 {
455 log<level::ERR>("Error occured while writing private key to file");
456 elog<InternalFailure>();
457 }
Marri Devender Raof4682712019-03-19 05:00:28 -0500458}
459
460void Manager::addEntry(X509_NAME* x509Name, const char* field,
461 const std::string& bytes)
462{
463 if (bytes.empty())
464 {
465 return;
466 }
467 int ret = X509_NAME_add_entry_by_txt(
468 x509Name, field, MBSTRING_ASC,
469 reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
470 if (ret != 1)
471 {
472 log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
473 entry("VALUE=%s", bytes.c_str()));
474 elog<InternalFailure>();
475 }
476}
477
478void Manager::createCSRObject(const Status& status)
479{
480 if (csrPtr)
481 {
482 csrPtr.reset(nullptr);
483 }
484 auto csrObjectPath = objectPath + '/' + "csr";
485 csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
486 certInstallPath.c_str(), status);
487}
488
489void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
490{
491 if (fs::exists(filePath))
492 {
493 log<level::INFO>("Removing the existing file",
494 entry("FILENAME=%s", filePath.c_str()));
495 if (!fs::remove(filePath.c_str()))
496 {
497 log<level::ERR>("Unable to remove the file",
498 entry("FILENAME=%s", filePath.c_str()));
499 elog<InternalFailure>();
500 }
501 }
502
503 FILE* fp = NULL;
504
505 if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
506 {
507 log<level::ERR>("Error opening the file to write the CSR",
508 entry("FILENAME=%s", filePath.c_str()));
509 elog<InternalFailure>();
510 }
511
512 int rc = PEM_write_X509_REQ(fp, x509Req.get());
513 if (!rc)
514 {
515 log<level::ERR>("PEM write routine failed",
516 entry("FILENAME=%s", filePath.c_str()));
517 std::fclose(fp);
518 elog<InternalFailure>();
519 }
520 std::fclose(fp);
521}
522
Marri Devender Raoffad1ef2019-06-03 04:54:12 -0500523void Manager::createCertificate()
524{
525 try
526 {
527 // TODO: Issue#3 At present supporting only one certificate to be
528 // uploaded this need to be revisited to support multiple
529 // certificates
530 auto certObjectPath = objectPath + '/' + '1';
531 certificatePtr = std::make_unique<Certificate>(
532 bus, certObjectPath, certType, unitToRestart, certInstallPath,
533 certInstallPath, true, certWatchPtr);
534 }
535 catch (const InternalFailure& e)
536 {
537 report<InternalFailure>();
538 }
539 catch (const InvalidCertificate& e)
540 {
541 report<InvalidCertificate>(
542 Reason("Existing certificate file is corrupted"));
543 }
544}
Ramesh Iyyarc6e58c72019-07-16 08:52:47 -0500545
546void Manager::createRSAPrivateKeyFile()
547{
548 fs::path rsaPrivateKeyFileName =
549 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
550
551 try
552 {
553 if (!fs::exists(rsaPrivateKeyFileName))
554 {
555 writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
556 RSA_PRIV_KEY_FILE_NAME);
557 }
558 }
559 catch (const InternalFailure& e)
560 {
561 report<InternalFailure>();
562 }
563}
564
565EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
566{
567 if (keyBitLength != SUPPORTED_KEYBITLENGTH)
568 {
569 log<level::ERR>(
570 "Given Key bit length is not supported",
571 entry("GIVENKEYBITLENGTH=%d", keyBitLength),
572 entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
573 elog<InvalidArgument>(
574 Argument::ARGUMENT_NAME("KEYBITLENGTH"),
575 Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
576 }
577 fs::path rsaPrivateKeyFileName =
578 certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
579
580 FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
581 if (!privateKeyFile)
582 {
583 log<level::ERR>("Unable to open RSA private key file to read",
584 entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
585 entry("ERRORREASON=%s", strerror(errno)));
586 elog<InternalFailure>();
587 }
588
589 EVP_PKEY_Ptr privateKey(
590 PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
591 ::EVP_PKEY_free);
592 std::fclose(privateKeyFile);
593
594 if (!privateKey)
595 {
596 log<level::ERR>("Error occured during PEM_read_PrivateKey call");
597 elog<InternalFailure>();
598 }
599 return privateKey;
600}
Jayanth Othayothcfbc8dc2018-09-03 07:22:27 -0500601} // namespace certs
602} // namespace phosphor