xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision c6e58c7e7fade369e64c6eaee23a5b72f37a7ace)
1cfbc8dc8SJayanth Othayoth #include "certs_manager.hpp"
2cfbc8dc8SJayanth Othayoth 
3f4682712SMarri Devender Rao #include <openssl/pem.h>
4f4682712SMarri Devender Rao #include <unistd.h>
5f4682712SMarri Devender Rao 
66ceec40bSMarri Devender Rao #include <phosphor-logging/elog-errors.hpp>
713bf74e4SMarri Devender Rao #include <xyz/openbmc_project/Certs/error.hpp>
8cfbc8dc8SJayanth Othayoth #include <xyz/openbmc_project/Common/error.hpp>
9cfbc8dc8SJayanth Othayoth namespace phosphor
10cfbc8dc8SJayanth Othayoth {
11cfbc8dc8SJayanth Othayoth namespace certs
12cfbc8dc8SJayanth Othayoth {
131396511dSMarri Devender Rao using InternalFailure =
141396511dSMarri Devender Rao     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
15ffad1ef1SMarri Devender Rao using InvalidCertificate =
16ffad1ef1SMarri Devender Rao     sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
17ffad1ef1SMarri Devender Rao using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
18cfbc8dc8SJayanth Othayoth 
19f4682712SMarri Devender Rao using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
20f4682712SMarri Devender Rao using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
21*c6e58c7eSRamesh Iyyar using InvalidArgument =
22*c6e58c7eSRamesh Iyyar     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
23*c6e58c7eSRamesh Iyyar using Argument = xyz::openbmc_project::Common::InvalidArgument;
24*c6e58c7eSRamesh Iyyar 
25*c6e58c7eSRamesh Iyyar constexpr auto SUPPORTED_KEYBITLENGTH = 2048;
26f4682712SMarri Devender Rao 
27f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
28f4682712SMarri Devender Rao                  const char* path, const CertificateType& type,
29f4682712SMarri Devender Rao                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
306ceec40bSMarri Devender Rao     Ifaces(bus, path),
31f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
32*c6e58c7eSRamesh Iyyar     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
33*c6e58c7eSRamesh Iyyar     certParentInstallPath(fs::path(certInstallPath).parent_path())
34cfbc8dc8SJayanth Othayoth {
35*c6e58c7eSRamesh Iyyar     // Generating RSA private key file if certificate type is server/client
36*c6e58c7eSRamesh Iyyar     if (certType != AUTHORITY)
37*c6e58c7eSRamesh Iyyar     {
38*c6e58c7eSRamesh Iyyar         createRSAPrivateKeyFile();
39*c6e58c7eSRamesh Iyyar     }
40*c6e58c7eSRamesh Iyyar 
41ffad1ef1SMarri Devender Rao     // restore any existing certificates
42bf7c588cSMarri Devender Rao     if (fs::exists(certInstallPath))
43bf7c588cSMarri Devender Rao     {
44ffad1ef1SMarri Devender Rao         createCertificate();
45ffad1ef1SMarri Devender Rao     }
46ffad1ef1SMarri Devender Rao 
47ffad1ef1SMarri Devender Rao     // watch is not required for authority certificates
48ffad1ef1SMarri Devender Rao     if (certType != AUTHORITY)
49ffad1ef1SMarri Devender Rao     {
50ffad1ef1SMarri Devender Rao         // watch for certificate file create/replace
51ffad1ef1SMarri Devender Rao         certWatchPtr = std::make_unique<
52ffad1ef1SMarri Devender Rao             Watch>(event, certInstallPath, [this]() {
53bf7c588cSMarri Devender Rao             try
54bf7c588cSMarri Devender Rao             {
55ffad1ef1SMarri Devender Rao                 // if certificate file existing update it
56ffad1ef1SMarri Devender Rao                 if (certificatePtr != nullptr)
57ffad1ef1SMarri Devender Rao                 {
58ffad1ef1SMarri Devender Rao                     log<level::INFO>(
59ffad1ef1SMarri Devender Rao                         "Inotify callback to update certificate properties");
60ffad1ef1SMarri Devender Rao                     certificatePtr->populateProperties();
61ffad1ef1SMarri Devender Rao                 }
62ffad1ef1SMarri Devender Rao                 else
63ffad1ef1SMarri Devender Rao                 {
64ffad1ef1SMarri Devender Rao                     log<level::INFO>(
65ffad1ef1SMarri Devender Rao                         "Inotify callback to create certificate object");
66ffad1ef1SMarri Devender Rao                     createCertificate();
67ffad1ef1SMarri Devender Rao                 }
68bf7c588cSMarri Devender Rao             }
69bf7c588cSMarri Devender Rao             catch (const InternalFailure& e)
70bf7c588cSMarri Devender Rao             {
71ffad1ef1SMarri Devender Rao                 commit<InternalFailure>();
72bf7c588cSMarri Devender Rao             }
73bf7c588cSMarri Devender Rao             catch (const InvalidCertificate& e)
74bf7c588cSMarri Devender Rao             {
75ffad1ef1SMarri Devender Rao                 commit<InvalidCertificate>();
76bf7c588cSMarri Devender Rao             }
77ffad1ef1SMarri Devender Rao         });
78bf7c588cSMarri Devender Rao     }
79dd74bd20SJayanth Othayoth }
80589159f2SJayanth Othayoth 
816ceec40bSMarri Devender Rao void Manager::install(const std::string filePath)
82cfbc8dc8SJayanth Othayoth {
831396511dSMarri Devender Rao     using NotAllowed =
841396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
851396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
861396511dSMarri Devender Rao     // TODO: Issue#3 At present supporting only one certificate to be
871396511dSMarri Devender Rao     // uploaded this need to be revisited to support multiple
881396511dSMarri Devender Rao     // certificates
891396511dSMarri Devender Rao     if (certificatePtr != nullptr)
901396511dSMarri Devender Rao     {
911396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
921396511dSMarri Devender Rao     }
93ffad1ef1SMarri Devender Rao 
941396511dSMarri Devender Rao     auto certObjectPath = objectPath + '/' + '1';
958f80c35bSMarri Devender Rao     certificatePtr = std::make_unique<Certificate>(
968f80c35bSMarri Devender Rao         bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
97ffad1ef1SMarri Devender Rao         false, certWatchPtr);
98589159f2SJayanth Othayoth }
99ae70b3daSDeepak Kodihalli 
100ae70b3daSDeepak Kodihalli void Manager::delete_()
101ae70b3daSDeepak Kodihalli {
1026ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
1036ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
1046ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
1056ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
1066ceec40bSMarri Devender Rao     // deletion of certificates
1076ceec40bSMarri Devender Rao     if (certificatePtr != nullptr)
108ae70b3daSDeepak Kodihalli     {
1096ceec40bSMarri Devender Rao         certificatePtr.reset(nullptr);
110ae70b3daSDeepak Kodihalli     }
111ae70b3daSDeepak Kodihalli }
112f4682712SMarri Devender Rao 
113f4682712SMarri Devender Rao std::string Manager::generateCSR(
114f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
115f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
116f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
117f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
118f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
119f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
120f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
121f4682712SMarri Devender Rao {
122f4682712SMarri Devender Rao     // We support only one CSR.
123f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
124f4682712SMarri Devender Rao     auto pid = fork();
125f4682712SMarri Devender Rao     if (pid == -1)
126f4682712SMarri Devender Rao     {
127f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
128f4682712SMarri Devender Rao         report<InternalFailure>();
129f4682712SMarri Devender Rao     }
130f4682712SMarri Devender Rao     else if (pid == 0)
131f4682712SMarri Devender Rao     {
132f4682712SMarri Devender Rao         try
133f4682712SMarri Devender Rao         {
134f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
135f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
136f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
137f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
138f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
139f4682712SMarri Devender Rao                               unstructuredName);
140f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
141f4682712SMarri Devender Rao         }
142f4682712SMarri Devender Rao         catch (const InternalFailure& e)
143f4682712SMarri Devender Rao         {
144f4682712SMarri Devender Rao             // commit the error reported in child process and exit
145f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
146f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
147f4682712SMarri Devender Rao             commit<InternalFailure>();
148f4682712SMarri Devender Rao         }
149f4682712SMarri Devender Rao     }
150f4682712SMarri Devender Rao     else
151f4682712SMarri Devender Rao     {
152f4682712SMarri Devender Rao         using namespace sdeventplus::source;
153f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
154f4682712SMarri Devender Rao                                           const siginfo_t* si) {
155f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
156f4682712SMarri Devender Rao             if (si->si_status != 0)
157f4682712SMarri Devender Rao             {
158f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
159f4682712SMarri Devender Rao             }
160f4682712SMarri Devender Rao             else
161f4682712SMarri Devender Rao             {
162f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
163f4682712SMarri Devender Rao             }
164f4682712SMarri Devender Rao         };
165f4682712SMarri Devender Rao         try
166f4682712SMarri Devender Rao         {
167f4682712SMarri Devender Rao             sigset_t ss;
168f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
169f4682712SMarri Devender Rao             {
170f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
171f4682712SMarri Devender Rao                 elog<InternalFailure>();
172f4682712SMarri Devender Rao             }
173f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
174f4682712SMarri Devender Rao             {
175f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
176f4682712SMarri Devender Rao                 elog<InternalFailure>();
177f4682712SMarri Devender Rao             }
178f4682712SMarri Devender Rao 
179f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
180f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
181f4682712SMarri Devender Rao             {
182f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
183f4682712SMarri Devender Rao                 elog<InternalFailure>();
184f4682712SMarri Devender Rao             }
185f4682712SMarri Devender Rao             if (childPtr)
186f4682712SMarri Devender Rao             {
187f4682712SMarri Devender Rao                 childPtr.reset();
188f4682712SMarri Devender Rao             }
189f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
190f4682712SMarri Devender Rao                                                std::move(callback));
191f4682712SMarri Devender Rao         }
192f4682712SMarri Devender Rao         catch (const InternalFailure& e)
193f4682712SMarri Devender Rao         {
194f4682712SMarri Devender Rao             commit<InternalFailure>();
195f4682712SMarri Devender Rao         }
196f4682712SMarri Devender Rao     }
197f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
198f4682712SMarri Devender Rao     return csrObjectPath;
199f4682712SMarri Devender Rao }
200f4682712SMarri Devender Rao 
201ffad1ef1SMarri Devender Rao CertificatePtr& Manager::getCertificate()
202ffad1ef1SMarri Devender Rao {
203ffad1ef1SMarri Devender Rao     return certificatePtr;
204ffad1ef1SMarri Devender Rao }
205ffad1ef1SMarri Devender Rao 
206f4682712SMarri Devender Rao void Manager::generateCSRHelper(
207f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
208f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
209f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
210f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
211f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
212f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
213f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
214f4682712SMarri Devender Rao {
215f4682712SMarri Devender Rao     int ret = 0;
216f4682712SMarri Devender Rao 
217f4682712SMarri Devender Rao     // set version of x509 req
218f4682712SMarri Devender Rao     int nVersion = 1;
219f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
220f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
221f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
222f4682712SMarri Devender Rao     if (ret == 0)
223f4682712SMarri Devender Rao     {
224f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
225f4682712SMarri Devender Rao         elog<InternalFailure>();
226f4682712SMarri Devender Rao     }
227f4682712SMarri Devender Rao 
228f4682712SMarri Devender Rao     // set subject of x509 req
229f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
230f4682712SMarri Devender Rao 
231f4682712SMarri Devender Rao     if (!alternativeNames.empty())
232f4682712SMarri Devender Rao     {
233f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
234f4682712SMarri Devender Rao         {
235f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
236f4682712SMarri Devender Rao         }
237f4682712SMarri Devender Rao     }
238f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
239f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
240f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
241f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
242f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
243f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
244f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
245f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
246f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
247f4682712SMarri Devender Rao     if (!keyUsage.empty())
248f4682712SMarri Devender Rao     {
249f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
250f4682712SMarri Devender Rao         {
251f4682712SMarri Devender Rao             addEntry(x509Name, "keyUsage", usage);
252f4682712SMarri Devender Rao         }
253f4682712SMarri Devender Rao     }
254f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
255f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
256f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
257f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
258f4682712SMarri Devender Rao 
2598a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
2608a09b52aSRamesh Iyyar 
2618a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
2628a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
2638a09b52aSRamesh Iyyar 
2648a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
2658a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
266*c6e58c7eSRamesh Iyyar         pKey = getRSAKeyPair(keyBitLength);
2678a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
268*c6e58c7eSRamesh Iyyar         pKey = generateECKeyPair(keyCurveId);
2698a09b52aSRamesh Iyyar     else
2708a09b52aSRamesh Iyyar     {
2718a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
2728a09b52aSRamesh Iyyar                         "RSA and EC only");
2738a09b52aSRamesh Iyyar         elog<InvalidArgument>(
2748a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
2758a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
2768a09b52aSRamesh Iyyar     }
2778a09b52aSRamesh Iyyar 
2788a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
2798a09b52aSRamesh Iyyar     if (ret == 0)
2808a09b52aSRamesh Iyyar     {
2818a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
2828a09b52aSRamesh Iyyar         elog<InternalFailure>();
2838a09b52aSRamesh Iyyar     }
2848a09b52aSRamesh Iyyar 
2858a09b52aSRamesh Iyyar     // Write private key to file
286*c6e58c7eSRamesh Iyyar     writePrivateKey(pKey, PRIV_KEY_FILE_NAME);
287f4682712SMarri Devender Rao 
288f4682712SMarri Devender Rao     // set sign key of x509 req
289f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
2908a09b52aSRamesh Iyyar     if (ret == 0)
291f4682712SMarri Devender Rao     {
292f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
293f4682712SMarri Devender Rao         elog<InternalFailure>();
294f4682712SMarri Devender Rao     }
2958a09b52aSRamesh Iyyar 
296f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
297*c6e58c7eSRamesh Iyyar     fs::path csrFilePath = certParentInstallPath / CSR_FILE_NAME;
298*c6e58c7eSRamesh Iyyar     writeCSR(csrFilePath.string(), x509Req);
299f4682712SMarri Devender Rao }
300f4682712SMarri Devender Rao 
3018a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
302f4682712SMarri Devender Rao {
303f4682712SMarri Devender Rao     int ret = 0;
304f4682712SMarri Devender Rao     // generate rsa key
305f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
306f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
307f4682712SMarri Devender Rao     if (ret == 0)
308f4682712SMarri Devender Rao     {
309f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
310f4682712SMarri Devender Rao         elog<InternalFailure>();
311f4682712SMarri Devender Rao     }
312f4682712SMarri Devender Rao 
3138a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
314f4682712SMarri Devender Rao     // set keybit length to default value if not set
3158a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
316f4682712SMarri Devender Rao     {
3178a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
3188a09b52aSRamesh Iyyar         log<level::INFO>(
3198a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
3208a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
3218a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
322f4682712SMarri Devender Rao     }
323f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
3248a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
325f4682712SMarri Devender Rao     if (ret != 1)
326f4682712SMarri Devender Rao     {
327f4682712SMarri Devender Rao         free(rsa);
328f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
3298a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
330f4682712SMarri Devender Rao         elog<InternalFailure>();
331f4682712SMarri Devender Rao     }
332f4682712SMarri Devender Rao 
333f4682712SMarri Devender Rao     // set public key of x509 req
334f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
3358a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
336f4682712SMarri Devender Rao     if (ret == 0)
337f4682712SMarri Devender Rao     {
3388a09b52aSRamesh Iyyar         free(rsa);
3398a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
340f4682712SMarri Devender Rao         elog<InternalFailure>();
341f4682712SMarri Devender Rao     }
342f4682712SMarri Devender Rao 
3438a09b52aSRamesh Iyyar     return pKey;
3448a09b52aSRamesh Iyyar }
3458a09b52aSRamesh Iyyar 
3468a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
3478a09b52aSRamesh Iyyar {
3488a09b52aSRamesh Iyyar     std::string curId(curveId);
3498a09b52aSRamesh Iyyar 
3508a09b52aSRamesh Iyyar     if (curId.empty())
3518a09b52aSRamesh Iyyar     {
3528a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
3538a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
3548a09b52aSRamesh Iyyar         log<level::INFO>(
3558a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
3568a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
3578a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
3588a09b52aSRamesh Iyyar     }
3598a09b52aSRamesh Iyyar 
3608a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
3618a09b52aSRamesh Iyyar 
3628a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
3638a09b52aSRamesh Iyyar     {
3648a09b52aSRamesh Iyyar         log<level::ERR>(
3658a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
3668a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
3678a09b52aSRamesh Iyyar         elog<InternalFailure>();
3688a09b52aSRamesh Iyyar     }
3698a09b52aSRamesh Iyyar 
3708a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
3718a09b52aSRamesh Iyyar 
3728a09b52aSRamesh Iyyar     if (ecKey == NULL)
3738a09b52aSRamesh Iyyar     {
3748a09b52aSRamesh Iyyar         log<level::ERR>(
3758a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
3768a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
3778a09b52aSRamesh Iyyar         elog<InternalFailure>();
3788a09b52aSRamesh Iyyar     }
3798a09b52aSRamesh Iyyar 
3808a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
3818a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
3828a09b52aSRamesh Iyyar     // flag on the key.
3838a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
3848a09b52aSRamesh Iyyar 
3858a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
3868a09b52aSRamesh Iyyar 
3878a09b52aSRamesh Iyyar     if (ret == 0)
3888a09b52aSRamesh Iyyar     {
3898a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
3908a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
3918a09b52aSRamesh Iyyar         elog<InternalFailure>();
3928a09b52aSRamesh Iyyar     }
3938a09b52aSRamesh Iyyar 
3948a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
3958a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
3968a09b52aSRamesh Iyyar     if (ret == 0)
3978a09b52aSRamesh Iyyar     {
3988a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
3998a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
4008a09b52aSRamesh Iyyar         elog<InternalFailure>();
4018a09b52aSRamesh Iyyar     }
4028a09b52aSRamesh Iyyar 
4038a09b52aSRamesh Iyyar     return pKey;
4048a09b52aSRamesh Iyyar }
4058a09b52aSRamesh Iyyar 
406*c6e58c7eSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey,
407*c6e58c7eSRamesh Iyyar                               const std::string& privKeyFileName)
4088a09b52aSRamesh Iyyar {
4098a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
410f4682712SMarri Devender Rao     // write private key to file
411*c6e58c7eSRamesh Iyyar     fs::path privKeyPath = certParentInstallPath / privKeyFileName;
412f4682712SMarri Devender Rao 
413f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
414f4682712SMarri Devender Rao     if (fp == NULL)
415f4682712SMarri Devender Rao     {
416f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
417f4682712SMarri Devender Rao         elog<InternalFailure>();
418f4682712SMarri Devender Rao     }
4198a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
420f4682712SMarri Devender Rao     std::fclose(fp);
421f4682712SMarri Devender Rao     if (ret == 0)
422f4682712SMarri Devender Rao     {
423f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
424f4682712SMarri Devender Rao         elog<InternalFailure>();
425f4682712SMarri Devender Rao     }
426f4682712SMarri Devender Rao }
427f4682712SMarri Devender Rao 
428f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
429f4682712SMarri Devender Rao                        const std::string& bytes)
430f4682712SMarri Devender Rao {
431f4682712SMarri Devender Rao     if (bytes.empty())
432f4682712SMarri Devender Rao     {
433f4682712SMarri Devender Rao         return;
434f4682712SMarri Devender Rao     }
435f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
436f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
437f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
438f4682712SMarri Devender Rao     if (ret != 1)
439f4682712SMarri Devender Rao     {
440f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
441f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
442f4682712SMarri Devender Rao         elog<InternalFailure>();
443f4682712SMarri Devender Rao     }
444f4682712SMarri Devender Rao }
445f4682712SMarri Devender Rao 
446f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
447f4682712SMarri Devender Rao {
448f4682712SMarri Devender Rao     if (csrPtr)
449f4682712SMarri Devender Rao     {
450f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
451f4682712SMarri Devender Rao     }
452f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
453f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
454f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
455f4682712SMarri Devender Rao }
456f4682712SMarri Devender Rao 
457f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
458f4682712SMarri Devender Rao {
459f4682712SMarri Devender Rao     if (fs::exists(filePath))
460f4682712SMarri Devender Rao     {
461f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
462f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
463f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
464f4682712SMarri Devender Rao         {
465f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
466f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
467f4682712SMarri Devender Rao             elog<InternalFailure>();
468f4682712SMarri Devender Rao         }
469f4682712SMarri Devender Rao     }
470f4682712SMarri Devender Rao 
471f4682712SMarri Devender Rao     FILE* fp = NULL;
472f4682712SMarri Devender Rao 
473f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
474f4682712SMarri Devender Rao     {
475f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
476f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
477f4682712SMarri Devender Rao         elog<InternalFailure>();
478f4682712SMarri Devender Rao     }
479f4682712SMarri Devender Rao 
480f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
481f4682712SMarri Devender Rao     if (!rc)
482f4682712SMarri Devender Rao     {
483f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
484f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
485f4682712SMarri Devender Rao         std::fclose(fp);
486f4682712SMarri Devender Rao         elog<InternalFailure>();
487f4682712SMarri Devender Rao     }
488f4682712SMarri Devender Rao     std::fclose(fp);
489f4682712SMarri Devender Rao }
490f4682712SMarri Devender Rao 
491ffad1ef1SMarri Devender Rao void Manager::createCertificate()
492ffad1ef1SMarri Devender Rao {
493ffad1ef1SMarri Devender Rao     try
494ffad1ef1SMarri Devender Rao     {
495ffad1ef1SMarri Devender Rao         // TODO: Issue#3 At present supporting only one certificate to be
496ffad1ef1SMarri Devender Rao         // uploaded this need to be revisited to support multiple
497ffad1ef1SMarri Devender Rao         // certificates
498ffad1ef1SMarri Devender Rao         auto certObjectPath = objectPath + '/' + '1';
499ffad1ef1SMarri Devender Rao         certificatePtr = std::make_unique<Certificate>(
500ffad1ef1SMarri Devender Rao             bus, certObjectPath, certType, unitToRestart, certInstallPath,
501ffad1ef1SMarri Devender Rao             certInstallPath, true, certWatchPtr);
502ffad1ef1SMarri Devender Rao     }
503ffad1ef1SMarri Devender Rao     catch (const InternalFailure& e)
504ffad1ef1SMarri Devender Rao     {
505ffad1ef1SMarri Devender Rao         report<InternalFailure>();
506ffad1ef1SMarri Devender Rao     }
507ffad1ef1SMarri Devender Rao     catch (const InvalidCertificate& e)
508ffad1ef1SMarri Devender Rao     {
509ffad1ef1SMarri Devender Rao         report<InvalidCertificate>(
510ffad1ef1SMarri Devender Rao             Reason("Existing certificate file is corrupted"));
511ffad1ef1SMarri Devender Rao     }
512ffad1ef1SMarri Devender Rao }
513*c6e58c7eSRamesh Iyyar 
514*c6e58c7eSRamesh Iyyar void Manager::createRSAPrivateKeyFile()
515*c6e58c7eSRamesh Iyyar {
516*c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
517*c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
518*c6e58c7eSRamesh Iyyar 
519*c6e58c7eSRamesh Iyyar     try
520*c6e58c7eSRamesh Iyyar     {
521*c6e58c7eSRamesh Iyyar         if (!fs::exists(rsaPrivateKeyFileName))
522*c6e58c7eSRamesh Iyyar         {
523*c6e58c7eSRamesh Iyyar             writePrivateKey(generateRSAKeyPair(SUPPORTED_KEYBITLENGTH),
524*c6e58c7eSRamesh Iyyar                             RSA_PRIV_KEY_FILE_NAME);
525*c6e58c7eSRamesh Iyyar         }
526*c6e58c7eSRamesh Iyyar     }
527*c6e58c7eSRamesh Iyyar     catch (const InternalFailure& e)
528*c6e58c7eSRamesh Iyyar     {
529*c6e58c7eSRamesh Iyyar         report<InternalFailure>();
530*c6e58c7eSRamesh Iyyar     }
531*c6e58c7eSRamesh Iyyar }
532*c6e58c7eSRamesh Iyyar 
533*c6e58c7eSRamesh Iyyar EVP_PKEY_Ptr Manager::getRSAKeyPair(const int64_t keyBitLength)
534*c6e58c7eSRamesh Iyyar {
535*c6e58c7eSRamesh Iyyar     if (keyBitLength != SUPPORTED_KEYBITLENGTH)
536*c6e58c7eSRamesh Iyyar     {
537*c6e58c7eSRamesh Iyyar         log<level::ERR>(
538*c6e58c7eSRamesh Iyyar             "Given Key bit length is not supported",
539*c6e58c7eSRamesh Iyyar             entry("GIVENKEYBITLENGTH=%d", keyBitLength),
540*c6e58c7eSRamesh Iyyar             entry("SUPPORTEDKEYBITLENGTH=%d", SUPPORTED_KEYBITLENGTH));
541*c6e58c7eSRamesh Iyyar         elog<InvalidArgument>(
542*c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYBITLENGTH"),
543*c6e58c7eSRamesh Iyyar             Argument::ARGUMENT_VALUE(std::to_string(keyBitLength).c_str()));
544*c6e58c7eSRamesh Iyyar     }
545*c6e58c7eSRamesh Iyyar     fs::path rsaPrivateKeyFileName =
546*c6e58c7eSRamesh Iyyar         certParentInstallPath / RSA_PRIV_KEY_FILE_NAME;
547*c6e58c7eSRamesh Iyyar 
548*c6e58c7eSRamesh Iyyar     FILE* privateKeyFile = std::fopen(rsaPrivateKeyFileName.c_str(), "r");
549*c6e58c7eSRamesh Iyyar     if (!privateKeyFile)
550*c6e58c7eSRamesh Iyyar     {
551*c6e58c7eSRamesh Iyyar         log<level::ERR>("Unable to open RSA private key file to read",
552*c6e58c7eSRamesh Iyyar                         entry("RSAKEYFILE=%s", rsaPrivateKeyFileName.c_str()),
553*c6e58c7eSRamesh Iyyar                         entry("ERRORREASON=%s", strerror(errno)));
554*c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
555*c6e58c7eSRamesh Iyyar     }
556*c6e58c7eSRamesh Iyyar 
557*c6e58c7eSRamesh Iyyar     EVP_PKEY_Ptr privateKey(
558*c6e58c7eSRamesh Iyyar         PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr),
559*c6e58c7eSRamesh Iyyar         ::EVP_PKEY_free);
560*c6e58c7eSRamesh Iyyar     std::fclose(privateKeyFile);
561*c6e58c7eSRamesh Iyyar 
562*c6e58c7eSRamesh Iyyar     if (!privateKey)
563*c6e58c7eSRamesh Iyyar     {
564*c6e58c7eSRamesh Iyyar         log<level::ERR>("Error occured during PEM_read_PrivateKey call");
565*c6e58c7eSRamesh Iyyar         elog<InternalFailure>();
566*c6e58c7eSRamesh Iyyar     }
567*c6e58c7eSRamesh Iyyar     return privateKey;
568*c6e58c7eSRamesh Iyyar }
569cfbc8dc8SJayanth Othayoth } // namespace certs
570cfbc8dc8SJayanth Othayoth } // namespace phosphor
571