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 | |
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>
-rw-r--r-- | image_verify.cpp | 140 | ||||
-rw-r--r-- | image_verify.hpp | 106 |
2 files changed, 237 insertions, 9 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 diff --git a/image_verify.hpp b/image_verify.hpp index 3e65288..5b590f4 100644 --- a/image_verify.hpp +++ b/image_verify.hpp @@ -1,6 +1,11 @@ #pragma once +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/pem.h> #include <experimental/filesystem> #include <set> +#include <unistd.h> +#include <sys/mman.h> namespace phosphor { @@ -17,9 +22,93 @@ using HashFilePath = fs::path; using KeyHashPathPair = std::pair<HashFilePath, PublicKeyPath>; using AvailableKeyTypes = std::set<Key_t>; +// RAII support for openSSL functions. +using BIO_MEM_Ptr = std::unique_ptr<BIO, decltype(&::BIO_free)>; +using EVP_PKEY_Ptr = std::unique_ptr<EVP_PKEY, decltype(&::EVP_PKEY_free)>; +using EVP_MD_CTX_Ptr = + std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_destroy)>; + // BMC flash image file name list. const std::vector<std::string> bmcImages = {"image-kernel", "image-rofs", "image-rwfs", "image-u-boot"}; +/** @struct CustomFd + * + * RAII wrapper for file descriptor. + */ +struct CustomFd +{ + public: + CustomFd() = delete; + CustomFd(const CustomFd&) = delete; + CustomFd& operator=(const CustomFd&) = delete; + CustomFd(CustomFd&&) = default; + CustomFd& operator=(CustomFd&&) = default; + /** @brief Saves File descriptor and uses it to do file operation + * + * @param[in] fd - File descriptor + */ + CustomFd(int fd) : fd(fd) + { + } + + ~CustomFd() + { + if (fd >= 0) + { + close(fd); + } + } + + int operator()() const + { + return fd; + } + + private: + /** @brief File descriptor */ + int fd = -1; +}; + +/** @struct CustomMap + * + * RAII wrapper for mmap. + */ +struct CustomMap +{ + private: + /** @brief starting address of the map */ + void* addr; + + /** @brief length of the mapping */ + size_t length; + + public: + CustomMap() = delete; + CustomMap(const CustomMap&) = delete; + CustomMap& operator=(const CustomMap&) = delete; + CustomMap(CustomMap&&) = default; + CustomMap& operator=(CustomMap&&) = default; + + /** @brief Saves starting address of the map and + * and length of the file. + * @param[in] addr - Starting address of the map + * @param[in] length - length of the map + */ + CustomMap(void* addr, size_t length) : addr(addr), length(length) + { + } + + ~CustomMap() + { + munmap(addr, length); + } + + void* operator()() const + { + return addr; + } +}; + /** @class Signature * @brief Contains signature verification functions. * @details The software image class that contains the signature @@ -95,7 +184,22 @@ class Signature bool verifyFile(const fs::path& file, const fs::path& signature, const fs::path& publicKey, const std::string& hashFunc); - /** @brief Directory where software images are placed */ + /** + * @brief Create RSA object from the public key + * @param[in] - publickey + * @param[out] - RSA Object. + */ + inline RSA* createPublicRSA(const fs::path& publicKey); + + /** + * @brief Memory map the file + * @param[in] - file path + * @param[in] - file size + * @param[out] - Custom Mmap address + */ + CustomMap mapFile(const fs::path& path, size_t size); + + /** @brief Directory where software images are placed*/ fs::path imageDirPath; /** @brief Path of public key and hash function files */ |