Merge "aboot: mdtp: use boot_verifier for boot/recovery verification"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index c87100a..a55c020 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -756,6 +756,22 @@
auth_kernel_img = 1;
}
+#ifdef MDTP_SUPPORT
+ {
+ /* Verify MDTP lock.
+ * For boot & recovery partitions, use aboot's verification result.
+ */
+ mdtp_ext_partition_verification_t ext_partition;
+ ext_partition.partition = boot_into_recovery ? MDTP_PARTITION_RECOVERY : MDTP_PARTITION_BOOT;
+ ext_partition.integrity_state = device.is_tampered ? MDTP_PARTITION_STATE_INVALID : MDTP_PARTITION_STATE_VALID;
+ ext_partition.page_size = 0; /* Not needed since already validated */
+ ext_partition.image_addr = 0; /* Not needed since already validated */
+ ext_partition.image_size = 0; /* Not needed since already validated */
+ ext_partition.sig_avail = FALSE; /* Not needed since already validated */
+ mdtp_fwlock_verify_lock(&ext_partition);
+ }
+#endif /* MDTP_SUPPORT */
+
#if USE_PCOM_SECBOOT
set_tamper_flag(device.is_tampered);
#endif
@@ -837,7 +853,6 @@
void boot_verifier_init()
{
-
uint32_t boot_state;
/* Check if device unlock */
if(device.is_unlocked)
@@ -1027,6 +1042,23 @@
#ifdef TZ_SAVE_KERNEL_HASH
aboot_save_boot_hash_mmc((uint32_t) image_addr, imagesize_actual);
#endif /* TZ_SAVE_KERNEL_HASH */
+
+#ifdef MDTP_SUPPORT
+ {
+ /* Verify MDTP lock.
+ * For boot & recovery partitions, MDTP will use boot_verifier APIs,
+ * since verification was skipped in aboot. The signature is not part of the loaded image.
+ */
+ mdtp_ext_partition_verification_t ext_partition;
+ ext_partition.partition = boot_into_recovery ? MDTP_PARTITION_RECOVERY : MDTP_PARTITION_BOOT;
+ ext_partition.integrity_state = MDTP_PARTITION_STATE_UNSET;
+ ext_partition.page_size = page_size;
+ ext_partition.image_addr = (uint32)image_addr;
+ ext_partition.image_size = imagesize_actual;
+ ext_partition.sig_avail = FALSE;
+ mdtp_fwlock_verify_lock(&ext_partition);
+ }
+#endif /* MDTP_SUPPORT */
}
/*
@@ -1821,13 +1853,6 @@
unsigned int kernel_size = 0;
unsigned int scratch_offset = 0;
-
-#ifdef MDTP_SUPPORT
- /* Go through Firmware Lock verification before continue with boot process */
- mdtp_fwlock_verify_lock();
- display_image_on_screen();
-#endif /* MDTP_SUPPORT */
-
#if VERIFIED_BOOT
if(!device.is_unlocked)
{
@@ -1879,6 +1904,24 @@
*/
verify_signed_bootimg((uint32_t)data, (image_actual - sig_actual));
+#ifdef MDTP_SUPPORT
+ else
+ {
+ /* Verify MDTP lock before continue with boot process.
+ * For boot & recovery partitions, MDTP will use boot_verifier APIs,
+ * since verification was skipped in aboot. The signarue is already part of the loaded image.
+ */
+ mdtp_ext_partition_verification_t ext_partition;
+ ext_partition.partition = boot_into_recovery ? MDTP_PARTITION_RECOVERY : MDTP_PARTITION_BOOT;
+ ext_partition.integrity_state = MDTP_PARTITION_STATE_UNSET;
+ ext_partition.page_size = page_size;
+ ext_partition.image_addr = (uint32_t)data;
+ ext_partition.image_size = image_actual - sig_actual;
+ ext_partition.sig_avail = TRUE;
+ mdtp_fwlock_verify_lock(&ext_partition);
+ }
+#endif /* MDTP_SUPPORT */
+
/*
* Check if the kernel image is a gzip package. If yes, need to decompress it.
* If not, continue booting.
@@ -2609,12 +2652,6 @@
fastboot_okay("");
fastboot_stop();
-#ifdef MDTP_SUPPORT
- /* Go through Firmware Lock verification before continue with boot process */
- mdtp_fwlock_verify_lock();
- display_image_on_screen();
-#endif /* MDTP_SUPPORT */
-
if (target_is_emmc_boot())
{
boot_linux_from_mmc();
@@ -3107,12 +3144,6 @@
normal_boot:
if (!boot_into_fastboot)
{
-#ifdef MDTP_SUPPORT
- /* Go through Firmware Lock verification before continue with boot process */
- mdtp_fwlock_verify_lock();
- display_image_on_screen();
-#endif /* MDTP_SUPPORT */
-
if (target_is_emmc_boot())
{
if(emmc_recovery_init())
diff --git a/app/aboot/mdtp.c b/app/aboot/mdtp.c
index 5c5782a..2ecccce 100644
--- a/app/aboot/mdtp.c
+++ b/app/aboot/mdtp.c
@@ -38,11 +38,14 @@
#include <string.h>
#include <rand.h>
#include <stdlib.h>
+#include <boot_verifier.h>
+#include <image_verify.h>
#include "scm.h"
#include "mdtp.h"
-#define DIP_ENCRYPT 0
-#define DIP_DECRYPT 1
+#define DIP_ENCRYPT (0)
+#define DIP_DECRYPT (1)
+#define MAX_CIPHER_DIP_SCM_CALLS (3)
#define MDTP_MAJOR_VERSION (0)
#define MDTP_MINOR_VERSION (2)
@@ -50,15 +53,15 @@
/** Extract major version number from complete version. */
#define MDTP_GET_MAJOR_VERSION(version) ((version) >> 16)
-static int is_mdtp_activated = -1;
-
static int mdtp_tzbsp_dec_verify_DIP(DIP_t *enc_dip, DIP_t *dec_dip, uint32_t *verified);
static int mdtp_tzbsp_enc_hash_DIP(DIP_t *dec_dip, DIP_t *enc_dip);
+static void mdtp_tzbsp_disallow_cipher_DIP(void);
uint32_t g_mdtp_version = (((MDTP_MAJOR_VERSION << 16) & 0xFFFF0000) | (MDTP_MINOR_VERSION & 0x0000FFFF));
+static int is_mdtp_activated = -1;
-int scm_random(uint32_t * rbuf, uint32_t r_len);
int check_aboot_addr_range_overlap(uint32_t start, uint32_t size);
+int scm_random(uint32_t * rbuf, uint32_t r_len);
/********************************************************************************/
@@ -175,7 +178,7 @@
unsigned char digest[HASH_LEN]={0};
unsigned long long ptn = 0;
int index = INVALID_PTN;
- unsigned char *buf = (unsigned char *)target_get_scratch_address();
+ unsigned char *buf = (unsigned char *)target_get_scratch_address() + MDTP_SCRATCH_OFFSET;
uint32_t block_size = mmc_get_device_blocksize();
uint64_t actual_partition_size = ROUNDUP(size, block_size);
@@ -225,7 +228,7 @@
unsigned char digest[HASH_LEN]={0};
unsigned long long ptn = 0;
int index = INVALID_PTN;
- unsigned char *buf = (unsigned char *)target_get_scratch_address();
+ unsigned char *buf = (unsigned char *)target_get_scratch_address() + MDTP_SCRATCH_OFFSET;
uint32_t bytes_to_read;
uint32_t block_num = 0;
uint32_t total_num_blocks = ((size - 1) / MDTP_FWLOCK_BLOCK_SIZE) + 1;
@@ -377,18 +380,18 @@
}
/* Display the recovery UI to allow the user to enter the PIN and continue boot */
-static void display_recovery_ui(DIP_t *dip)
+static void display_recovery_ui(mdtp_cfg_t *mdtp_cfg)
{
uint32_t pin_length = 0;
char entered_pin[MDTP_MAX_PIN_LEN+1] = {0};
uint32_t i;
char pin_mismatch = 0;
- if (dip->mdtp_cfg.enable_local_pin_authentication)
+ if (mdtp_cfg->enable_local_pin_authentication)
{
dprintf(SPEW, "mdtp: display_recovery_ui: Local deactivation enabled\n");
- pin_length = strlen(dip->mdtp_cfg.mdtp_pin.mdtp_pin);
+ pin_length = strlen(mdtp_cfg->mdtp_pin.mdtp_pin);
if (pin_length > MDTP_MAX_PIN_LEN || pin_length < MDTP_MIN_PIN_LEN)
{
@@ -411,7 +414,7 @@
// Go over the entire PIN in any case, to prevent side-channel attacks
for (i=0; i<pin_length; i++)
{
- pin_mismatch |= dip->mdtp_cfg.mdtp_pin.mdtp_pin[i] ^ entered_pin[i];
+ pin_mismatch |= mdtp_cfg->mdtp_pin.mdtp_pin[i] ^ entered_pin[i];
}
if (0 == pin_mismatch)
@@ -439,11 +442,110 @@
}
}
+/* Verify the boot or recovery partitions using boot_verifier. */
+static int verify_ext_partition(mdtp_ext_partition_verification_t *ext_partition)
+{
+ int ret = 0;
+ bool restore_to_orange = false;
+ unsigned long long ptn = 0;
+ int index = INVALID_PTN;
+
+ /* If image was already verified in aboot, return its status */
+ if (ext_partition->integrity_state == MDTP_PARTITION_STATE_INVALID)
+ {
+ dprintf(CRITICAL, "mdtp: verify_ext_partition: image %s verified externally and failed.\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ return -1;
+ }
+ else if (ext_partition->integrity_state == MDTP_PARTITION_STATE_VALID)
+ {
+ dprintf(CRITICAL, "mdtp: verify_ext_partition: image %s verified externally succesfully.\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ return 0;
+ }
+
+ /* If image was not verified in aboot, verify it ourselves using boot_verifier. */
+
+ /* 1) Initialize keystore. We don't care about return value which is Verified Boot's state machine state. */
+ boot_verify_keystore_init();
+
+ /* 2) If boot_verifier is ORANGE, it will prevent verifying an image. So
+ * temporarly change boot_verifier state to BOOT_INIT.
+ */
+ if (boot_verify_get_state() == ORANGE)
+ restore_to_orange = true;
+ boot_verify_send_event(BOOT_INIT);
+
+ switch (ext_partition->partition)
+ {
+ case MDTP_PARTITION_BOOT:
+ case MDTP_PARTITION_RECOVERY:
+
+ /* 3) Signature may or may not be at the end of the image. Read the signature if needed. */
+ if (!ext_partition->sig_avail)
+ {
+ if (check_aboot_addr_range_overlap((uint32_t)(ext_partition->image_addr + ext_partition->image_size), ext_partition->page_size))
+ {
+ dprintf(CRITICAL, "ERROR: Signature read buffer address overlaps with aboot addresses.\n");
+ return -1;
+ }
+
+ index = partition_get_index(ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ ptn = partition_get_offset(index);
+ if(ptn == 0) {
+ dprintf(CRITICAL, "ERROR: partition %s not found\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ return -1;
+ }
+
+ if(mmc_read(ptn + ext_partition->image_size, (void *)(ext_partition->image_addr + ext_partition->image_size), ext_partition->page_size))
+ {
+ dprintf(CRITICAL, "ERROR: Cannot read %s image signature\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ return -1;
+ }
+ }
+
+ /* 4) Verify the image using its signature. */
+ ret = boot_verify_image((unsigned char *)ext_partition->image_addr,
+ ext_partition->image_size,
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ break;
+
+ default:
+ /* Only boot and recovery are legal here */
+ dprintf(CRITICAL, "ERROR: wrong partition %d\n", ext_partition->partition);
+ return -1;
+ }
+
+ if (ret)
+ {
+ dprintf(INFO, "mdtp: verify_ext_partition: image %s verified succesfully in MDTP.\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ }
+ else
+ {
+ dprintf(CRITICAL, "mdtp: verify_ext_partition: image %s verification failed in MDTP.\n",
+ ext_partition->partition == MDTP_PARTITION_BOOT ? "boot" : "recovery");
+ }
+
+ /* 5) Restore the right boot_verifier state upon exit. */
+ if (restore_to_orange)
+ {
+ boot_verify_send_event(DEV_UNLOCK);
+ }
+
+ return ret ? 0 : -1;
+}
+
/* Verify all protected partitinons according to the DIP */
-static void verify_all_partitions(DIP_t *dip, verify_result_t *verify_result)
+static void verify_all_partitions(DIP_t *dip,
+ mdtp_ext_partition_verification_t *ext_partition,
+ verify_result_t *verify_result)
{
int i;
- bool verify_failure = FALSE;
+ int verify_failure = 0;
+ int ext_partition_verify_failure = 0;
uint32_t total_num_blocks;
ASSERT(dip != NULL);
@@ -487,7 +589,9 @@
}
}
- if (verify_failure)
+ ext_partition_verify_failure = verify_ext_partition(ext_partition);
+
+ if (verify_failure || ext_partition_verify_failure)
{
dprintf(CRITICAL, "mdtp: verify_all_partitions: Failed partition verification\n");
return;
@@ -501,7 +605,7 @@
}
/* Verify the DIP and all protected partitions */
-static void validate_DIP_and_firmware()
+static void validate_DIP_and_firmware(mdtp_ext_partition_verification_t *ext_partition)
{
int ret;
DIP_t *enc_dip;
@@ -509,6 +613,7 @@
uint32_t verified = 0;
verify_result_t verify_result;
uint32_t block_size = mmc_get_device_blocksize();
+ mdtp_cfg_t mdtp_cfg;
enc_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
if (enc_dip == NULL)
@@ -548,12 +653,15 @@
display_error_msg(); /* This will never return */
}
- /* Verify the integrity of the partitions which are protectedm, according to the content of the DIP */
- verify_all_partitions(dec_dip, &verify_result);
+ /* Verify the integrity of the partitions which are protected, according to the content of the DIP */
+ verify_all_partitions(dec_dip, ext_partition, &verify_result);
+
+ mdtp_cfg = dec_dip->mdtp_cfg;
/* Clear decrypted DIP since we don't need it anymore */
memset(dec_dip, 0, sizeof(DIP_t));
+
if (verify_result == VERIFY_OK)
{
dprintf(SPEW, "mdtp: validate_DIP_and_firmware: Verify OK\n");
@@ -564,9 +672,11 @@
} else /* VERIFY_FAILED */
{
dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted firmware\n");
- display_recovery_ui(dec_dip);
+ display_recovery_ui(&mdtp_cfg);
}
+ memset(&mdtp_cfg, 0, sizeof(mdtp_cfg));
+
free(enc_dip);
free(dec_dip);
@@ -575,10 +685,13 @@
/********************************************************************************/
-/** Entry point of the MDTP Firmware Lock: If needed, verify the DIP
- * and all protected partitions **/
-
-void mdtp_fwlock_verify_lock()
+/** Entry point of the MDTP Firmware Lock.
+ * If needed, verify the DIP and all protected partitions.
+ * Allow passing information about partition verified using an external method
+ * (either boot or recovery). For boot and recovery, either use aboot's
+ * verification result, or use boot_verifier APIs to verify internally.
+ **/
+void mdtp_fwlock_verify_lock(mdtp_ext_partition_verification_t *ext_partition)
{
int ret;
bool enabled;
@@ -586,18 +699,34 @@
/* sets the default value of this global to be MDTP not activated */
is_mdtp_activated = 0;
- ret = mdtp_fuse_get_enabled(&enabled);
- if(ret)
- {
- dprintf(CRITICAL, "mdtp: mdtp_fwlock_verify_lock: ERROR, cannot get enabled fuse\n");
- display_error_msg(); /* This will never return */
- }
+ do {
+ if (ext_partition == NULL)
+ {
+ dprintf(CRITICAL, "mdtp: mdtp_fwlock_verify_lock: ERROR, external partition is NULL\n");
+ display_error_msg(); /* This will never return */
+ break;
+ }
- /* Continue with Firmware Lock verification only if enabled by eFuse */
- if (enabled)
+ ret = mdtp_fuse_get_enabled(&enabled);
+ if(ret)
+ {
+ dprintf(CRITICAL, "mdtp: mdtp_fwlock_verify_lock: ERROR, cannot get enabled fuse\n");
+ display_error_msg(); /* This will never return */
+ }
+
+ /* Continue with Firmware Lock verification only if enabled by eFuse */
+ if (enabled)
+ {
+ /* This function will handle firmware verification failure via UI */
+ validate_DIP_and_firmware(ext_partition);
+ }
+ } while (0);
+
+ /* Disallow CIPHER_DIP SCM call from this point, unless we are in recovery */
+ /* The recovery image will disallow CIPHER_DIP SCM call by itself. */
+ if (ext_partition->partition != MDTP_PARTITION_RECOVERY)
{
- /* This function will handle firmware verification failure via UI */
- validate_DIP_and_firmware();
+ mdtp_tzbsp_disallow_cipher_DIP();
}
}
/********************************************************************************/
@@ -654,6 +783,7 @@
return 0;
}
+/* Encrypt a given DIP and calculate its integrity information */
static int mdtp_tzbsp_enc_hash_DIP(DIP_t *dec_dip, DIP_t *enc_dip)
{
SHA256_CTX sha256_ctx;
@@ -677,3 +807,25 @@
return 0;
}
+
+/* Disallow the CIPHER_DIP SCM call */
+static void mdtp_tzbsp_disallow_cipher_DIP(void)
+{
+ DIP_t *dip;
+ int i;
+
+ dip = malloc(sizeof(DIP_t));
+ if (dip == NULL)
+ {
+ dprintf(CRITICAL, "mdtp: mdtp_tzbsp_disallow_cipher_DIP: ERROR, cannot allocate DIP\n");
+ return;
+ }
+
+ /* Disallow the CIPHER_DIP SCM by calling it MAX_CIPHER_DIP_SCM_CALLS times */
+ for (i=0; i<MAX_CIPHER_DIP_SCM_CALLS; i++)
+ {
+ mdtp_tzbsp_enc_hash_DIP(dip, dip);
+ }
+
+ free(dip);
+}
diff --git a/app/aboot/mdtp.h b/app/aboot/mdtp.h
index 0f30b54..c29dcc2 100644
--- a/app/aboot/mdtp.h
+++ b/app/aboot/mdtp.h
@@ -45,6 +45,13 @@
#define MDTP_FWLOCK_BLOCK_SIZE (1024*1024*16)
#define MDTP_FWLOCK_MAX_FILES (100)
#define MDTP_FWLOCK_MAX_FILE_NAME_LEN (100)
+#define MDTP_SCRATCH_OFFSET 0x8000000
+
+#ifdef MDTP_SUPPORT
+#ifndef VERIFIED_BOOT
+#error MDTP feature requires VERIFIED_BOOT feature
+#endif
+#endif
#pragma pack(push, mdtp, 1)
@@ -102,22 +109,35 @@
} DIP_t;
#pragma pack(pop, mdtp)
+
+typedef enum {
+ MDTP_PARTITION_BOOT = 0,
+ MDTP_PARTITION_RECOVERY,
+ MDTP_PARTITION_NUM,
+} mdtp_ext_partition_t;
+
+typedef enum {
+ MDTP_PARTITION_STATE_UNSET = 0,
+ MDTP_PARTITION_STATE_VALID,
+ MDTP_PARTITION_STATE_INVALID,
+ MDTP_PARTITION_STATE_SIZE,
+} mdtp_ext_partition_state_t;
+
+typedef struct mdtp_ext_partition {
+ mdtp_ext_partition_t partition;
+ mdtp_ext_partition_state_t integrity_state;
+ uint32_t page_size;
+ uint32_t image_addr;
+ uint32_t image_size;
+ bool sig_avail;
+} mdtp_ext_partition_verification_t;
+
typedef enum {
VERIFY_SKIPPED = 0,
VERIFY_OK,
VERIFY_FAILED,
} verify_result_t;
-
-/**
- * mdtp_fwlock_verify_lock
- *
- * Start Firmware Lock verification process.
- *
- * @return - None.
- */
-void mdtp_fwlock_verify_lock();
-
/**
* mdtp_fuse_get_enabled
*
@@ -175,4 +195,15 @@
*/
int mdtp_activated(bool * activated);
+
+// External functions
+
+/** Entry point of the MDTP Firmware Lock.
+ * If needed, verify the DIP and all protected partitions.
+ * Allow passing information about partition verified using an external method
+ * (either boot or recovery). For boot and recovery, either use aboot's
+ * verification result, or use boot_verifier APIs to verify internally.
+ **/
+void mdtp_fwlock_verify_lock(mdtp_ext_partition_verification_t *ext_partition);
+
#endif