diff options
author | Jayanth Othayoth <ojayanth@in.ibm.com> | 2018-02-21 05:27:47 -0600 |
---|---|---|
committer | Jayanth Othayoth <ojayanth@in.ibm.com> | 2018-03-13 06:08:20 -0500 |
commit | 2ab9b1098efa8280f0cea165d1b6856e1ce05170 (patch) | |
tree | 4f080b7954cb47269bcf4f2b9da4009a12ae1e30 | |
parent | 9d7cd834ecfd2a8e868de398c8122fd31e0b7961 (diff) | |
download | phosphor-bmc-code-mgmt-2ab9b1098efa8280f0cea165d1b6856e1ce05170.tar.gz phosphor-bmc-code-mgmt-2ab9b1098efa8280f0cea165d1b6856e1ce05170.zip |
Add support for signature verification routines
Enabled high level logic flow for the signed image
signature validation routines.
Includes reading hash type, key type from Manifest file.
Change-Id: I9b0213042bb15882f351e7937fd17fb0a3e9fb33
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
-rwxr-xr-x | configure.ac | 16 | ||||
-rw-r--r-- | image_verify.cpp | 170 | ||||
-rw-r--r-- | image_verify.hpp | 69 | ||||
-rw-r--r-- | item_updater.cpp | 5 |
4 files changed, 252 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac index d89cee5..6caf4b9 100755 --- a/configure.ac +++ b/configure.ac @@ -108,6 +108,22 @@ AC_ARG_VAR(MANIFEST_FILE_NAME, [The name of the MANIFEST file]) AS_IF([test "x$MANIFEST_FILE_NAME" == "x"], [MANIFEST_FILE_NAME="MANIFEST"]) AC_DEFINE_UNQUOTED([MANIFEST_FILE_NAME], ["$MANIFEST_FILE_NAME"], [The name of the MANIFEST file]) +AC_ARG_VAR(PUBLICKEY_FILE_NAME, [The name of the public key file]) +AS_IF([test "x$PUBLICKEY_FILE_NAME" == "x"], [PUBLICKEY_FILE_NAME="publickey"]) +AC_DEFINE_UNQUOTED([PUBLICKEY_FILE_NAME], ["$PUBLICKEY_FILE_NAME"], [The name of the public key file]) + +AC_ARG_VAR(HASH_FILE_NAME, [Hash file name]) +AS_IF([test "x$HASH_FILE_NAME" == "x"], [HASH_FILE_NAME="hashfunc"]) +AC_DEFINE_UNQUOTED([HASH_FILE_NAME], ["$HASH_FILE_NAME"], [The name of the hash file]) + +AC_ARG_VAR(SIGNED_IMAGE_CONF_PATH, [Path of public key and hash function files]) +AS_IF([test "x$SIGNED_IMAGE_CONF_PATH" == "x"], [SIGNED_IMAGE_CONF_PATH="/etc/activationdata/"]) +AC_DEFINE_UNQUOTED([SIGNED_IMAGE_CONF_PATH], ["$SIGNED_IMAGE_CONF_PATH"], [Path of public key and hash function files]) + +AC_ARG_VAR(SIGNATURE_FILE_EXT, [The extension of the Signature file]) +AS_IF([test "x$SIGNATURE_FILE_EXT" == "x"], [SIGNATURE_FILE_EXT=".sig"]) +AC_DEFINE_UNQUOTED([SIGNATURE_FILE_EXT], ["$SIGNATURE_FILE_EXT"], [The extension of the Signature file]) + AC_ARG_VAR(ACTIVE_BMC_MAX_ALLOWED, [The maximum allowed active BMC versions]) AS_IF([test "x$ACTIVE_BMC_MAX_ALLOWED" == "x"], [ACTIVE_BMC_MAX_ALLOWED=2]) AC_DEFINE_UNQUOTED([ACTIVE_BMC_MAX_ALLOWED], [$ACTIVE_BMC_MAX_ALLOWED], diff --git a/image_verify.cpp b/image_verify.cpp index be5536c..5b50f39 100644 --- a/image_verify.cpp +++ b/image_verify.cpp @@ -1,4 +1,13 @@ +#include <set> + #include "image_verify.hpp" +#include "config.h" +#include "version.hpp" + +#include <phosphor-logging/log.hpp> +#include <phosphor-logging/elog.hpp> +#include <phosphor-logging/elog-errors.hpp> +#include <xyz/openbmc_project/Common/error.hpp> namespace phosphor { @@ -7,8 +16,169 @@ namespace software namespace image { +using namespace phosphor::logging; +using namespace phosphor::software::manager; +using InternalFailure = + sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; + +constexpr auto keyTypeTag = "KeyType"; +constexpr auto hashFunctionTag = "HashType"; + +Signature::Signature(const fs::path& imageDirPath, + const fs::path& signedConfPath) : + imageDirPath(imageDirPath), + signedConfPath(signedConfPath) +{ + fs::path file(imageDirPath / MANIFEST_FILE_NAME); + + keyType = Version::getValue(file, keyTypeTag); + hashType = Version::getValue(file, hashFunctionTag); +} + +AvailableKeyTypes Signature::getAvailableKeyTypesFromSystem() const +{ + AvailableKeyTypes keyTypes{}; + + // Find the path of all the files + if (!fs::is_directory(signedConfPath)) + { + log<level::ERR>("Signed configuration path not found in the system"); + elog<InternalFailure>(); + } + + // Look for all the hash and public key file names get the key value + // For example: + // /etc/activationdata/OpenBMC/publickey + // /etc/activationdata/OpenBMC/hashfunc + // /etc/activationdata/GA/publickey + // /etc/activationdata/GA/hashfunc + // Set will have OpenBMC, GA + + for (const auto& p : fs::recursive_directory_iterator(signedConfPath)) + { + if ((p.path().filename() == HASH_FILE_NAME) || + (p.path().filename() == PUBLICKEY_FILE_NAME)) + { + // extract the key types + // /etc/activationdata/OpenBMC/ -> get OpenBMC from the path + auto key = p.path().parent_path(); + keyTypes.insert(key.filename()); + } + } + + return keyTypes; +} + +inline KeyHashPathPair Signature::getKeyHashFileNames(const Key_t& key) const +{ + fs::path hashpath(signedConfPath / key / HASH_FILE_NAME); + fs::path keyPath(signedConfPath / key / PUBLICKEY_FILE_NAME); + + return std::make_pair(std::move(hashpath), std::move(keyPath)); +} + bool Signature::verify() { + try + { + // Verify the MANIFEST and publickey file using available + // public keys and hash on the system. + if (false == systemLevelVerify()) + { + log<level::ERR>("System level Signature Validation failed"); + return false; + } + + // image specfic publickey file name. + fs::path publicKeyFile(imageDirPath / PUBLICKEY_FILE_NAME); + + // Validate the BMC image files. + for (const auto& bmcImage : bmcImages) + { + // Build Image File name + fs::path file(imageDirPath); + file /= bmcImage; + + // Build Signature File name + fs::path sigFile(file); + sigFile.replace_extension(SIGNATURE_FILE_EXT); + + // Verify the signature. + auto valid = verifyFile(file, sigFile, publicKeyFile, hashType); + if (valid == false) + { + log<level::ERR>("Image file Signature Validation failed", + entry("IMAGE=%s", bmcImage.c_str())); + return false; + } + } + + log<level::DEBUG>("Sucessfully completed Signature vaildation."); + + return true; + } + catch (const InternalFailure& e) + { + return false; + } + catch (const std::exception& e) + { + log<level::ERR>(e.what()); + return false; + } +} + +bool Signature::systemLevelVerify() +{ + // Get available key types from the system. + auto keyTypes = getAvailableKeyTypesFromSystem(); + if (keyTypes.empty()) + { + log<level::ERR>("Missing Signature configuration data in system"); + elog<InternalFailure>(); + } + + // Build publickey and its signature file name. + fs::path pkeyFile(imageDirPath / PUBLICKEY_FILE_NAME); + fs::path pkeyFileSig(pkeyFile); + pkeyFileSig.replace_extension(SIGNATURE_FILE_EXT); + + // Build manifest and its signature file name. + fs::path manifestFile(imageDirPath / MANIFEST_FILE_NAME); + fs::path manifestFileSig(manifestFile); + manifestFileSig.replace_extension(SIGNATURE_FILE_EXT); + + auto valid = false; + + // Verify the file signature with available key types + // public keys and hash function. + 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) + { + // Verify publickey file signature. + valid = + verifyFile(pkeyFile, pkeyFileSig, keyHashPair.second, hashFunc); + if (valid) + { + break; + } + } + } + return valid; +} + +bool Signature::verifyFile(const fs::path& file, const fs::path& sigFile, + const fs::path& publicKey, + const std::string& hashFunc) +{ return true; } diff --git a/image_verify.hpp b/image_verify.hpp index b5c4514..3e65288 100644 --- a/image_verify.hpp +++ b/image_verify.hpp @@ -1,5 +1,6 @@ #pragma once #include <experimental/filesystem> +#include <set> namespace phosphor { @@ -9,7 +10,16 @@ namespace image { namespace fs = std::experimental::filesystem; +using Key_t = std::string; +using Hash_t = std::string; +using PublicKeyPath = fs::path; +using HashFilePath = fs::path; +using KeyHashPathPair = std::pair<HashFilePath, PublicKeyPath>; +using AvailableKeyTypes = std::set<Key_t>; +// BMC flash image file name list. +const std::vector<std::string> bmcImages = {"image-kernel", "image-rofs", + "image-rwfs", "image-u-boot"}; /** @class Signature * @brief Contains signature verification functions. * @details The software image class that contains the signature @@ -25,11 +35,13 @@ class Signature Signature& operator=(Signature&&) = default; ~Signature() = default; - /** @brief Constructs Verify Class - * - * @param[in] imageDirPath - file path + /** + * @brief Constructs Signature. + * @param[in] imageDirPath - image path + * @param[in] signedConfPath - Path of public key + * hash function files */ - Signature(const fs::path& imageDirPath) : imageDirPath(imageDirPath){}; + Signature(const fs::path& imageDirPath, const fs::path& signedConfPath); /** * @brief Image signature verification function. @@ -45,8 +57,55 @@ class Signature bool verify(); private: - /** @brief Directory where software images are placed*/ + /** + * @brief Function used for system level file signature validation + * of image specfic publickey file and manifest file + * using the available public keys and hash functions + * in the system. + * Refer code-update documenation for more details. + */ + bool systemLevelVerify(); + + /** + * @brief Return all key types stored in the BMC based on the + * public key and hashfunc files stored in the BMC. + * + * @return list + */ + AvailableKeyTypes getAvailableKeyTypesFromSystem() const; + + /** + * @brief Return public key and hash function file names for the + * corresponding key type + * + * @param[in] key - key type + * @return Pair of hash and public key file names + */ + inline KeyHashPathPair getKeyHashFileNames(const Key_t& key) const; + + /** + * @brief Verify the file signature using public key and hash function + * + * @param[in] - Image file path + * @param[in] - Signature file path + * @param[in] - Public key + * @param[in] - Hash function name + * @return true if signature verification was successful, false if not + */ + 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 */ fs::path imageDirPath; + + /** @brief Path of public key and hash function files */ + fs::path signedConfPath; + + /** @brief key type defined in mainfest file */ + Key_t keyType; + + /** @brief Hash type defined in mainfest file */ + Hash_t hashType; }; } // namespace image diff --git a/item_updater.cpp b/item_updater.cpp index 4d07ac9..df73fc5 100644 --- a/item_updater.cpp +++ b/item_updater.cpp @@ -12,6 +12,7 @@ #include <experimental/filesystem> #include "version.hpp" #include "serialize.hpp" +#include "image_verify.hpp" namespace phosphor { @@ -26,11 +27,9 @@ namespace control = sdbusplus::xyz::openbmc_project::Control::server; using namespace phosphor::logging; using namespace sdbusplus::xyz::openbmc_project::Software::Version::Error; +using namespace phosphor::software::image; namespace fs = std::experimental::filesystem; -const std::vector<std::string> bmcImages = {"image-kernel", "image-rofs", - "image-rwfs", "image-u-boot"}; - void ItemUpdater::createActivation(sdbusplus::message::message& msg) { |