boot: Harden critical path against fault attacks

Add fault attack mitigation measures to code vital for the correct
validation of images.

Change-Id: If6eb1110a8c2966faf105d07ad2e95482a80a8d9
Signed-off-by: Raef Coles <raef.coles@arm.com>
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index d9dd352..a8b6b47 100644
--- a/boot/bootutil/src/bootutil_misc.c
+++ b/boot/bootutil/src/bootutil_misc.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2017-2019 Linaro LTD
  * Copyright (c) 2016-2019 JUUL Labs
- * Copyright (c) 2019 Arm Limited
+ * Copyright (c) 2019-2020 Arm Limited
  *
  * Original license:
  *
@@ -36,6 +36,7 @@
 #include "bootutil/bootutil.h"
 #include "bootutil_priv.h"
 #include "bootutil/bootutil_log.h"
+#include "bootutil/fault_injection_hardening.h"
 #ifdef MCUBOOT_ENC_IMAGES
 #include "bootutil/enc_key.h"
 #endif
@@ -106,6 +107,49 @@
 #define BOOT_SWAP_TABLES_COUNT \
     (sizeof boot_swap_tables / sizeof boot_swap_tables[0])
 
+/**
+ * @brief Determine if the data at two memory addresses is equal
+ *
+ * @param s1    The first  memory region to compare.
+ * @param s2    The second memory region to compare.
+ * @param n     The amount of bytes to compare.
+ *
+ * @note        This function does not comply with the specification of memcmp,
+ *              so should not be considered a drop-in replacement. It has no
+ *              constant time execution. The point is to make sure that all the
+ *              bytes are compared and detect if loop was abused and some cycles
+ *              was skipped due to fault injection.
+ *
+ * @return      FIH_SUCCESS if memory regions are equal, otherwise FIH_FAILURE
+ */
+#ifdef MCUBOOT_FIH_PROFILE_OFF
+inline
+fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
+{
+    return memcmp(s1, s2, n);
+}
+#else
+fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n)
+{
+    size_t i;
+    uint8_t *s1_p = (uint8_t*) s1;
+    uint8_t *s2_p = (uint8_t*) s2;
+    fih_int ret = FIH_FAILURE;
+
+    for (i = 0; i < n; i++) {
+        if (s1_p[i] != s2_p[i]) {
+            goto out;
+        }
+    }
+    if (i == n) {
+        ret = FIH_SUCCESS;
+    }
+
+out:
+    FIH_RET(ret);
+}
+#endif
+
 static int
 boot_magic_decode(const uint32_t *magic)
 {
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index 180cd5c..be9de71 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -36,6 +36,7 @@
 
 #include "bootutil/bootutil.h"
 #include "bootutil/image.h"
+#include "bootutil/fault_injection_hardening.h"
 #include "mcuboot_config/mcuboot_config.h"
 
 #ifdef MCUBOOT_ENC_IMAGES
@@ -284,8 +285,10 @@
 #endif
 };
 
-int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
-                        size_t slen, uint8_t key_id);
+fih_int bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig,
+                            size_t slen, uint8_t key_id);
+
+fih_int boot_fih_memequal(const void *s1, const void *s2, size_t n);
 
 int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val);
 uint32_t boot_status_sz(uint32_t min_write_sz);
diff --git a/boot/bootutil/src/fault_injection_hardening.c b/boot/bootutil/src/fault_injection_hardening.c
new file mode 100644
index 0000000..5ee109c
--- /dev/null
+++ b/boot/bootutil/src/fault_injection_hardening.c
@@ -0,0 +1,78 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Arm Limited
+ */
+
+#include "bootutil/fault_injection_hardening.h"
+
+#ifdef FIH_ENABLE_DOUBLE_VARS
+/* Variable that could be (but isn't) changed at runtime to force the compiler
+ * not to optimize the double check. Value doesn't matter.
+ */
+volatile int _fih_mask = _FIH_MASK_VALUE;
+fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE, _FIH_MASK_VALUE ^ FIH_POSITIVE_VALUE};
+fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE, _FIH_MASK_VALUE ^ FIH_NEGATIVE_VALUE};
+#else
+fih_int FIH_SUCCESS = {FIH_POSITIVE_VALUE};
+fih_int FIH_FAILURE = {FIH_NEGATIVE_VALUE};
+#endif /* FIH_ENABLE_DOUBLE_VARS */
+
+#ifdef FIH_ENABLE_CFI
+
+#ifdef FIH_ENABLE_DOUBLE_VARS
+fih_int _fih_cfi_ctr = {0, 0 ^ _FIH_MASK_VALUE};
+#else
+fih_int _fih_cfi_ctr = {0};
+#endif /* FIH_ENABLE_DOUBLE_VARS */
+
+/* Increment the CFI counter by one, and return the value before the increment.
+ */
+fih_int fih_cfi_get_and_increment(void)
+{
+    fih_int saved = _fih_cfi_ctr;
+    _fih_cfi_ctr = fih_int_encode(fih_int_decode(saved) + 1);
+    return saved;
+}
+
+/* Validate that the saved precall value is the same as the value of the global
+ * counter. For this to be the case, a fih_ret must have been called between
+ * these functions being executed. If the values aren't the same then panic.
+ */
+void fih_cfi_validate(fih_int saved)
+{
+    if (fih_int_decode(saved) != fih_int_decode(_fih_cfi_ctr)) {
+        FIH_PANIC;
+    }
+}
+
+/* Decrement the global CFI counter by one, so that it has the same value as
+ * before the cfi_precall
+ */
+void fih_cfi_decrement(void)
+{
+    _fih_cfi_ctr = fih_int_encode(fih_int_decode(_fih_cfi_ctr) - 1);
+}
+
+#endif /* FIH_ENABLE_CFI */
+
+#ifdef FIH_ENABLE_GLOBAL_FAIL
+/* Global failure loop for bootloader code. Uses attribute used to prevent
+ * compiler removing due to non-standard calling procedure. Multiple loop jumps
+ * used to make unlooping difficult.
+ */
+__attribute__((used))
+__attribute__((noinline))
+void fih_panic_loop(void)
+{
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+    __asm volatile ("b fih_panic_loop");
+}
+#endif /* FIH_ENABLE_GLOBAL_FAIL */
diff --git a/boot/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c b/boot/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c
new file mode 100644
index 0000000..e6a9766
--- /dev/null
+++ b/boot/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c
@@ -0,0 +1,51 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2020 Arm Limited
+ */
+
+#include "bootutil/fault_injection_hardening.h"
+
+#ifdef FIH_ENABLE_DELAY
+
+#include "bootutil/fault_injection_hardening_delay_rng.h"
+#include "mcuboot-mbedtls-cfg.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/entropy.h"
+
+#include "bootutil/bootutil_log.h"
+
+/* Mbedtls implementation of the delay RNG. Can be replaced by any other RNG
+ * implementation that is backed by an entropy source by altering these
+ * functions. This is not provided as a header API and a C file implementation
+ * due to issues with inlining.
+ */
+
+#ifdef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+#error "FIH_ENABLE_DELAY requires an entropy source"
+#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */
+
+mbedtls_entropy_context fih_entropy_ctx;
+mbedtls_ctr_drbg_context fih_drbg_ctx;
+
+int fih_delay_init(void)
+{
+    mbedtls_entropy_init(&fih_entropy_ctx);
+    mbedtls_ctr_drbg_init(&fih_drbg_ctx);
+    mbedtls_ctr_drbg_seed(&fih_drbg_ctx , mbedtls_entropy_func,
+                          &fih_entropy_ctx, NULL, 0);
+
+    return 1;
+}
+
+unsigned char fih_delay_random_uchar(void)
+{
+    unsigned char delay;
+
+    mbedtls_ctr_drbg_random(&fih_drbg_ctx,(unsigned char*) &delay,
+                            sizeof(delay));
+
+    return delay;
+}
+
+#endif /* FIH_ENABLE_DELAY */
diff --git a/boot/bootutil/src/image_rsa.c b/boot/bootutil/src/image_rsa.c
index a94de5c..1a1727e 100644
--- a/boot/bootutil/src/image_rsa.c
+++ b/boot/bootutil/src/image_rsa.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2017-2018 Linaro LTD
  * Copyright (c) 2017-2019 JUUL Labs
+ * Copyright (c) 2020 Arm Limited
  *
  * Original license:
  *
@@ -37,6 +38,7 @@
 #include "mbedtls/version.h"
 
 #include "bootutil_priv.h"
+#include "bootutil/fault_injection_hardening.h"
 
 /*
  * Constants for this particular constrained implementation of
@@ -157,7 +159,7 @@
  * v2.2, section 9.1.2, with many parameters required to have fixed
  * values.
  */
-static int
+static fih_int
 bootutil_cmp_rsasig(mbedtls_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
   uint8_t *sig)
 {
@@ -166,17 +168,22 @@
     uint8_t db_mask[PSS_MASK_LEN];
     uint8_t h2[PSS_HLEN];
     int i;
+    int rc = 0;
+    fih_int fih_rc = FIH_FAILURE;
 
     if (ctx->len != PSS_EMLEN || PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
-        return -1;
+        rc = -1;
+        goto out;
     }
 
     if (hlen != PSS_HLEN) {
-        return -1;
+        rc = -1;
+        goto out;
     }
 
     if (mbedtls_rsa_public(ctx, sig, em)) {
-        return -1;
+        rc = -1;
+        goto out;
     }
 
     /*
@@ -204,7 +211,8 @@
      * 0xbc, output inconsistent and stop.
      */
     if (em[PSS_EMLEN - 1] != 0xbc) {
-        return -1;
+        rc = -1;
+        goto out;
     }
 
     /* Step 5.  Let maskedDB be the leftmost emLen - hLen - 1 octets
@@ -244,12 +252,14 @@
      * hexadecimal value 0x01, output "inconsistent" and stop. */
     for (i = 0; i < PSS_MASK_ZERO_COUNT; i++) {
         if (db_mask[i] != 0) {
-            return -1;
+            rc = -1;
+            goto out;
         }
     }
 
     if (db_mask[PSS_MASK_ONE_POS] != 1) {
-        return -1;
+        rc = -1;
+        goto out;
     }
 
     /* Step 11. Let salt be the last sLen octets of DB */
@@ -266,19 +276,23 @@
 
     /* Step 14.  If H = H', output "consistent".  Otherwise, output
      * "inconsistent". */
-    if (memcmp(h2, &em[PSS_HASH_OFFSET], PSS_HLEN) != 0) {
-        return -1;
+    FIH_CALL(boot_fih_memequal, fih_rc, h2, &em[PSS_HASH_OFFSET], PSS_HLEN);
+
+out:
+    if (rc) {
+        fih_rc = fih_int_encode(rc);
     }
 
-    return 0;
+    FIH_RET(fih_rc);
 }
 
-int
+fih_int
 bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
   uint8_t key_id)
 {
     mbedtls_rsa_context ctx;
     int rc;
+    fih_int fih_rc = FIH_FAILURE;
     uint8_t *cp;
     uint8_t *end;
 
@@ -290,11 +304,13 @@
     rc = bootutil_parse_rsakey(&ctx, &cp, end);
     if (rc || slen != ctx.len) {
         mbedtls_rsa_free(&ctx);
-        return rc;
+        goto out;
     }
-    rc = bootutil_cmp_rsasig(&ctx, hash, hlen, sig);
+    FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig);
+
+out:
     mbedtls_rsa_free(&ctx);
 
-    return rc;
+    FIH_RET(fih_rc);
 }
 #endif /* MCUBOOT_SIGN_RSA */
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 8865bb4..f066add 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -36,6 +36,7 @@
 #include "bootutil/crypto/sha256.h"
 #include "bootutil/sign_key.h"
 #include "bootutil/security_cnt.h"
+#include "bootutil/fault_injection_hardening.h"
 
 #include "mcuboot_config/mcuboot_config.h"
 
@@ -232,6 +233,7 @@
     uint8_t key_hash[32];
     size_t key_hash_size = sizeof(key_hash);
     int rc;
+    fih_int fih_rc;
 
     bootutil_sha256_init(&sha256_ctx);
     bootutil_sha256_update(&sha256_ctx, key, key_len);
@@ -243,11 +245,19 @@
         return rc;
     }
 
-    if (!memcmp(hash, key_hash, key_hash_size)) {
+    /* Adding hardening to avoid this potential attack:
+     *  - Image is signed with an arbitrary key and the corresponding public
+     *    key is added as a TLV field.
+     * - During public key validation (comparing against key-hash read from
+     *   HW) a fault is injected to accept the public key as valid one.
+     */
+    FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size);
+    if (fih_eq(fih_rc, FIH_SUCCESS)) {
         bootutil_keys[0].key = key;
         pub_key_len = key_len;
         return 0;
     }
+
     return -1;
 }
 #endif /* !MCUBOOT_HW_KEY */
@@ -319,7 +329,7 @@
  * Verify the integrity of the image.
  * Return non-zero if image could not be validated/does not validate.
  */
-int
+fih_int
 bootutil_img_validate(struct enc_key_data *enc_state, int image_index,
                       struct image_header *hdr, const struct flash_area *fap,
                       uint8_t *tmp_buf, uint32_t tmp_buf_sz, uint8_t *seed,
@@ -330,7 +340,7 @@
     uint16_t type;
     int sha256_valid = 0;
 #ifdef EXPECTED_SIG_TLV
-    int valid_signature = 0;
+    fih_int valid_signature = FIH_FAILURE;
     int key_id = -1;
 #ifdef MCUBOOT_HW_KEY
     /* Few extra bytes for encoding and for public exponent. */
@@ -340,17 +350,18 @@
     struct image_tlv_iter it;
     uint8_t buf[SIG_BUF_SIZE];
     uint8_t hash[32];
-    int rc;
+    int rc = 0;
+    fih_int fih_rc = FIH_FAILURE;
 #ifdef MCUBOOT_HW_ROLLBACK_PROT
-    uint32_t security_cnt = UINT32_MAX;
+    fih_int security_cnt = fih_int_encode(INT_MAX);
     uint32_t img_security_cnt = 0;
-    int32_t security_counter_valid = 0;
+    fih_int security_counter_valid = FIH_FAILURE;
 #endif
 
     rc = bootutil_img_hash(enc_state, image_index, hdr, fap, tmp_buf,
             tmp_buf_sz, hash, seed, seed_len);
     if (rc) {
-        return rc;
+        goto out;
     }
 
     if (out_hash) {
@@ -359,7 +370,7 @@
 
     rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false);
     if (rc) {
-        return rc;
+        goto out;
     }
 
     /*
@@ -369,7 +380,7 @@
     while (true) {
         rc = bootutil_tlv_iter_next(&it, &off, &len, &type);
         if (rc < 0) {
-            return -1;
+            goto out;
         } else if (rc > 0) {
             break;
         }
@@ -380,14 +391,17 @@
              * present.
              */
             if (len != sizeof(hash)) {
-                return -1;
+                rc = -1;
+                goto out;
             }
             rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash));
             if (rc) {
-                return rc;
+                goto out;
             }
-            if (memcmp(hash, buf, sizeof(hash))) {
-                return -1;
+
+            FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash));
+            if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                goto out;
             }
 
             sha256_valid = 1;
@@ -398,11 +412,12 @@
              * Determine which key we should be checking.
              */
             if (len > 32) {
-                return -1;
+                rc = -1;
+                goto out;
             }
             rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
             if (rc) {
-                return rc;
+                goto out;
             }
             key_id = bootutil_find_key(buf, len);
             /*
@@ -415,11 +430,12 @@
              * Determine which key we should be checking.
              */
             if (len > sizeof(key_buf)) {
-                return -1;
+                rc = -1;
+                goto out;
             }
             rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len);
             if (rc) {
-                return rc;
+                goto out;
             }
             key_id = bootutil_find_key(image_index, key_buf, len);
             /*
@@ -434,16 +450,15 @@
                 continue;
             }
             if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) {
-                return -1;
+                rc = -1;
+                goto out;
             }
             rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len);
             if (rc) {
-                return -1;
+                goto out;
             }
-            rc = bootutil_verify_sig(hash, sizeof(hash), buf, len, key_id);
-            if (rc == 0) {
-                valid_signature = 1;
-            }
+            FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash),
+                                                           buf, len, key_id);
             key_id = -1;
 #endif /* EXPECTED_SIG_TLV */
 #ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -454,44 +469,55 @@
              */
             if (len != sizeof(img_security_cnt)) {
                 /* Security counter is not valid. */
-                return -1;
+                rc = -1;
+                goto out;
             }
 
             rc = LOAD_IMAGE_DATA(hdr, fap, off, &img_security_cnt, len);
             if (rc) {
-                return rc;
+                goto out;
             }
 
-            rc = boot_nv_security_counter_get(image_index, &security_cnt);
-            if (rc) {
-                return rc;
+            FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index,
+                                                           &security_cnt);
+            if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                goto out;
             }
 
             /* Compare the new image's security counter value against the
              * stored security counter value.
              */
-            if (img_security_cnt < security_cnt) {
-                /* The image's security counter is not accepted. */
-                return -1;
+            fih_rc = fih_int_encode_zero_equality(img_security_cnt <
+                                   fih_int_decode(security_cnt));
+            if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                goto out;
             }
 
             /* The image's security counter has been successfully verified. */
-            security_counter_valid = 1;
+            security_counter_valid = fih_rc;
 #endif /* MCUBOOT_HW_ROLLBACK_PROT */
         }
     }
 
-    if (!sha256_valid) {
-        return -1;
+    rc = !sha256_valid;
+    if (rc) {
+        goto out;
+    }
 #ifdef EXPECTED_SIG_TLV
-    } else if (!valid_signature) {
-        return -1;
+    fih_rc = fih_int_encode_zero_equality(fih_not_eq(valid_signature,
+                                                     FIH_SUCCESS));
 #endif
 #ifdef MCUBOOT_HW_ROLLBACK_PROT
-    } else if (!security_counter_valid) {
-        return -1;
+    if (fih_not_eq(security_counter_valid, FIH_SUCCESS)) {
+        rc = -1;
+        goto out;
+    }
 #endif
+
+out:
+    if (rc) {
+        fih_rc = fih_int_encode(rc);
     }
 
-    return 0;
+    FIH_RET(fih_rc);
 }
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 1c1d3a6..a08ed7e 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -43,6 +43,7 @@
 #include "bootutil/bootutil_log.h"
 #include "bootutil/security_cnt.h"
 #include "bootutil/boot_record.h"
+#include "bootutil/fault_injection_hardening.h"
 
 #ifdef MCUBOOT_ENC_IMAGES
 #include "bootutil/enc_key.h"
@@ -385,13 +386,14 @@
 /*
  * Validate image hash/signature and optionally the security counter in a slot.
  */
-static int
+static fih_int
 boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
                  const struct flash_area *fap, struct boot_status *bs)
 {
     TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
     uint8_t image_index;
     int rc;
+    fih_int fih_rc = FIH_FAILURE;
 
 #if (BOOT_IMAGE_NUMBER == 1)
     (void)state;
@@ -406,24 +408,22 @@
     if (MUST_DECRYPT(fap, image_index, hdr)) {
         rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
         if (rc < 0) {
-            return BOOT_EBADIMAGE;
+            FIH_RET(fih_rc);
         }
         if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
-            return BOOT_EBADIMAGE;
+            FIH_RET(fih_rc);
         }
     }
 #endif
 
-    if (bootutil_img_validate(BOOT_CURR_ENC(state), image_index, hdr, fap, tmpbuf,
-                              BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
-        return BOOT_EBADIMAGE;
-    }
+    FIH_CALL(bootutil_img_validate, fih_rc, BOOT_CURR_ENC(state), image_index,
+             hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL);
 
-    return 0;
+    FIH_RET(fih_rc);
 }
 
 #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
-static int
+static fih_int
 split_image_check(struct image_header *app_hdr,
                   const struct flash_area *app_fap,
                   struct image_header *loader_hdr,
@@ -431,25 +431,26 @@
 {
     static void *tmpbuf;
     uint8_t loader_hash[32];
+    fih_int fih_rc = FIH_FAILURE;
 
     if (!tmpbuf) {
         tmpbuf = malloc(BOOT_TMPBUF_SZ);
         if (!tmpbuf) {
-            return BOOT_ENOMEM;
+            goto out;
         }
     }
 
-    if (bootutil_img_validate(NULL, 0, loader_hdr, loader_fap, tmpbuf,
-                              BOOT_TMPBUF_SZ, NULL, 0, loader_hash)) {
-        return BOOT_EBADIMAGE;
+    FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, loader_hdr, loader_fap,
+             tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, loader_hash);
+    if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+        FIH_RET(fih_rc);
     }
 
-    if (bootutil_img_validate(NULL, 0, app_hdr, app_fap, tmpbuf,
-                              BOOT_TMPBUF_SZ, loader_hash, 32, NULL)) {
-        return BOOT_EBADIMAGE;
-    }
+    FIH_CALL(bootutil_img_validate, fih_rc, NULL, 0, app_hdr, app_fap,
+             tmpbuf, BOOT_TMPBUF_SZ, loader_hash, 32, NULL);
 
-    return 0;
+out:
+    FIH_RET(fih_rc);
 }
 #endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
 
@@ -569,23 +570,24 @@
  * Check that there is a valid image in a slot
  *
  * @returns
- *         0 if image was successfully validated
- *         1 if no bootloable image was found
- *         -1 on any errors
+ *         FIH_SUCCESS                      if image was successfully validated
+ *         1 (or its fih_int encoded form)  if no bootloable image was found
+ *         FIH_FAILURE                      on any errors
  */
-static int
+static fih_int
 boot_validate_slot(struct boot_loader_state *state, int slot,
                    struct boot_status *bs)
 {
     const struct flash_area *fap;
     struct image_header *hdr;
     int area_id;
+    fih_int fih_rc = FIH_FAILURE;
     int rc;
 
     area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
-        return -1;
+        FIH_RET(fih_rc);
     }
 
     hdr = boot_img_hdr(state, slot);
@@ -609,7 +611,7 @@
 #endif
 
         /* No bootable image in slot; continue booting from the primary slot. */
-        rc = 1;
+        fih_rc = fih_int_encode(1);
         goto out;
     }
 
@@ -625,13 +627,14 @@
             /* Image in the secondary slot does not satisfy version requirement.
              * Erase the image and continue booting from the primary slot.
              */
-            rc = 1;
+            fih_rc = fih_int_encode(1);
             goto out;
         }
     }
 #endif
 
-    if (!boot_is_header_valid(hdr, fap) || boot_image_check(state, hdr, fap, bs)) {
+    FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
+    if (!boot_is_header_valid(hdr, fap) || fih_not_eq(fih_rc, FIH_SUCCESS)) {
         if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
             flash_area_erase(fap, 0, fap->fa_size);
             /* Image is invalid, erase it to prevent further unnecessary
@@ -642,16 +645,14 @@
         BOOT_LOG_ERR("Image in the %s slot is not valid!",
                      (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
 #endif
-        rc = 1;
+        fih_rc = fih_int_encode(1);
         goto out;
     }
 
-    /* Image in the secondary slot is valid. */
-    rc = 0;
-
 out:
     flash_area_close(fap);
-    return rc;
+
+    FIH_RET(fih_rc);
 }
 
 #ifdef MCUBOOT_HW_ROLLBACK_PROT
@@ -713,18 +714,20 @@
                          struct boot_status *bs)
 {
     int swap_type;
-    int rc;
+    fih_int fih_rc = FIH_FAILURE;
 
     swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state));
     if (BOOT_IS_UPGRADE(swap_type)) {
         /* Boot loader wants to switch to the secondary slot.
          * Ensure image is valid.
          */
-        rc = boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs);
-        if (rc == 1) {
-            swap_type = BOOT_SWAP_TYPE_NONE;
-        } else if (rc != 0) {
-            swap_type = BOOT_SWAP_TYPE_FAIL;
+        FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SECONDARY_SLOT, bs);
+        if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+            if (fih_eq(fih_rc, fih_int_encode(1))) {
+                swap_type = BOOT_SWAP_TYPE_NONE;
+            } else {
+                swap_type = BOOT_SWAP_TYPE_FAIL;
+            }
         }
     }
 
@@ -1298,8 +1301,10 @@
      * primary slot (the validity of the image in the secondary slot had
      * already been checked).
      */
-    if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
-        boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
+    fih_int fih_rc = FIH_FAILURE;
+    rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
+    FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
+    if (rc == 0 || fih_not_eq(fih_rc, FIH_SUCCESS)) {
         rc = boot_copy_image(state, bs);
     } else {
         rc = boot_swap_image(state, bs);
@@ -1481,6 +1486,7 @@
                               struct boot_status *bs)
 {
     int rc;
+    fih_int fih_rc = FIH_FAILURE;
 
     /* Determine the sector layout of the image slots and scratch area. */
     rc = boot_read_sectors(state);
@@ -1569,10 +1575,14 @@
             /* There was no partial swap, determine swap type. */
             if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
                 BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
-            } else if (boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) != 0) {
-                BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
             } else {
-                BOOT_SWAP_TYPE(state) = bs->swap_type;
+                FIH_CALL(boot_validate_slot, fih_rc,
+                         state, BOOT_SECONDARY_SLOT, bs);
+                if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+                    BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
+                } else {
+                    BOOT_SWAP_TYPE(state) = bs->swap_type;
+                }
             }
 
 #if (BOOT_IMAGE_NUMBER > 1)
@@ -1587,11 +1597,17 @@
                  * magic, so also run validation on the primary slot to be
                  * sure it's not OK.
                  */
-                if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
-                        boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
-                    if (boot_img_hdr(state,
-                            BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC &&
-                            boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) == 0) {
+                rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
+                FIH_CALL(boot_validate_slot, fih_rc,
+                         state, BOOT_PRIMARY_SLOT, bs);
+
+                if (rc == 0 || fih_not_eq(fih_rc, FIH_SUCCESS)) {
+
+                    rc = boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC;
+                    FIH_CALL(boot_validate_slot, fih_rc,
+                             state, BOOT_SECONDARY_SLOT, bs);
+
+                    if (rc == 0 && fih_eq(fih_rc, FIH_SUCCESS)) {
                         /* Set swap type to REVERT to overwrite the primary
                          * slot with the image contained in secondary slot
                          * and to trigger the explicit setting of the
@@ -1609,12 +1625,13 @@
     }
 }
 
-int
+fih_int
 context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
 {
     size_t slot;
     struct boot_status bs;
     int rc = -1;
+    fih_int fih_rc = FIH_FAILURE;
     int fa_id;
     int image_index;
     bool has_upgrade;
@@ -1757,7 +1774,7 @@
             assert(0);
 
             /* Loop forever... */
-            while (1) {}
+            FIH_PANIC;
         }
     }
 
@@ -1782,9 +1799,8 @@
         }
 
 #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
-        rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
-        if (rc != 0) {
-            rc = BOOT_EBADIMAGE;
+        FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
+        if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
             goto out;
         }
 #else
@@ -1832,6 +1848,7 @@
         if (rc != 0) {
             BOOT_LOG_ERR("Failed to add Image %u data to shared memory area",
                          BOOT_CURR_IMG(state));
+            goto out;
         }
 #endif /* MCUBOOT_MEASURED_BOOT */
 
@@ -1840,6 +1857,7 @@
                                    BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
         if (rc != 0) {
             BOOT_LOG_ERR("Failed to add data to shared memory area.");
+            goto out;
         }
 #endif /* MCUBOOT_DATA_SHARING */
     }
@@ -1860,6 +1878,7 @@
     rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
     rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
 
+    fih_rc = FIH_SUCCESS;
 out:
     IMAGES_ITER(BOOT_CURR_IMG(state)) {
 #if MCUBOOT_SWAP_USING_SCRATCH
@@ -1869,10 +1888,15 @@
             flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
         }
     }
-    return rc;
+
+    if (rc) {
+        fih_rc = fih_int_encode(rc);
+    }
+
+    FIH_RET(fih_rc);
 }
 
-int
+fih_int
 split_go(int loader_slot, int split_slot, void **entry)
 {
     boot_sector_t *sectors;
@@ -1880,10 +1904,11 @@
     int loader_flash_id;
     int split_flash_id;
     int rc;
+    fih_int fih_rc = FIH_FAILURE;
 
     sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
     if (sectors == NULL) {
-        return SPLIT_GO_ERR;
+        FIH_RET(FIH_FAILURE);
     }
     BOOT_IMG(&boot_data, loader_slot).sectors = sectors + 0;
     BOOT_IMG(&boot_data, split_slot).sectors = sectors + BOOT_MAX_IMG_SECTORS;
@@ -1913,12 +1938,12 @@
      * bootable or non-bootable image.  Just validate that the image check
      * passes which is distinct from the normal check.
      */
-    rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
-                           BOOT_IMG_AREA(&boot_data, split_slot),
-                           boot_img_hdr(&boot_data, loader_slot),
-                           BOOT_IMG_AREA(&boot_data, loader_slot));
-    if (rc != 0) {
-        rc = SPLIT_GO_NON_MATCHING;
+    FIH_CALL(split_image_check, fih_rc,
+             boot_img_hdr(&boot_data, split_slot),
+             BOOT_IMG_AREA(&boot_data, split_slot),
+             boot_img_hdr(&boot_data, loader_slot),
+             BOOT_IMG_AREA(&boot_data, loader_slot));
+    if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
         goto done;
     }
 
@@ -1931,7 +1956,12 @@
     flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
     flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
     free(sectors);
-    return rc;
+
+    if (rc) {
+        fih_rc = fih_int_encode(rc);
+    }
+
+    FIH_RET(fih_rc);
 }
 
 #else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
@@ -2120,7 +2150,7 @@
 }
 #endif /* MCUBOOT_RAM_LOAD */
 
-int
+fih_int
 context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
 {
     struct image_header *hdr = NULL;
@@ -2137,6 +2167,7 @@
     uint32_t img_sz;
     uint32_t img_loaded = 0;
 #endif /* MCUBOOT_RAM_LOAD */
+    fih_int fih_rc;
 
     memset(state, 0, sizeof(struct boot_loader_state));
 
@@ -2202,8 +2233,8 @@
                 img_loaded = 1;
             }
 #endif /* MCUBOOT_RAM_LOAD */
-            rc = boot_validate_slot(state, selected_slot, NULL);
-            if (rc == 0) {
+            FIH_CALL(boot_validate_slot, fih_rc, state, selected_slot, NULL);
+            if (fih_eq(fih_rc, FIH_SUCCESS)) {
                 /* If a valid image is found then there is no reason to check
                  * the rest of the images, as each of them has a smaller version
                  * number.
@@ -2225,9 +2256,8 @@
             slot_usage[selected_slot] = 0;
         }
 
-        if (rc || (selected_image_header == NULL)) {
+        if (fih_not_eq(fih_rc, FIH_SUCCESS) || (selected_image_header == NULL)) {
             /* If there was no valid image at all */
-            rc = BOOT_EBADIMAGE;
             goto out;
         }
 
@@ -2278,20 +2308,27 @@
    for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
        flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
    }
-   return rc;
+
+   if (rc) {
+       fih_rc = fih_int_encode(rc);
+   }
+
+   FIH_RET(fih_rc);
 }
 #endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
 
 /**
- * Prepares the booting process.  This function moves images around in flash as
+ * Prepares the booting process. This function moves images around in flash as
  * appropriate, and tells you what address to boot from.
  *
  * @param rsp                   On success, indicates how booting should occur.
  *
- * @return                      0 on success; nonzero on failure.
+ * @return                      FIH_SUCCESS on success; nonzero on failure.
  */
-int
+fih_int
 boot_go(struct boot_rsp *rsp)
 {
-    return context_boot_go(&boot_data, rsp);
+    fih_int fih_rc = FIH_FAILURE;
+    FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp);
+    FIH_RET(fih_rc);
 }