summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJayanth Othayoth <ojayanth@in.ibm.com>2018-02-21 05:27:47 -0600
committerJayanth Othayoth <ojayanth@in.ibm.com>2018-03-13 06:08:20 -0500
commit2ab9b1098efa8280f0cea165d1b6856e1ce05170 (patch)
tree4f080b7954cb47269bcf4f2b9da4009a12ae1e30
parent9d7cd834ecfd2a8e868de398c8122fd31e0b7961 (diff)
downloadphosphor-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-xconfigure.ac16
-rw-r--r--image_verify.cpp170
-rw-r--r--image_verify.hpp69
-rw-r--r--item_updater.cpp5
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)
{
OpenPOWER on IntegriCloud