image_verify: Support other images

The code was verifying BMC images only, make it support other images
e.g. BIOS tarball.

The change moves the verifySignature() call before checking the purpose,
so that every image is to be verified.

The `Signature::verify()` is updated to support:
* If the BMC images exists in the tarball, verify all of them;
* If one of the optional images exists in the taball, verify it;
* Return true when either BMC or the optional images are verfied.

The `optional-images` config option removes the "choices", so that a
bbappend could set its own optional images, e.g. `bios.bin`, `fpga.bin`,
etc.

Be noted that the code in verifyFullImage() uses hard-coded images when
WANT_SIGNATURE_FULL_VERIFY is defined, which is not generic.
So if WANT_SIGNATURE_FULL_VERIFY is defined, the verify will fail for
BIOS tarball.

Tested: Enable field mode and verify the BIOS code update fails on
        invalid or missing signatures, and succeeds on valid signatures.

Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: Id5e1d2eb2c3daec91f24819ec78fa864dc92f0b1
diff --git a/activation.cpp b/activation.cpp
index c82e297..f270504 100644
--- a/activation.cpp
+++ b/activation.cpp
@@ -88,6 +88,19 @@
 
     if (value == softwareServer::Activation::Activations::Activating)
     {
+#ifdef WANT_SIGNATURE_VERIFY
+        fs::path uploadDir(IMG_UPLOAD_DIR);
+        if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
+        {
+            onVerifyFailed();
+            // Stop the activation process, if fieldMode is enabled.
+            if (parent.control::FieldMode::fieldModeEnabled())
+            {
+                return softwareServer::Activation::activation(
+                    softwareServer::Activation::Activations::Failed);
+            }
+        }
+#endif
 
 #ifdef HOST_BIOS_UPGRADE
         auto purpose = parent.versions.find(versionId)->second->purpose();
@@ -130,20 +143,6 @@
                 softwareServer::Activation::Activations::Failed);
         }
 
-#ifdef WANT_SIGNATURE_VERIFY
-        fs::path uploadDir(IMG_UPLOAD_DIR);
-        if (!verifySignature(uploadDir / versionId, SIGNED_IMAGE_CONF_PATH))
-        {
-            onVerifyFailed();
-            // Stop the activation process, if fieldMode is enabled.
-            if (parent.control::FieldMode::fieldModeEnabled())
-            {
-                return softwareServer::Activation::activation(
-                    softwareServer::Activation::Activations::Failed);
-            }
-        }
-#endif
-
         if (!activationProgress)
         {
             activationProgress =
diff --git a/image_verify.cpp b/image_verify.cpp
index fc0e38f..4d42b49 100644
--- a/image_verify.cpp
+++ b/image_verify.cpp
@@ -15,6 +15,7 @@
 #include <phosphor-logging/log.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+#include <cassert>
 #include <fstream>
 #include <set>
 
@@ -134,6 +135,7 @@
             return false;
         }
 
+        bool bmcFilesFound = false;
         // image specific publickey file name.
         fs::path publicKeyFile(imageDirPath / PUBLICKEY_FILE_NAME);
 
@@ -141,15 +143,21 @@
         // First check and Validate for the fullimage, then check and Validate
         // for images with partitions
         std::vector<std::string> imageUpdateList = {bmcFullImages};
-        valid =
-            checkAndVerifyImage(imageDirPath, publicKeyFile, imageUpdateList);
+        valid = checkAndVerifyImage(imageDirPath, publicKeyFile,
+                                    imageUpdateList, bmcFilesFound);
+        if (bmcFilesFound && !valid)
+        {
+            return false;
+        }
+
         if (!valid)
         {
+            // Validate bmcImages
             imageUpdateList.clear();
             imageUpdateList.assign(bmcImages.begin(), bmcImages.end());
             valid = checkAndVerifyImage(imageDirPath, publicKeyFile,
-                                        imageUpdateList);
-            if (!valid)
+                                        imageUpdateList, bmcFilesFound);
+            if (bmcFilesFound && !valid)
             {
                 return false;
             }
@@ -157,6 +165,8 @@
 
         // Validate the optional image files.
         auto optionalImages = getOptionalImages();
+        bool optionalFilesFound = false;
+        bool optionalImagesValid = false;
         for (const auto& optionalImage : optionalImages)
         {
             // Build Image File name
@@ -165,13 +175,15 @@
 
             if (fs::exists(file))
             {
+                optionalFilesFound = true;
                 // Build Signature File name
                 fs::path sigFile(file);
                 sigFile += SIGNATURE_FILE_EXT;
 
                 // Verify the signature.
-                valid = verifyFile(file, sigFile, publicKeyFile, hashType);
-                if (valid == false)
+                optionalImagesValid =
+                    verifyFile(file, sigFile, publicKeyFile, hashType);
+                if (!optionalImagesValid)
                 {
                     log<level::ERR>("Image file Signature Validation failed",
                                     entry("IMAGE=%s", optionalImage.c_str()));
@@ -186,8 +198,16 @@
             return false;
         }
 
-        log<level::DEBUG>("Successfully completed Signature vaildation.");
+        if (!bmcFilesFound && !optionalFilesFound)
+        {
+            log<level::ERR>("Unable to find files to verify");
+            return false;
+        }
 
+        // Either BMC images or optional images shall be valid
+        assert(valid || optionalImagesValid);
+
+        log<level::DEBUG>("Successfully completed Signature vaildation.");
         return true;
     }
     catch (const InternalFailure& e)
@@ -377,10 +397,12 @@
 
 bool Signature::checkAndVerifyImage(const std::string& filePath,
                                     const std::string& publicKeyPath,
-                                    const std::vector<std::string>& imageList)
+                                    const std::vector<std::string>& imageList,
+                                    bool& fileFound)
 {
     bool valid = true;
 
+    fileFound = false;
     for (auto& bmcImage : imageList)
     {
         fs::path file(filePath);
@@ -391,6 +413,7 @@
             valid = false;
             break;
         }
+        fileFound = true;
 
         fs::path sigFile(file);
         sigFile += SIGNATURE_FILE_EXT;
diff --git a/image_verify.hpp b/image_verify.hpp
index a995e5a..5426c6d 100644
--- a/image_verify.hpp
+++ b/image_verify.hpp
@@ -223,13 +223,15 @@
      * @param[in] filePath - BMC tarball file path
      * @param[in] publicKeyPath - publicKey file Path
      * @param[in] imageList - Image filenames included in the BMC tarball
-     * @param[out] result - Boolean
-     *                      true if all image files are found in BMC tarball and
+     * @param[out] fileFound - Indicate if the file to verify is found or not
+     *
+     * @return true if all image files are found in BMC tarball and
      * Verify Sucess false if one of image files is missing
      */
     bool checkAndVerifyImage(const std::string& filePath,
                              const std::string& publicKeyPath,
-                             const std::vector<std::string>& imageList);
+                             const std::vector<std::string>& imageList,
+                             bool& fileFound);
 };
 
 } // namespace image
diff --git a/meson_options.txt b/meson_options.txt
index 0877798..4def7f9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -58,7 +58,6 @@
 
 option(
     'optional-images', type: 'array',
-    choices: ['image-hostfw'],
     value: [],
     description: 'A list of additional image files in the BMC tarball.',
 )