diff options
author | Jayanth Othayoth <ojayanth@in.ibm.com> | 2018-02-21 05:43:20 -0600 |
---|---|---|
committer | Jayanth Othayoth <ojayanth@in.ibm.com> | 2018-03-13 07:51:14 -0500 |
commit | fb6e1fc202b43141b2d57b641d784501a837096a (patch) | |
tree | e432283fc7170eaafcda9d70ea4c19839ef2a262 /image_verify.cpp | |
parent | 2ab9b1098efa8280f0cea165d1b6856e1ce05170 (diff) | |
download | phosphor-bmc-code-mgmt-fb6e1fc202b43141b2d57b641d784501a837096a.tar.gz phosphor-bmc-code-mgmt-fb6e1fc202b43141b2d57b641d784501a837096a.zip |
Enabled OpenSSL based signature validation functions
Added support for OpenSSL based function for the signed
image validation.
Change-Id: I45bb677276694b0bbb92c7c694c7f95b8b2c011d
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Diffstat (limited to 'image_verify.cpp')
-rw-r--r-- | image_verify.cpp | 140 |
1 files changed, 132 insertions, 8 deletions
diff --git a/image_verify.cpp b/image_verify.cpp index 5b50f39..99c7d2b 100644 --- a/image_verify.cpp +++ b/image_verify.cpp @@ -1,4 +1,8 @@ #include <set> +#include <fstream> +#include <sys/stat.h> +#include <fcntl.h> +#include <openssl/err.h> #include "image_verify.hpp" #include "config.h" @@ -152,25 +156,35 @@ bool Signature::systemLevelVerify() // Verify the file signature with available key types // public keys and hash function. + // For any internal failure during the key/hash pair specific + // validation, should continue the validation with next + // available Key/hash pair. for (const auto& keyType : keyTypes) { auto keyHashPair = getKeyHashFileNames(keyType); auto hashFunc = Version::getValue(keyHashPair.first, hashFunctionTag); - // Verify manifest file signature - valid = verifyFile(manifestFile, manifestFileSig, keyHashPair.second, - hashFunc); - if (valid) + try { - // Verify publickey file signature. - valid = - verifyFile(pkeyFile, pkeyFileSig, keyHashPair.second, hashFunc); + // Verify manifest file signature + valid = verifyFile(manifestFile, manifestFileSig, + keyHashPair.second, hashFunc); if (valid) { - break; + // Verify publickey file signature. + valid = verifyFile(pkeyFile, pkeyFileSig, keyHashPair.second, + hashFunc); + if (valid) + { + break; + } } } + catch (const InternalFailure& e) + { + valid = false; + } } return valid; } @@ -179,9 +193,119 @@ bool Signature::verifyFile(const fs::path& file, const fs::path& sigFile, const fs::path& publicKey, const std::string& hashFunc) { + + // Check existence of the files in the system. + if (!(fs::exists(file) && fs::exists(sigFile))) + { + log<level::ERR>("Failed to find the Data or signature file.", + entry("FILE=%s", file.c_str())); + elog<InternalFailure>(); + } + + // Create RSA. + auto publicRSA = createPublicRSA(publicKey); + if (publicRSA == nullptr) + { + log<level::ERR>("Failed to create RSA", + entry("FILE=%s", publicKey.c_str())); + elog<InternalFailure>(); + } + + // Assign key to RSA. + EVP_PKEY_Ptr pKeyPtr(EVP_PKEY_new(), ::EVP_PKEY_free); + EVP_PKEY_assign_RSA(pKeyPtr.get(), publicRSA); + + // Initializes a digest context. + EVP_MD_CTX_Ptr rsaVerifyCtx(EVP_MD_CTX_create(), ::EVP_MD_CTX_destroy); + + // Adds all digest algorithms to the internal table + OpenSSL_add_all_digests(); + + // Create Hash structre. + auto hashStruct = EVP_get_digestbyname(hashFunc.c_str()); + if (!hashStruct) + { + log<level::ERR>("EVP_get_digestbynam: Unknown message digest", + entry("HASH=%s", hashFunc.c_str())); + elog<InternalFailure>(); + } + + auto result = EVP_DigestVerifyInit(rsaVerifyCtx.get(), nullptr, hashStruct, + nullptr, pKeyPtr.get()); + + if (result <= 0) + { + log<level::ERR>("Error occured during EVP_DigestVerifyInit", + entry("ERRCODE=%lu", ERR_get_error())); + elog<InternalFailure>(); + } + + // Hash the data file and update the verification context + auto size = fs::file_size(file); + auto dataPtr = mapFile(file, size); + + result = EVP_DigestVerifyUpdate(rsaVerifyCtx.get(), dataPtr(), size); + if (result <= 0) + { + log<level::ERR>("Error occured during EVP_DigestVerifyUpdate", + entry("ERRCODE=%lu", ERR_get_error())); + elog<InternalFailure>(); + } + + // Verify the data with signature. + size = fs::file_size(sigFile); + auto signature = mapFile(sigFile, size); + + result = EVP_DigestVerifyFinal( + rsaVerifyCtx.get(), reinterpret_cast<unsigned char*>(signature()), + size); + + // Check the verification result. + if (result < 0) + { + log<level::ERR>("Error occured during EVP_DigestVerifyFinal", + entry("ERRCODE=%lu", ERR_get_error())); + elog<InternalFailure>(); + } + + if (result == 0) + { + log<level::ERR>("EVP_DigestVerifyFinal:Signature validation failed", + entry("PATH=%s", sigFile.c_str())); + return false; + } return true; } +inline RSA* Signature::createPublicRSA(const fs::path& publicKey) +{ + RSA* rsa = nullptr; + auto size = fs::file_size(publicKey); + + // Read public key file + auto data = mapFile(publicKey, size); + + BIO_MEM_Ptr keyBio(BIO_new_mem_buf(data(), -1), &::BIO_free); + if (keyBio.get() == nullptr) + { + log<level::ERR>("Failed to create new BIO Memory buffer"); + elog<InternalFailure>(); + } + + rsa = PEM_read_bio_RSA_PUBKEY(keyBio.get(), &rsa, nullptr, nullptr); + + return rsa; +} + +CustomMap Signature::mapFile(const fs::path& path, size_t size) +{ + + CustomFd fd(open(path.c_str(), O_RDONLY)); + + return CustomMap(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd(), 0), + size); +} + } // namespace image } // namespace software } // namespace phosphor |