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