xref: /openbmc/phosphor-certificate-manager/certs_manager.cpp (revision ffad1ef1c244b4a85da7c79dd550cfbb3d1ebeb8)
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;
15*ffad1ef1SMarri Devender Rao using InvalidCertificate =
16*ffad1ef1SMarri Devender Rao     sdbusplus::xyz::openbmc_project::Certs::Error::InvalidCertificate;
17*ffad1ef1SMarri 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)>;
21f4682712SMarri Devender Rao 
22f4682712SMarri Devender Rao Manager::Manager(sdbusplus::bus::bus& bus, sdeventplus::Event& event,
23f4682712SMarri Devender Rao                  const char* path, const CertificateType& type,
24f4682712SMarri Devender Rao                  UnitsToRestart&& unit, CertInstallPath&& installPath) :
256ceec40bSMarri Devender Rao     Ifaces(bus, path),
26f4682712SMarri Devender Rao     bus(bus), event(event), objectPath(path), certType(type),
27*ffad1ef1SMarri Devender Rao     unitToRestart(std::move(unit)), certInstallPath(std::move(installPath))
28cfbc8dc8SJayanth Othayoth {
29*ffad1ef1SMarri Devender Rao     // restore any existing certificates
30bf7c588cSMarri Devender Rao     if (fs::exists(certInstallPath))
31bf7c588cSMarri Devender Rao     {
32*ffad1ef1SMarri Devender Rao         createCertificate();
33*ffad1ef1SMarri Devender Rao     }
34*ffad1ef1SMarri Devender Rao 
35*ffad1ef1SMarri Devender Rao     // watch is not required for authority certificates
36*ffad1ef1SMarri Devender Rao     if (certType != AUTHORITY)
37*ffad1ef1SMarri Devender Rao     {
38*ffad1ef1SMarri Devender Rao         // watch for certificate file create/replace
39*ffad1ef1SMarri Devender Rao         certWatchPtr = std::make_unique<
40*ffad1ef1SMarri Devender Rao             Watch>(event, certInstallPath, [this]() {
41bf7c588cSMarri Devender Rao             try
42bf7c588cSMarri Devender Rao             {
43*ffad1ef1SMarri Devender Rao                 // if certificate file existing update it
44*ffad1ef1SMarri Devender Rao                 if (certificatePtr != nullptr)
45*ffad1ef1SMarri Devender Rao                 {
46*ffad1ef1SMarri Devender Rao                     log<level::INFO>(
47*ffad1ef1SMarri Devender Rao                         "Inotify callback to update certificate properties");
48*ffad1ef1SMarri Devender Rao                     certificatePtr->populateProperties();
49*ffad1ef1SMarri Devender Rao                 }
50*ffad1ef1SMarri Devender Rao                 else
51*ffad1ef1SMarri Devender Rao                 {
52*ffad1ef1SMarri Devender Rao                     log<level::INFO>(
53*ffad1ef1SMarri Devender Rao                         "Inotify callback to create certificate object");
54*ffad1ef1SMarri Devender Rao                     createCertificate();
55*ffad1ef1SMarri Devender Rao                 }
56bf7c588cSMarri Devender Rao             }
57bf7c588cSMarri Devender Rao             catch (const InternalFailure& e)
58bf7c588cSMarri Devender Rao             {
59*ffad1ef1SMarri Devender Rao                 commit<InternalFailure>();
60bf7c588cSMarri Devender Rao             }
61bf7c588cSMarri Devender Rao             catch (const InvalidCertificate& e)
62bf7c588cSMarri Devender Rao             {
63*ffad1ef1SMarri Devender Rao                 commit<InvalidCertificate>();
64bf7c588cSMarri Devender Rao             }
65*ffad1ef1SMarri Devender Rao         });
66bf7c588cSMarri Devender Rao     }
67dd74bd20SJayanth Othayoth }
68589159f2SJayanth Othayoth 
696ceec40bSMarri Devender Rao void Manager::install(const std::string filePath)
70cfbc8dc8SJayanth Othayoth {
711396511dSMarri Devender Rao     using NotAllowed =
721396511dSMarri Devender Rao         sdbusplus::xyz::openbmc_project::Common::Error::NotAllowed;
731396511dSMarri Devender Rao     using Reason = xyz::openbmc_project::Common::NotAllowed::REASON;
741396511dSMarri Devender Rao     // TODO: Issue#3 At present supporting only one certificate to be
751396511dSMarri Devender Rao     // uploaded this need to be revisited to support multiple
761396511dSMarri Devender Rao     // certificates
771396511dSMarri Devender Rao     if (certificatePtr != nullptr)
781396511dSMarri Devender Rao     {
791396511dSMarri Devender Rao         elog<NotAllowed>(Reason("Certificate already exist"));
801396511dSMarri Devender Rao     }
81*ffad1ef1SMarri Devender Rao 
821396511dSMarri Devender Rao     auto certObjectPath = objectPath + '/' + '1';
838f80c35bSMarri Devender Rao     certificatePtr = std::make_unique<Certificate>(
848f80c35bSMarri Devender Rao         bus, certObjectPath, certType, unitToRestart, certInstallPath, filePath,
85*ffad1ef1SMarri Devender Rao         false, certWatchPtr);
86589159f2SJayanth Othayoth }
87ae70b3daSDeepak Kodihalli 
88ae70b3daSDeepak Kodihalli void Manager::delete_()
89ae70b3daSDeepak Kodihalli {
906ceec40bSMarri Devender Rao     // TODO: #Issue 4 when a certificate is deleted system auto generates
916ceec40bSMarri Devender Rao     // certificate file. At present we are not supporting creation of
926ceec40bSMarri Devender Rao     // certificate object for the auto-generated certificate file as
936ceec40bSMarri Devender Rao     // deletion if only applicable for REST server and Bmcweb does not allow
946ceec40bSMarri Devender Rao     // deletion of certificates
956ceec40bSMarri Devender Rao     if (certificatePtr != nullptr)
96ae70b3daSDeepak Kodihalli     {
976ceec40bSMarri Devender Rao         certificatePtr.reset(nullptr);
98ae70b3daSDeepak Kodihalli     }
99ae70b3daSDeepak Kodihalli }
100f4682712SMarri Devender Rao 
101f4682712SMarri Devender Rao std::string Manager::generateCSR(
102f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
103f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
104f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
105f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
106f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
107f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
108f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
109f4682712SMarri Devender Rao {
110f4682712SMarri Devender Rao     // We support only one CSR.
111f4682712SMarri Devender Rao     csrPtr.reset(nullptr);
112f4682712SMarri Devender Rao     auto pid = fork();
113f4682712SMarri Devender Rao     if (pid == -1)
114f4682712SMarri Devender Rao     {
115f4682712SMarri Devender Rao         log<level::ERR>("Error occurred during forking process");
116f4682712SMarri Devender Rao         report<InternalFailure>();
117f4682712SMarri Devender Rao     }
118f4682712SMarri Devender Rao     else if (pid == 0)
119f4682712SMarri Devender Rao     {
120f4682712SMarri Devender Rao         try
121f4682712SMarri Devender Rao         {
122f4682712SMarri Devender Rao             generateCSRHelper(alternativeNames, challengePassword, city,
123f4682712SMarri Devender Rao                               commonName, contactPerson, country, email,
124f4682712SMarri Devender Rao                               givenName, initials, keyBitLength, keyCurveId,
125f4682712SMarri Devender Rao                               keyPairAlgorithm, keyUsage, organization,
126f4682712SMarri Devender Rao                               organizationalUnit, state, surname,
127f4682712SMarri Devender Rao                               unstructuredName);
128f4682712SMarri Devender Rao             exit(EXIT_SUCCESS);
129f4682712SMarri Devender Rao         }
130f4682712SMarri Devender Rao         catch (const InternalFailure& e)
131f4682712SMarri Devender Rao         {
132f4682712SMarri Devender Rao             // commit the error reported in child process and exit
133f4682712SMarri Devender Rao             // Callback method from SDEvent Loop looks for exit status
134f4682712SMarri Devender Rao             exit(EXIT_FAILURE);
135f4682712SMarri Devender Rao             commit<InternalFailure>();
136f4682712SMarri Devender Rao         }
137f4682712SMarri Devender Rao     }
138f4682712SMarri Devender Rao     else
139f4682712SMarri Devender Rao     {
140f4682712SMarri Devender Rao         using namespace sdeventplus::source;
141f4682712SMarri Devender Rao         Child::Callback callback = [this](Child& eventSource,
142f4682712SMarri Devender Rao                                           const siginfo_t* si) {
143f4682712SMarri Devender Rao             eventSource.set_enabled(Enabled::On);
144f4682712SMarri Devender Rao             if (si->si_status != 0)
145f4682712SMarri Devender Rao             {
146f4682712SMarri Devender Rao                 this->createCSRObject(Status::FAILURE);
147f4682712SMarri Devender Rao             }
148f4682712SMarri Devender Rao             else
149f4682712SMarri Devender Rao             {
150f4682712SMarri Devender Rao                 this->createCSRObject(Status::SUCCESS);
151f4682712SMarri Devender Rao             }
152f4682712SMarri Devender Rao         };
153f4682712SMarri Devender Rao         try
154f4682712SMarri Devender Rao         {
155f4682712SMarri Devender Rao             sigset_t ss;
156f4682712SMarri Devender Rao             if (sigemptyset(&ss) < 0)
157f4682712SMarri Devender Rao             {
158f4682712SMarri Devender Rao                 log<level::ERR>("Unable to initialize signal set");
159f4682712SMarri Devender Rao                 elog<InternalFailure>();
160f4682712SMarri Devender Rao             }
161f4682712SMarri Devender Rao             if (sigaddset(&ss, SIGCHLD) < 0)
162f4682712SMarri Devender Rao             {
163f4682712SMarri Devender Rao                 log<level::ERR>("Unable to add signal to signal set");
164f4682712SMarri Devender Rao                 elog<InternalFailure>();
165f4682712SMarri Devender Rao             }
166f4682712SMarri Devender Rao 
167f4682712SMarri Devender Rao             // Block SIGCHLD first, so that the event loop can handle it
168f4682712SMarri Devender Rao             if (sigprocmask(SIG_BLOCK, &ss, NULL) < 0)
169f4682712SMarri Devender Rao             {
170f4682712SMarri Devender Rao                 log<level::ERR>("Unable to block signal");
171f4682712SMarri Devender Rao                 elog<InternalFailure>();
172f4682712SMarri Devender Rao             }
173f4682712SMarri Devender Rao             if (childPtr)
174f4682712SMarri Devender Rao             {
175f4682712SMarri Devender Rao                 childPtr.reset();
176f4682712SMarri Devender Rao             }
177f4682712SMarri Devender Rao             childPtr = std::make_unique<Child>(event, pid, WEXITED | WSTOPPED,
178f4682712SMarri Devender Rao                                                std::move(callback));
179f4682712SMarri Devender Rao         }
180f4682712SMarri Devender Rao         catch (const InternalFailure& e)
181f4682712SMarri Devender Rao         {
182f4682712SMarri Devender Rao             commit<InternalFailure>();
183f4682712SMarri Devender Rao         }
184f4682712SMarri Devender Rao     }
185f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
186f4682712SMarri Devender Rao     return csrObjectPath;
187f4682712SMarri Devender Rao }
188f4682712SMarri Devender Rao 
189*ffad1ef1SMarri Devender Rao CertificatePtr& Manager::getCertificate()
190*ffad1ef1SMarri Devender Rao {
191*ffad1ef1SMarri Devender Rao     return certificatePtr;
192*ffad1ef1SMarri Devender Rao }
193*ffad1ef1SMarri Devender Rao 
194f4682712SMarri Devender Rao void Manager::generateCSRHelper(
195f4682712SMarri Devender Rao     std::vector<std::string> alternativeNames, std::string challengePassword,
196f4682712SMarri Devender Rao     std::string city, std::string commonName, std::string contactPerson,
197f4682712SMarri Devender Rao     std::string country, std::string email, std::string givenName,
198f4682712SMarri Devender Rao     std::string initials, int64_t keyBitLength, std::string keyCurveId,
199f4682712SMarri Devender Rao     std::string keyPairAlgorithm, std::vector<std::string> keyUsage,
200f4682712SMarri Devender Rao     std::string organization, std::string organizationalUnit, std::string state,
201f4682712SMarri Devender Rao     std::string surname, std::string unstructuredName)
202f4682712SMarri Devender Rao {
203f4682712SMarri Devender Rao     int ret = 0;
204f4682712SMarri Devender Rao 
205f4682712SMarri Devender Rao     // set version of x509 req
206f4682712SMarri Devender Rao     int nVersion = 1;
207f4682712SMarri Devender Rao     // TODO: Issue#6 need to make version number configurable
208f4682712SMarri Devender Rao     X509_REQ_Ptr x509Req(X509_REQ_new(), ::X509_REQ_free);
209f4682712SMarri Devender Rao     ret = X509_REQ_set_version(x509Req.get(), nVersion);
210f4682712SMarri Devender Rao     if (ret == 0)
211f4682712SMarri Devender Rao     {
212f4682712SMarri Devender Rao         log<level::ERR>("Error occured during X509_REQ_set_version call");
213f4682712SMarri Devender Rao         elog<InternalFailure>();
214f4682712SMarri Devender Rao     }
215f4682712SMarri Devender Rao 
216f4682712SMarri Devender Rao     // set subject of x509 req
217f4682712SMarri Devender Rao     X509_NAME* x509Name = X509_REQ_get_subject_name(x509Req.get());
218f4682712SMarri Devender Rao 
219f4682712SMarri Devender Rao     if (!alternativeNames.empty())
220f4682712SMarri Devender Rao     {
221f4682712SMarri Devender Rao         for (auto& name : alternativeNames)
222f4682712SMarri Devender Rao         {
223f4682712SMarri Devender Rao             addEntry(x509Name, "subjectAltName", name);
224f4682712SMarri Devender Rao         }
225f4682712SMarri Devender Rao     }
226f4682712SMarri Devender Rao     addEntry(x509Name, "challengePassword", challengePassword);
227f4682712SMarri Devender Rao     addEntry(x509Name, "L", city);
228f4682712SMarri Devender Rao     addEntry(x509Name, "CN", commonName);
229f4682712SMarri Devender Rao     addEntry(x509Name, "name", contactPerson);
230f4682712SMarri Devender Rao     addEntry(x509Name, "C", country);
231f4682712SMarri Devender Rao     addEntry(x509Name, "emailAddress", email);
232f4682712SMarri Devender Rao     addEntry(x509Name, "GN", givenName);
233f4682712SMarri Devender Rao     addEntry(x509Name, "initials", initials);
234f4682712SMarri Devender Rao     addEntry(x509Name, "algorithm", keyPairAlgorithm);
235f4682712SMarri Devender Rao     if (!keyUsage.empty())
236f4682712SMarri Devender Rao     {
237f4682712SMarri Devender Rao         for (auto& usage : keyUsage)
238f4682712SMarri Devender Rao         {
239f4682712SMarri Devender Rao             addEntry(x509Name, "keyUsage", usage);
240f4682712SMarri Devender Rao         }
241f4682712SMarri Devender Rao     }
242f4682712SMarri Devender Rao     addEntry(x509Name, "O", organization);
243f4682712SMarri Devender Rao     addEntry(x509Name, "ST", state);
244f4682712SMarri Devender Rao     addEntry(x509Name, "SN", surname);
245f4682712SMarri Devender Rao     addEntry(x509Name, "unstructuredName", unstructuredName);
246f4682712SMarri Devender Rao 
2478a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(nullptr, ::EVP_PKEY_free);
2488a09b52aSRamesh Iyyar 
2498a09b52aSRamesh Iyyar     log<level::INFO>("Given Key pair algorithm",
2508a09b52aSRamesh Iyyar                      entry("KEYPAIRALGORITHM=%s", keyPairAlgorithm.c_str()));
2518a09b52aSRamesh Iyyar 
2528a09b52aSRamesh Iyyar     // Used EC algorithm as default if user did not give algorithm type.
2538a09b52aSRamesh Iyyar     if (keyPairAlgorithm == "RSA")
2548a09b52aSRamesh Iyyar         pKey = std::move(generateRSAKeyPair(keyBitLength));
2558a09b52aSRamesh Iyyar     else if ((keyPairAlgorithm == "EC") || (keyPairAlgorithm.empty()))
2568a09b52aSRamesh Iyyar         pKey = std::move(generateECKeyPair(keyCurveId));
2578a09b52aSRamesh Iyyar     else
2588a09b52aSRamesh Iyyar     {
2598a09b52aSRamesh Iyyar         using InvalidArgument =
2608a09b52aSRamesh Iyyar             sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
2618a09b52aSRamesh Iyyar         using Argument = xyz::openbmc_project::Common::InvalidArgument;
2628a09b52aSRamesh Iyyar 
2638a09b52aSRamesh Iyyar         log<level::ERR>("Given Key pair algorithm is not supported. Supporting "
2648a09b52aSRamesh Iyyar                         "RSA and EC only");
2658a09b52aSRamesh Iyyar         elog<InvalidArgument>(
2668a09b52aSRamesh Iyyar             Argument::ARGUMENT_NAME("KEYPAIRALGORITHM"),
2678a09b52aSRamesh Iyyar             Argument::ARGUMENT_VALUE(keyPairAlgorithm.c_str()));
2688a09b52aSRamesh Iyyar     }
2698a09b52aSRamesh Iyyar 
2708a09b52aSRamesh Iyyar     ret = X509_REQ_set_pubkey(x509Req.get(), pKey.get());
2718a09b52aSRamesh Iyyar     if (ret == 0)
2728a09b52aSRamesh Iyyar     {
2738a09b52aSRamesh Iyyar         log<level::ERR>("Error occured while setting Public key");
2748a09b52aSRamesh Iyyar         elog<InternalFailure>();
2758a09b52aSRamesh Iyyar     }
2768a09b52aSRamesh Iyyar 
2778a09b52aSRamesh Iyyar     // Write private key to file
2788a09b52aSRamesh Iyyar     writePrivateKey(pKey);
279f4682712SMarri Devender Rao 
280f4682712SMarri Devender Rao     // set sign key of x509 req
281f4682712SMarri Devender Rao     ret = X509_REQ_sign(x509Req.get(), pKey.get(), EVP_sha256());
2828a09b52aSRamesh Iyyar     if (ret == 0)
283f4682712SMarri Devender Rao     {
284f4682712SMarri Devender Rao         log<level::ERR>("Error occured while signing key of x509");
285f4682712SMarri Devender Rao         elog<InternalFailure>();
286f4682712SMarri Devender Rao     }
2878a09b52aSRamesh Iyyar 
288f4682712SMarri Devender Rao     log<level::INFO>("Writing CSR to file");
289f4682712SMarri Devender Rao     std::string path = fs::path(certInstallPath).parent_path();
290f4682712SMarri Devender Rao     std::string csrFilePath = path + '/' + CSR_FILE_NAME;
291f4682712SMarri Devender Rao     writeCSR(csrFilePath, x509Req);
292f4682712SMarri Devender Rao }
293f4682712SMarri Devender Rao 
2948a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateRSAKeyPair(const int64_t keyBitLength)
295f4682712SMarri Devender Rao {
296f4682712SMarri Devender Rao     int ret = 0;
297f4682712SMarri Devender Rao     // generate rsa key
298f4682712SMarri Devender Rao     BIGNUM_Ptr bne(BN_new(), ::BN_free);
299f4682712SMarri Devender Rao     ret = BN_set_word(bne.get(), RSA_F4);
300f4682712SMarri Devender Rao     if (ret == 0)
301f4682712SMarri Devender Rao     {
302f4682712SMarri Devender Rao         log<level::ERR>("Error occured during BN_set_word call");
303f4682712SMarri Devender Rao         elog<InternalFailure>();
304f4682712SMarri Devender Rao     }
305f4682712SMarri Devender Rao 
3068a09b52aSRamesh Iyyar     int64_t keyBitLen = keyBitLength;
307f4682712SMarri Devender Rao     // set keybit length to default value if not set
3088a09b52aSRamesh Iyyar     if (keyBitLen <= 0)
309f4682712SMarri Devender Rao     {
3108a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYBITLENGTH = 2048;
3118a09b52aSRamesh Iyyar         log<level::INFO>(
3128a09b52aSRamesh Iyyar             "KeyBitLength is not given.Hence, using default KeyBitLength",
3138a09b52aSRamesh Iyyar             entry("DEFAULTKEYBITLENGTH=%d", DEFAULT_KEYBITLENGTH));
3148a09b52aSRamesh Iyyar         keyBitLen = DEFAULT_KEYBITLENGTH;
315f4682712SMarri Devender Rao     }
316f4682712SMarri Devender Rao     RSA* rsa = RSA_new();
3178a09b52aSRamesh Iyyar     ret = RSA_generate_key_ex(rsa, keyBitLen, bne.get(), NULL);
318f4682712SMarri Devender Rao     if (ret != 1)
319f4682712SMarri Devender Rao     {
320f4682712SMarri Devender Rao         free(rsa);
321f4682712SMarri Devender Rao         log<level::ERR>("Error occured during RSA_generate_key_ex call",
3228a09b52aSRamesh Iyyar                         entry("KEYBITLENGTH=%PRIu64", keyBitLen));
323f4682712SMarri Devender Rao         elog<InternalFailure>();
324f4682712SMarri Devender Rao     }
325f4682712SMarri Devender Rao 
326f4682712SMarri Devender Rao     // set public key of x509 req
327f4682712SMarri Devender Rao     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
3288a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_RSA(pKey.get(), rsa);
329f4682712SMarri Devender Rao     if (ret == 0)
330f4682712SMarri Devender Rao     {
3318a09b52aSRamesh Iyyar         free(rsa);
3328a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign rsa key into EVP");
333f4682712SMarri Devender Rao         elog<InternalFailure>();
334f4682712SMarri Devender Rao     }
335f4682712SMarri Devender Rao 
3368a09b52aSRamesh Iyyar     return pKey;
3378a09b52aSRamesh Iyyar }
3388a09b52aSRamesh Iyyar 
3398a09b52aSRamesh Iyyar EVP_PKEY_Ptr Manager::generateECKeyPair(const std::string& curveId)
3408a09b52aSRamesh Iyyar {
3418a09b52aSRamesh Iyyar     std::string curId(curveId);
3428a09b52aSRamesh Iyyar 
3438a09b52aSRamesh Iyyar     if (curId.empty())
3448a09b52aSRamesh Iyyar     {
3458a09b52aSRamesh Iyyar         // secp224r1 is equal to RSA 2048 KeyBitLength. Refer RFC 5349
3468a09b52aSRamesh Iyyar         constexpr auto DEFAULT_KEYCURVEID = "secp224r1";
3478a09b52aSRamesh Iyyar         log<level::INFO>(
3488a09b52aSRamesh Iyyar             "KeyCurveId is not given. Hence using default curve id",
3498a09b52aSRamesh Iyyar             entry("DEFAULTKEYCURVEID=%s", DEFAULT_KEYCURVEID));
3508a09b52aSRamesh Iyyar         curId = DEFAULT_KEYCURVEID;
3518a09b52aSRamesh Iyyar     }
3528a09b52aSRamesh Iyyar 
3538a09b52aSRamesh Iyyar     int ecGrp = OBJ_txt2nid(curId.c_str());
3548a09b52aSRamesh Iyyar 
3558a09b52aSRamesh Iyyar     if (ecGrp == NID_undef)
3568a09b52aSRamesh Iyyar     {
3578a09b52aSRamesh Iyyar         log<level::ERR>(
3588a09b52aSRamesh Iyyar             "Error occured during convert the curve id string format into NID",
3598a09b52aSRamesh Iyyar             entry("KEYCURVEID=%s", curId.c_str()));
3608a09b52aSRamesh Iyyar         elog<InternalFailure>();
3618a09b52aSRamesh Iyyar     }
3628a09b52aSRamesh Iyyar 
3638a09b52aSRamesh Iyyar     EC_KEY* ecKey = EC_KEY_new_by_curve_name(ecGrp);
3648a09b52aSRamesh Iyyar 
3658a09b52aSRamesh Iyyar     if (ecKey == NULL)
3668a09b52aSRamesh Iyyar     {
3678a09b52aSRamesh Iyyar         log<level::ERR>(
3688a09b52aSRamesh Iyyar             "Error occured during create the EC_Key object from NID",
3698a09b52aSRamesh Iyyar             entry("ECGROUP=%d", ecGrp));
3708a09b52aSRamesh Iyyar         elog<InternalFailure>();
3718a09b52aSRamesh Iyyar     }
3728a09b52aSRamesh Iyyar 
3738a09b52aSRamesh Iyyar     // If you want to save a key and later load it with
3748a09b52aSRamesh Iyyar     // SSL_CTX_use_PrivateKey_file, then you must set the OPENSSL_EC_NAMED_CURVE
3758a09b52aSRamesh Iyyar     // flag on the key.
3768a09b52aSRamesh Iyyar     EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
3778a09b52aSRamesh Iyyar 
3788a09b52aSRamesh Iyyar     int ret = EC_KEY_generate_key(ecKey);
3798a09b52aSRamesh Iyyar 
3808a09b52aSRamesh Iyyar     if (ret == 0)
3818a09b52aSRamesh Iyyar     {
3828a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
3838a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during generate EC key");
3848a09b52aSRamesh Iyyar         elog<InternalFailure>();
3858a09b52aSRamesh Iyyar     }
3868a09b52aSRamesh Iyyar 
3878a09b52aSRamesh Iyyar     EVP_PKEY_Ptr pKey(EVP_PKEY_new(), ::EVP_PKEY_free);
3888a09b52aSRamesh Iyyar     ret = EVP_PKEY_assign_EC_KEY(pKey.get(), ecKey);
3898a09b52aSRamesh Iyyar     if (ret == 0)
3908a09b52aSRamesh Iyyar     {
3918a09b52aSRamesh Iyyar         EC_KEY_free(ecKey);
3928a09b52aSRamesh Iyyar         log<level::ERR>("Error occured during assign EC Key into EVP");
3938a09b52aSRamesh Iyyar         elog<InternalFailure>();
3948a09b52aSRamesh Iyyar     }
3958a09b52aSRamesh Iyyar 
3968a09b52aSRamesh Iyyar     return pKey;
3978a09b52aSRamesh Iyyar }
3988a09b52aSRamesh Iyyar 
3998a09b52aSRamesh Iyyar void Manager::writePrivateKey(const EVP_PKEY_Ptr& pKey)
4008a09b52aSRamesh Iyyar {
4018a09b52aSRamesh Iyyar     log<level::INFO>("Writing private key to file");
402f4682712SMarri Devender Rao     // write private key to file
403f4682712SMarri Devender Rao     std::string path = fs::path(certInstallPath).parent_path();
404f4682712SMarri Devender Rao     std::string privKeyPath = path + '/' + PRIV_KEY_FILE_NAME;
405f4682712SMarri Devender Rao 
406f4682712SMarri Devender Rao     FILE* fp = std::fopen(privKeyPath.c_str(), "w");
407f4682712SMarri Devender Rao     if (fp == NULL)
408f4682712SMarri Devender Rao     {
409f4682712SMarri Devender Rao         log<level::ERR>("Error occured creating private key file");
410f4682712SMarri Devender Rao         elog<InternalFailure>();
411f4682712SMarri Devender Rao     }
4128a09b52aSRamesh Iyyar     int ret = PEM_write_PrivateKey(fp, pKey.get(), NULL, NULL, 0, 0, NULL);
413f4682712SMarri Devender Rao     std::fclose(fp);
414f4682712SMarri Devender Rao     if (ret == 0)
415f4682712SMarri Devender Rao     {
416f4682712SMarri Devender Rao         log<level::ERR>("Error occured while writing private key to file");
417f4682712SMarri Devender Rao         elog<InternalFailure>();
418f4682712SMarri Devender Rao     }
419f4682712SMarri Devender Rao }
420f4682712SMarri Devender Rao 
421f4682712SMarri Devender Rao void Manager::addEntry(X509_NAME* x509Name, const char* field,
422f4682712SMarri Devender Rao                        const std::string& bytes)
423f4682712SMarri Devender Rao {
424f4682712SMarri Devender Rao     if (bytes.empty())
425f4682712SMarri Devender Rao     {
426f4682712SMarri Devender Rao         return;
427f4682712SMarri Devender Rao     }
428f4682712SMarri Devender Rao     int ret = X509_NAME_add_entry_by_txt(
429f4682712SMarri Devender Rao         x509Name, field, MBSTRING_ASC,
430f4682712SMarri Devender Rao         reinterpret_cast<const unsigned char*>(bytes.c_str()), -1, -1, 0);
431f4682712SMarri Devender Rao     if (ret != 1)
432f4682712SMarri Devender Rao     {
433f4682712SMarri Devender Rao         log<level::ERR>("Unable to set entry", entry("FIELD=%s", field),
434f4682712SMarri Devender Rao                         entry("VALUE=%s", bytes.c_str()));
435f4682712SMarri Devender Rao         elog<InternalFailure>();
436f4682712SMarri Devender Rao     }
437f4682712SMarri Devender Rao }
438f4682712SMarri Devender Rao 
439f4682712SMarri Devender Rao void Manager::createCSRObject(const Status& status)
440f4682712SMarri Devender Rao {
441f4682712SMarri Devender Rao     if (csrPtr)
442f4682712SMarri Devender Rao     {
443f4682712SMarri Devender Rao         csrPtr.reset(nullptr);
444f4682712SMarri Devender Rao     }
445f4682712SMarri Devender Rao     auto csrObjectPath = objectPath + '/' + "csr";
446f4682712SMarri Devender Rao     csrPtr = std::make_unique<CSR>(bus, csrObjectPath.c_str(),
447f4682712SMarri Devender Rao                                    certInstallPath.c_str(), status);
448f4682712SMarri Devender Rao }
449f4682712SMarri Devender Rao 
450f4682712SMarri Devender Rao void Manager::writeCSR(const std::string& filePath, const X509_REQ_Ptr& x509Req)
451f4682712SMarri Devender Rao {
452f4682712SMarri Devender Rao     if (fs::exists(filePath))
453f4682712SMarri Devender Rao     {
454f4682712SMarri Devender Rao         log<level::INFO>("Removing the existing file",
455f4682712SMarri Devender Rao                          entry("FILENAME=%s", filePath.c_str()));
456f4682712SMarri Devender Rao         if (!fs::remove(filePath.c_str()))
457f4682712SMarri Devender Rao         {
458f4682712SMarri Devender Rao             log<level::ERR>("Unable to remove the file",
459f4682712SMarri Devender Rao                             entry("FILENAME=%s", filePath.c_str()));
460f4682712SMarri Devender Rao             elog<InternalFailure>();
461f4682712SMarri Devender Rao         }
462f4682712SMarri Devender Rao     }
463f4682712SMarri Devender Rao 
464f4682712SMarri Devender Rao     FILE* fp = NULL;
465f4682712SMarri Devender Rao 
466f4682712SMarri Devender Rao     if ((fp = std::fopen(filePath.c_str(), "w")) == NULL)
467f4682712SMarri Devender Rao     {
468f4682712SMarri Devender Rao         log<level::ERR>("Error opening the file to write the CSR",
469f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
470f4682712SMarri Devender Rao         elog<InternalFailure>();
471f4682712SMarri Devender Rao     }
472f4682712SMarri Devender Rao 
473f4682712SMarri Devender Rao     int rc = PEM_write_X509_REQ(fp, x509Req.get());
474f4682712SMarri Devender Rao     if (!rc)
475f4682712SMarri Devender Rao     {
476f4682712SMarri Devender Rao         log<level::ERR>("PEM write routine failed",
477f4682712SMarri Devender Rao                         entry("FILENAME=%s", filePath.c_str()));
478f4682712SMarri Devender Rao         std::fclose(fp);
479f4682712SMarri Devender Rao         elog<InternalFailure>();
480f4682712SMarri Devender Rao     }
481f4682712SMarri Devender Rao     std::fclose(fp);
482f4682712SMarri Devender Rao }
483f4682712SMarri Devender Rao 
484*ffad1ef1SMarri Devender Rao void Manager::createCertificate()
485*ffad1ef1SMarri Devender Rao {
486*ffad1ef1SMarri Devender Rao     try
487*ffad1ef1SMarri Devender Rao     {
488*ffad1ef1SMarri Devender Rao         // TODO: Issue#3 At present supporting only one certificate to be
489*ffad1ef1SMarri Devender Rao         // uploaded this need to be revisited to support multiple
490*ffad1ef1SMarri Devender Rao         // certificates
491*ffad1ef1SMarri Devender Rao         auto certObjectPath = objectPath + '/' + '1';
492*ffad1ef1SMarri Devender Rao         certificatePtr = std::make_unique<Certificate>(
493*ffad1ef1SMarri Devender Rao             bus, certObjectPath, certType, unitToRestart, certInstallPath,
494*ffad1ef1SMarri Devender Rao             certInstallPath, true, certWatchPtr);
495*ffad1ef1SMarri Devender Rao     }
496*ffad1ef1SMarri Devender Rao     catch (const InternalFailure& e)
497*ffad1ef1SMarri Devender Rao     {
498*ffad1ef1SMarri Devender Rao         report<InternalFailure>();
499*ffad1ef1SMarri Devender Rao     }
500*ffad1ef1SMarri Devender Rao     catch (const InvalidCertificate& e)
501*ffad1ef1SMarri Devender Rao     {
502*ffad1ef1SMarri Devender Rao         report<InvalidCertificate>(
503*ffad1ef1SMarri Devender Rao             Reason("Existing certificate file is corrupted"));
504*ffad1ef1SMarri Devender Rao     }
505*ffad1ef1SMarri Devender Rao }
506cfbc8dc8SJayanth Othayoth } // namespace certs
507cfbc8dc8SJayanth Othayoth } // namespace phosphor
508