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/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);
 }