summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/fizz/ec.tasklist3
-rw-r--r--common/vboot.c184
-rw-r--r--include/rwsig.h8
3 files changed, 180 insertions, 15 deletions
diff --git a/board/fizz/ec.tasklist b/board/fizz/ec.tasklist
index 06c39984a3..82a214f38d 100644
--- a/board/fizz/ec.tasklist
+++ b/board/fizz/ec.tasklist
@@ -22,7 +22,8 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
- TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
+ /* Larger stack for RW verification (i.e. sha256, rsa) */ \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, 2048) \
TASK_NOTEST(PDCMD, pd_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
diff --git a/common/vboot.c b/common/vboot.c
index 6f16d05380..1e92572c5b 100644
--- a/common/vboot.c
+++ b/common/vboot.c
@@ -4,7 +4,7 @@
*/
/*
- * Implementation of EC's boot verification
+ * Verify and jump to a RW image if power supply is not sufficient.
*/
#include "battery.h"
@@ -12,10 +12,14 @@
#include "chipset.h"
#include "console.h"
#include "host_command.h"
+#include "rsa.h"
#include "rwsig.h"
+#include "sha256.h"
+#include "shared_mem.h"
#include "system.h"
#include "usb_pd.h"
#include "vboot.h"
+#include "vb21_struct.h"
#define CPRINTS(format, args...) cprints(CC_VBOOT, format, ## args)
@@ -31,7 +35,11 @@ static int has_matrix_keyboard(void)
static int is_vboot_ec_supported(void)
{
+#ifdef CONFIG_VBOOT_EC
+ return 1;
+#else
return 0;
+#endif
}
static int is_low_power_ap_boot_supported(void)
@@ -39,24 +47,179 @@ static int is_low_power_ap_boot_supported(void)
return 0;
}
+static int is_vb21_packed_key_valid(const struct vb21_packed_key *key)
+{
+ if (key->c.magic != VB21_MAGIC_PACKED_KEY)
+ return EC_ERROR_INVAL;
+ if (key->key_size != sizeof(struct rsa_public_key))
+ return EC_ERROR_INVAL;
+ return EC_SUCCESS;
+}
+
+static int is_vb21_signature_valid(const struct vb21_signature *sig,
+ const struct vb21_packed_key *key)
+{
+ if (sig->c.magic != VB21_MAGIC_SIGNATURE)
+ return EC_ERROR_INVAL;
+ if (sig->sig_size != RSANUMBYTES)
+ return EC_ERROR_INVAL;
+ if (key->sig_alg != sig->sig_alg)
+ return EC_ERROR_INVAL;
+ if (key->hash_alg != sig->hash_alg)
+ return EC_ERROR_INVAL;
+ /* Sanity check signature offset and data size. */
+ if (sig->sig_offset < sizeof(*sig))
+ return EC_ERROR_INVAL;
+ if (sig->sig_offset + RSANUMBYTES > CONFIG_RW_SIG_SIZE)
+ return EC_ERROR_INVAL;
+ if (sig->data_size > CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE)
+ return EC_ERROR_INVAL;
+ return EC_SUCCESS;
+}
+
+static int is_padding_valid(const uint8_t *data, unsigned int start, int len)
+{
+ const uint32_t *data32 = (const uint32_t *)data;
+ int i;
+
+ if (len < 0)
+ return EC_ERROR_INVAL;
+
+ if ((start % 4) != 0 || (len % 4) != 0)
+ return EC_ERROR_INVAL;
+
+ for (i = start/4; i < len/4; i++) {
+ if (data32[i] != 0xffffffff)
+ return EC_ERROR_INVAL;
+ }
+
+ return EC_SUCCESS;
+}
+
+static int vboot_verify(const uint8_t *data, int len,
+ const struct rsa_public_key *key, const uint8_t *sig)
+{
+ struct sha256_ctx ctx;
+ uint8_t *hash;
+ uint32_t *workbuf;
+ int err = EC_SUCCESS;
+
+ if (shared_mem_acquire(3 * RSANUMBYTES, (char **)&workbuf)) {
+ CPRINTS("Failed to allocate memory");
+ return EC_ERROR_UNKNOWN;
+ }
+
+ /* Compute hash of the RW firmware */
+ SHA256_init(&ctx);
+ SHA256_update(&ctx, data, len);
+ hash = SHA256_final(&ctx);
+
+ /* Verify the data */
+ if (rsa_verify(key, sig, hash, workbuf) != 1) {
+ CPRINTS("Invalid data");
+ err = EC_ERROR_INVAL;
+ }
+
+ shared_mem_release(workbuf);
+
+ return err;
+}
+
static int verify_slot(int slot)
{
- /* TODO: Handle slot A and B */
- CPRINTS("Verifying S%d", slot);
- return rwsig_check_signature();
+ const uint8_t *data;
+ const struct vb21_packed_key *vb21_key;
+ const struct vb21_signature *vb21_sig;
+ const struct rsa_public_key *key;
+ const uint8_t *sig;
+ int len;
+ int rv = EC_ERROR_INVAL;
+
+ CPRINTS("Verifying RW_%c", slot == VBOOT_EC_SLOT_A ? 'A' : 'B');
+
+ vb21_key = (const struct vb21_packed_key *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_PROTECTED_STORAGE_OFF +
+ CONFIG_RO_PUBKEY_STORAGE_OFF);
+ if (is_vb21_packed_key_valid(vb21_key)) {
+ CPRINTS("Invalid key");
+ goto exit;
+ }
+ key = (const struct rsa_public_key *)
+ ((const uint8_t *)vb21_key + vb21_key->key_offset);
+
+ if (slot == VBOOT_EC_SLOT_A) {
+ data = (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_A_STORAGE_OFF);
+ vb21_sig = (const struct vb21_signature *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_A_SIGN_STORAGE_OFF);
+ } else {
+ data = (const uint8_t *)(CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_B_STORAGE_OFF);
+ vb21_sig = (const struct vb21_signature *)(
+ CONFIG_MAPPED_STORAGE_BASE +
+ CONFIG_EC_WRITABLE_STORAGE_OFF +
+ CONFIG_RW_B_SIGN_STORAGE_OFF);
+ }
+
+ if (is_vb21_signature_valid(vb21_sig, vb21_key)) {
+ CPRINTS("Invalid signature");
+ goto exit;
+ }
+ sig = (const uint8_t *)vb21_sig + vb21_sig->sig_offset;
+ len = vb21_sig->data_size;
+
+ if (is_padding_valid(data, len,
+ CONFIG_RW_SIZE - len - CONFIG_RW_SIG_SIZE)) {
+ CPRINTS("Invalid padding");
+ goto exit;
+ }
+
+ if (vboot_verify(data, len, key, sig)) {
+ CPRINTS("Invalid data");
+ goto exit;
+ }
+
+ rv = EC_SUCCESS;
+
+exit:
+ return rv;
}
-static int verify_rw(void)
+static int verify_and_jump(void)
{
uint8_t slot;
+ int rv;
- /* 1. Read BBRAM to decide which slot to verify */
+ /* 1. Decide which slot to try */
if (system_get_bbram(SYSTEM_BBRAM_IDX_TRY_SLOT, &slot)) {
CPRINTS("Failed to read try slot");
slot = VBOOT_EC_SLOT_A;
}
+
/* 2. Verify the slot */
- return verify_slot(slot);
+ rv = verify_slot(slot);
+ if (rv) {
+ if (rv != EC_ERROR_INVAL)
+ /* Unknown error. The other slot isn't worth trying. */
+ return rv;
+ /* Verification error. The other slot is worth trying. */
+ slot = 1 - slot;
+ if (verify_slot(slot))
+ /* Both slots failed */
+ return rv;
+ /* Proceed with the other slot. AP will help us fix it. */
+ }
+
+ /* 3. Jump (and reboot) */
+ system_run_image_copy(slot == VBOOT_EC_SLOT_A ?
+ SYSTEM_IMAGE_RW : SYSTEM_IMAGE_RW_B);
+
+ return EC_ERROR_UNKNOWN;
}
/* Request more power: charging battery or more powerful AC adapter */
@@ -109,10 +272,9 @@ void vboot_ec(void)
return;
}
- if (verify_rw())
- /* Jump (and reboot) */
- rwsig_jump_now();
+ /* If successful, this won't return. */
+ verify_and_jump();
- /* Failed to verify RW. Need recovery. */
+ /* Failed to jump. Need recovery. */
request_recovery();
}
diff --git a/include/rwsig.h b/include/rwsig.h
index 0cb98c83f0..813fa06f9c 100644
--- a/include/rwsig.h
+++ b/include/rwsig.h
@@ -77,12 +77,14 @@ void rwsig_jump_now(void);
#endif /* ! CONFIG_RO_PUBKEY_SIZE */
#ifndef CONFIG_RO_PUBKEY_ADDR
#ifdef CONFIG_RWSIG_TYPE_RWSIG
+#define CONFIG_RO_PUBKEY_STORAGE_OFF (CONFIG_RO_STORAGE_OFF \
+ + CONFIG_RO_SIZE \
+ - CONFIG_RO_PUBKEY_SIZE)
+
/* The pubkey resides at the end of the RO image */
#define CONFIG_RO_PUBKEY_ADDR (CONFIG_PROGRAM_MEMORY_BASE \
+ CONFIG_EC_PROTECTED_STORAGE_OFF \
- + CONFIG_RO_STORAGE_OFF \
- + CONFIG_RO_SIZE \
- - CONFIG_RO_PUBKEY_SIZE)
+ + CONFIG_RO_PUBKEY_STORAGE_OFF)
#else
/*
* usbpd1 type assumes pubkey location at the end of first half of flash,