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