xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision 8a09b52a767bebdc510914d3b4bb63313dae2196)
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;
15cfbc8dc8SJayanth Othayoth 
16f4682712SMarri Devender Rao using X509_REQ_Ptr = std::unique_ptr<X509_REQ, decltype(&::X509_REQ_free)>;
17f4682712SMarri Devender Rao using BIGNUM_Ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
18f4682712SMarri Devender Rao 
19f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
20f4682712SMarri Devender Rao                  const char* path, const CertificateType& type,
21f4682712SMarri Devender Rao                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
226ceec40bSMarri Devender Rao     Ifaces(bus, path),
23f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
24f4682712SMarri Devender Rao     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath)),
25f4682712SMarri Devender Rao     childPtr(nullptr)
26cfbc8dc8SJayanth Othayoth {
2713bf74e4SMarri Devender Rao     using InvalidCertificate =
2813bf74e4SMarri Devender Rao         sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
2913bf74e4SMarri Devender Rao     using Reason = xyz::openbmc_project::Certs::InvalidCertificate::REASON;
30bf7c588cSMarri Devender Rao     if (fs::exists(certInstallPath))
31bf7c588cSMarri Devender Rao     {
32bf7c588cSMarri Devender Rao         try
33bf7c588cSMarri Devender Rao         {
34bf7c588cSMarri Devender Rao             // TODO: Issue#3 At present supporting only one certificate to be
35bf7c588cSMarri Devender Rao             // uploaded this need to be revisited to support multiple
36bf7c588cSMarri Devender Rao             // certificates
37bf7c588cSMarri Devender Rao             auto certObjectPath = objectPath + '/' + '1';
38bf7c588cSMarri Devender Rao             certificatePtr = std::make_unique<Certificate>(
39bf7c588cSMarri Devender Rao                 bus, certObjectPath, certType, unitToRestart, certInstallPath,
408f80c35bSMarri Devender Rao                 certInstallPath, true);
41bf7c588cSMarri Devender Rao         }
42bf7c588cSMarri Devender Rao         catch (const InternalFailure& e)
43bf7c588cSMarri Devender Rao         {
44bf7c588cSMarri Devender Rao             report<InternalFailure>();
45bf7c588cSMarri Devender Rao         }
46bf7c588cSMarri Devender Rao         catch (const InvalidCertificate& e)
47bf7c588cSMarri Devender Rao         {
48bf7c588cSMarri Devender Rao             report<InvalidCertificate>(
49bf7c588cSMarri Devender Rao                 Reason("Existing certificate file is corrupted"));
50bf7c588cSMarri Devender Rao         }
51bf7c588cSMarri Devender Rao     }
52dd74bd20SJayanth Othayoth }
53589159f2SJayanth Othayoth 
546ceec40bSMarri Devender Rao void Manager::install(const std::string filePath)
55cfbc8dc8SJayanth Othayoth {
561396511dSMarri Devender Rao     using NotAllowed =
571396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
581396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
591396511dSMarri Devender Rao     // TODO: Issue#3 At present supporting only one certificate to be
601396511dSMarri Devender Rao     // uploaded this need to be revisited to support multiple
611396511dSMarri Devender Rao     // certificates
621396511dSMarri Devender Rao     if (certificatePtr != nullptr)
631396511dSMarri Devender Rao     {
641396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
651396511dSMarri Devender Rao     }
661396511dSMarri Devender Rao     auto certObjectPath = objectPath + '/' + '1';
678f80c35bSMarri Devender Rao     certificatePtr = std::make_unique<Certificate>(
688f80c35bSMarri Devender Rao         bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
698f80c35bSMarri Devender Rao         false);
70589159f2SJayanth Othayoth }
71ae70b3daSDeepak Kodihalli 
72ae70b3daSDeepak Kodihalli void Manager::delete_()
73ae70b3daSDeepak Kodihalli {
746ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
756ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
766ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
776ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
786ceec40bSMarri Devender Rao     // deletion of certificates
796ceec40bSMarri Devender Rao     if (certificatePtr != nullptr)
80ae70b3daSDeepak Kodihalli     {
816ceec40bSMarri Devender Rao         certificatePtr.reset(nullptr);
82ae70b3daSDeepak Kodihalli     }
83ae70b3daSDeepak Kodihalli }
84f4682712SMarri Devender Rao 
85f4682712SMarri Devender Rao std::string Manager::generateCSR(
86f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
87f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
88f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
89f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
90f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
91f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
92f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
93f4682712SMarri Devender Rao {
94f4682712SMarri Devender Rao     // We support only one CSR.
95f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
96f4682712SMarri Devender Rao     auto pid = fork();
97f4682712SMarri Devender Rao     if (pid == -1)
98f4682712SMarri Devender Rao     {
99f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
100f4682712SMarri Devender Rao         report<InternalFailure>();
101f4682712SMarri Devender Rao     }
102f4682712SMarri Devender Rao     else if (pid == 0)
103f4682712SMarri Devender Rao     {
104f4682712SMarri Devender Rao         try
105f4682712SMarri Devender Rao         {
106f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
107f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
108f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
109f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
110f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
111f4682712SMarri Devender Rao                               unstructuredName);
112f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
113f4682712SMarri Devender Rao         }
114f4682712SMarri Devender Rao         catch (const InternalFailure& e)
115f4682712SMarri Devender Rao         {
116f4682712SMarri Devender Rao             // commit the error reported in child process and exit
117f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
118f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
119f4682712SMarri Devender Rao             commit<InternalFailure>();
120f4682712SMarri Devender Rao         }
121f4682712SMarri Devender Rao     }
122f4682712SMarri Devender Rao     else
123f4682712SMarri Devender Rao     {
124f4682712SMarri Devender Rao         using namespace sdeventplus::source;
125f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
126f4682712SMarri Devender Rao                                           const siginfo_t* si) {
127f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
128f4682712SMarri Devender Rao             if (si->si_status != 0)
129f4682712SMarri Devender Rao             {
130f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
131f4682712SMarri Devender Rao             }
132f4682712SMarri Devender Rao             else
133f4682712SMarri Devender Rao             {
134f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
135f4682712SMarri Devender Rao             }
136f4682712SMarri Devender Rao         };
137f4682712SMarri Devender Rao         try
138f4682712SMarri Devender Rao         {
139f4682712SMarri Devender Rao             sigset_t ss;
140f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
141f4682712SMarri Devender Rao             {
142f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
143f4682712SMarri Devender Rao                 elog<InternalFailure>();
144f4682712SMarri Devender Rao             }
145f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
146f4682712SMarri Devender Rao             {
147f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
148f4682712SMarri Devender Rao                 elog<InternalFailure>();
149f4682712SMarri Devender Rao             }
150f4682712SMarri Devender Rao 
151f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
152f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
153f4682712SMarri Devender Rao             {
154f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
155f4682712SMarri Devender Rao                 elog<InternalFailure>();
156f4682712SMarri Devender Rao             }
157f4682712SMarri Devender Rao             if (childPtr)
158f4682712SMarri Devender Rao             {
159f4682712SMarri Devender Rao                 childPtr.reset();
160f4682712SMarri Devender Rao             }
161f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
162f4682712SMarri Devender Rao                                                std::move(callback));
163f4682712SMarri Devender Rao         }
164f4682712SMarri Devender Rao         catch (const InternalFailure& e)
165f4682712SMarri Devender Rao         {
166f4682712SMarri Devender Rao             commit<InternalFailure>();
167f4682712SMarri Devender Rao         }
168f4682712SMarri Devender Rao     }
169f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
170f4682712SMarri Devender Rao     return csrObjectPath;
171f4682712SMarri Devender Rao }
172f4682712SMarri Devender Rao 
173f4682712SMarri Devender Rao void Manager::generateCSRHelper(
174f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
175f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
176f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
177f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
178f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
179f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
180f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
181f4682712SMarri Devender Rao {
182f4682712SMarri Devender Rao     int ret = 0;
183f4682712SMarri Devender Rao 
184f4682712SMarri Devender Rao     // set version of x509 req
185f4682712SMarri Devender Rao     int nVersion = 1;
186f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
187f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
188f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
189f4682712SMarri Devender Rao     if (ret == 0)
190f4682712SMarri Devender Rao     {
191f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
192f4682712SMarri Devender Rao         elog<InternalFailure>();
193f4682712SMarri Devender Rao     }
194f4682712SMarri Devender Rao 
195f4682712SMarri Devender Rao     // set subject of x509 req
196f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
197f4682712SMarri Devender Rao 
198f4682712SMarri Devender Rao     if (!alternativeNames.empty())
199f4682712SMarri Devender Rao     {
200f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
201f4682712SMarri Devender Rao         {
202f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
203f4682712SMarri Devender Rao         }
204f4682712SMarri Devender Rao     }
205f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
206f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
207f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
208f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
209f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
210f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
211f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
212f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
213f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
214f4682712SMarri Devender Rao     if (!keyUsage.empty())
215f4682712SMarri Devender Rao     {
216f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
217f4682712SMarri Devender Rao         {
218f4682712SMarri Devender Rao             addEntry(x509Name, "keyUsage", usage);
219f4682712SMarri Devender Rao         }
220f4682712SMarri Devender Rao     }
221f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
222f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
223f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
224f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
225f4682712SMarri Devender Rao 
226*8a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
227*8a09b52aSRamesh Iyyar 
228*8a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
229*8a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
230*8a09b52aSRamesh Iyyar 
231*8a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
232*8a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
233*8a09b52aSRamesh Iyyar         pKey = std::move(generateRSAKeyPair(keyBitLength));
234*8a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
235*8a09b52aSRamesh Iyyar         pKey = std::move(generateECKeyPair(keyCurveId));
236*8a09b52aSRamesh Iyyar     else
237*8a09b52aSRamesh Iyyar     {
238*8a09b52aSRamesh Iyyar         using InvalidArgument =
239*8a09b52aSRamesh Iyyar             sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
240*8a09b52aSRamesh Iyyar         using Argument = xyz::openbmc_project::Common::InvalidArgument;
241*8a09b52aSRamesh Iyyar 
242*8a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
243*8a09b52aSRamesh Iyyar                         "RSA and EC only");
244*8a09b52aSRamesh Iyyar         elog<InvalidArgument>(
245*8a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
246*8a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
247*8a09b52aSRamesh Iyyar     }
248*8a09b52aSRamesh Iyyar 
249*8a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
250*8a09b52aSRamesh Iyyar     if (ret == 0)
251*8a09b52aSRamesh Iyyar     {
252*8a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
253*8a09b52aSRamesh Iyyar         elog<InternalFailure>();
254*8a09b52aSRamesh Iyyar     }
255*8a09b52aSRamesh Iyyar 
256*8a09b52aSRamesh Iyyar     // Write private key to file
257*8a09b52aSRamesh Iyyar     writePrivateKey(pKey);
258f4682712SMarri Devender Rao 
259f4682712SMarri Devender Rao     // set sign key of x509 req
260f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
261*8a09b52aSRamesh Iyyar     if (ret == 0)
262f4682712SMarri Devender Rao     {
263f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
264f4682712SMarri Devender Rao         elog<InternalFailure>();
265f4682712SMarri Devender Rao     }
266*8a09b52aSRamesh Iyyar 
267f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
268f4682712SMarri Devender Rao     std::string path = fs::path(certInstallPath).parent_path();
269f4682712SMarri Devender Rao     std::string csrFilePath = path + '/' + CSR_FILE_NAME;
270f4682712SMarri Devender Rao     writeCSR(csrFilePath, x509Req);
271f4682712SMarri Devender Rao }
272f4682712SMarri Devender Rao 
273*8a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
274f4682712SMarri Devender Rao {
275f4682712SMarri Devender Rao     int ret = 0;
276f4682712SMarri Devender Rao     // generate rsa key
277f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
278f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
279f4682712SMarri Devender Rao     if (ret == 0)
280f4682712SMarri Devender Rao     {
281f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
282f4682712SMarri Devender Rao         elog<InternalFailure>();
283f4682712SMarri Devender Rao     }
284f4682712SMarri Devender Rao 
285*8a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
286f4682712SMarri Devender Rao     // set keybit length to default value if not set
287*8a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
288f4682712SMarri Devender Rao     {
289*8a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
290*8a09b52aSRamesh Iyyar         log<level::INFO>(
291*8a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
292*8a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
293*8a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
294f4682712SMarri Devender Rao     }
295f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
296*8a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
297f4682712SMarri Devender Rao     if (ret != 1)
298f4682712SMarri Devender Rao     {
299f4682712SMarri Devender Rao         free(rsa);
300f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
301*8a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
302f4682712SMarri Devender Rao         elog<InternalFailure>();
303f4682712SMarri Devender Rao     }
304f4682712SMarri Devender Rao 
305f4682712SMarri Devender Rao     // set public key of x509 req
306f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
307*8a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
308f4682712SMarri Devender Rao     if (ret == 0)
309f4682712SMarri Devender Rao     {
310*8a09b52aSRamesh Iyyar         free(rsa);
311*8a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
312f4682712SMarri Devender Rao         elog<InternalFailure>();
313f4682712SMarri Devender Rao     }
314f4682712SMarri Devender Rao 
315*8a09b52aSRamesh Iyyar     return pKey;
316*8a09b52aSRamesh Iyyar }
317*8a09b52aSRamesh Iyyar 
318*8a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
319*8a09b52aSRamesh Iyyar {
320*8a09b52aSRamesh Iyyar     std::string curId(curveId);
321*8a09b52aSRamesh Iyyar 
322*8a09b52aSRamesh Iyyar     if (curId.empty())
323*8a09b52aSRamesh Iyyar     {
324*8a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
325*8a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
326*8a09b52aSRamesh Iyyar         log<level::INFO>(
327*8a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
328*8a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
329*8a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
330*8a09b52aSRamesh Iyyar     }
331*8a09b52aSRamesh Iyyar 
332*8a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
333*8a09b52aSRamesh Iyyar 
334*8a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
335*8a09b52aSRamesh Iyyar     {
336*8a09b52aSRamesh Iyyar         log<level::ERR>(
337*8a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
338*8a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
339*8a09b52aSRamesh Iyyar         elog<InternalFailure>();
340*8a09b52aSRamesh Iyyar     }
341*8a09b52aSRamesh Iyyar 
342*8a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
343*8a09b52aSRamesh Iyyar 
344*8a09b52aSRamesh Iyyar     if (ecKey == NULL)
345*8a09b52aSRamesh Iyyar     {
346*8a09b52aSRamesh Iyyar         log<level::ERR>(
347*8a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
348*8a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
349*8a09b52aSRamesh Iyyar         elog<InternalFailure>();
350*8a09b52aSRamesh Iyyar     }
351*8a09b52aSRamesh Iyyar 
352*8a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
353*8a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
354*8a09b52aSRamesh Iyyar     // flag on the key.
355*8a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
356*8a09b52aSRamesh Iyyar 
357*8a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
358*8a09b52aSRamesh Iyyar 
359*8a09b52aSRamesh Iyyar     if (ret == 0)
360*8a09b52aSRamesh Iyyar     {
361*8a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
362*8a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
363*8a09b52aSRamesh Iyyar         elog<InternalFailure>();
364*8a09b52aSRamesh Iyyar     }
365*8a09b52aSRamesh Iyyar 
366*8a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
367*8a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
368*8a09b52aSRamesh Iyyar     if (ret == 0)
369*8a09b52aSRamesh Iyyar     {
370*8a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
371*8a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
372*8a09b52aSRamesh Iyyar         elog<InternalFailure>();
373*8a09b52aSRamesh Iyyar     }
374*8a09b52aSRamesh Iyyar 
375*8a09b52aSRamesh Iyyar     return pKey;
376*8a09b52aSRamesh Iyyar }
377*8a09b52aSRamesh Iyyar 
378*8a09b52aSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey)
379*8a09b52aSRamesh Iyyar {
380*8a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
381f4682712SMarri Devender Rao     // write private key to file
382f4682712SMarri Devender Rao     std::string path = fs::path(certInstallPath).parent_path();
383f4682712SMarri Devender Rao     std::string privKeyPath = path + '/' + PRIV_KEY_FILE_NAME;
384f4682712SMarri Devender Rao 
385f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
386f4682712SMarri Devender Rao     if (fp == NULL)
387f4682712SMarri Devender Rao     {
388f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
389f4682712SMarri Devender Rao         elog<InternalFailure>();
390f4682712SMarri Devender Rao     }
391*8a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
392f4682712SMarri Devender Rao     std::fclose(fp);
393f4682712SMarri Devender Rao     if (ret == 0)
394f4682712SMarri Devender Rao     {
395f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
396f4682712SMarri Devender Rao         elog<InternalFailure>();
397f4682712SMarri Devender Rao     }
398f4682712SMarri Devender Rao }
399f4682712SMarri Devender Rao 
400f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
401f4682712SMarri Devender Rao                        const std::string& bytes)
402f4682712SMarri Devender Rao {
403f4682712SMarri Devender Rao     if (bytes.empty())
404f4682712SMarri Devender Rao     {
405f4682712SMarri Devender Rao         return;
406f4682712SMarri Devender Rao     }
407f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
408f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
409f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
410f4682712SMarri Devender Rao     if (ret != 1)
411f4682712SMarri Devender Rao     {
412f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
413f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
414f4682712SMarri Devender Rao         elog<InternalFailure>();
415f4682712SMarri Devender Rao     }
416f4682712SMarri Devender Rao }
417f4682712SMarri Devender Rao 
418f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
419f4682712SMarri Devender Rao {
420f4682712SMarri Devender Rao     if (csrPtr)
421f4682712SMarri Devender Rao     {
422f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
423f4682712SMarri Devender Rao     }
424f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
425f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
426f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
427f4682712SMarri Devender Rao }
428f4682712SMarri Devender Rao 
429f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
430f4682712SMarri Devender Rao {
431f4682712SMarri Devender Rao     if (fs::exists(filePath))
432f4682712SMarri Devender Rao     {
433f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
434f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
435f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
436f4682712SMarri Devender Rao         {
437f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
438f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
439f4682712SMarri Devender Rao             elog<InternalFailure>();
440f4682712SMarri Devender Rao         }
441f4682712SMarri Devender Rao     }
442f4682712SMarri Devender Rao 
443f4682712SMarri Devender Rao     FILE* fp = NULL;
444f4682712SMarri Devender Rao 
445f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
446f4682712SMarri Devender Rao     {
447f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
448f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
449f4682712SMarri Devender Rao         elog<InternalFailure>();
450f4682712SMarri Devender Rao     }
451f4682712SMarri Devender Rao 
452f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
453f4682712SMarri Devender Rao     if (!rc)
454f4682712SMarri Devender Rao     {
455f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
456f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
457f4682712SMarri Devender Rao         std::fclose(fp);
458f4682712SMarri Devender Rao         elog<InternalFailure>();
459f4682712SMarri Devender Rao     }
460f4682712SMarri Devender Rao     std::fclose(fp);
461f4682712SMarri Devender Rao }
462f4682712SMarri Devender Rao 
463cfbc8dc8SJayanth Othayoth } // namespace certs
464cfbc8dc8SJayanth Othayoth } // namespace phosphor
465