diff options
Diffstat (limited to 'common/vboot')
-rw-r--r-- | common/vboot/common.c | 58 | ||||
-rw-r--r-- | common/vboot/efs2.c | 352 | ||||
-rw-r--r-- | common/vboot/vb21_lib.c | 108 | ||||
-rw-r--r-- | common/vboot/vboot.c | 228 |
4 files changed, 0 insertions, 746 deletions
diff --git a/common/vboot/common.c b/common/vboot/common.c deleted file mode 100644 index 39f8c193c7..0000000000 --- a/common/vboot/common.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "common.h" -#include "console.h" -#include "rsa.h" -#include "sha256.h" -#include "shared_mem.h" -#include "vboot.h" - -#define CPRINTS(format, args...) cprints(CC_VBOOT, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args) - -int vboot_is_padding_valid(const uint8_t *data, uint32_t start, uint32_t end) -{ - const uint32_t *data32 = (const uint32_t *)data; - int i; - - if (start > end) - return EC_ERROR_INVAL; - - if (start % 4 || end % 4) - return EC_ERROR_INVAL; - - for (i = start / 4; i < end / 4; i++) { - if (data32[i] != 0xffffffff) - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -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_CHECK(3 * RSANUMBYTES, (char **)&workbuf)) - return EC_ERROR_MEMORY_ALLOCATION; - - /* 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) - err = EC_ERROR_VBOOT_DATA_VERIFY; - - shared_mem_release(workbuf); - - return err; -} diff --git a/common/vboot/efs2.c b/common/vboot/efs2.c deleted file mode 100644 index e5c3b64f04..0000000000 --- a/common/vboot/efs2.c +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * Early Firmware Selection ver.2. - * - * Verify and jump to a RW image. Register boot mode to Cr50. - */ - -#include "battery.h" -#include "chipset.h" -#include "clock.h" -#include "compile_time_macros.h" -#include "console.h" -#include "crc8.h" -#include "flash.h" -#include "hooks.h" -#include "sha256.h" -#include "system.h" -#include "task.h" -#include "usb_pd.h" -#include "uart.h" -#include "vboot.h" -#include "vboot_hash.h" - -#define CPRINTS(format, args...) cprints(CC_VBOOT,"VB " format, ## args) -#define CPRINTF(format, args...) cprintf(CC_VBOOT,"VB " format, ## args) - -static const char *boot_mode_to_string(uint8_t mode) -{ - static const char *boot_mode_str[] = { - [BOOT_MODE_NORMAL] = "NORMAL", - [BOOT_MODE_NO_BOOT] = "NO_BOOT", - }; - if (mode < ARRAY_SIZE(boot_mode_str)) - return boot_mode_str[mode]; - return "UNDEF"; -} - -/* - * Check whether the session has successfully ended or not. ERR_TIMEOUT is - * excluded because it's an internal error produced by EC itself. - */ -static bool is_valid_cr50_response(enum cr50_comm_err code) -{ - return code != CR50_COMM_ERR_TIMEOUT - && (code >> 8) == CR50_COMM_ERR_PREFIX; -} - -__overridable void board_enable_packet_mode(bool enable) -{ - /* - * This can be done by set_flags(INPUT|PULL_UP). We don't need it now - * because Cr50 never initiates communication. - */ - gpio_set_level(GPIO_PACKET_MODE_EN, enable ? 1 : 0); -} - -static enum cr50_comm_err send_to_cr50(const uint8_t *data, size_t size) -{ - timestamp_t until; - int i, timeout = 0; - uint32_t lock_key; - struct cr50_comm_response res = {}; - - /* This will wake up (if it's sleeping) and interrupt Cr50. */ - board_enable_packet_mode(true); - - uart_flush_output(); - uart_clear_input(); - - if (uart_shell_stop()) { - /* Failed to stop the shell. */ - board_enable_packet_mode(false); - return CR50_COMM_ERR_UNKNOWN; - } - - /* - * Send packet. No traffic control, assuming Cr50 consumes stream much - * faster. TX buffer shouldn't overflow because it's cleared above and - * much bigger than the max packet size. - * - * Disable interrupts so that the data frame will be stored in the Tx - * buffer in one piece. - */ - lock_key = irq_lock(); - uart_put_raw(data, size); - irq_unlock(lock_key); - - uart_flush_output(); - - until.val = get_time().val + CR50_COMM_TIMEOUT; - - /* - * Make sure console task won't steal the response in case we exchange - * packets after tasks start. - */ -#ifndef CONFIG_ZEPHYR - if (task_start_called()) - task_disable_task(TASK_ID_CONSOLE); -#endif /* !CONFIG_ZEPHYR */ - - /* Wait for response from Cr50 */ - for (i = 0; i < sizeof(res); i++) { - while (!timeout) { - int c = uart_getc(); - if (c != -1) { - res.error = res.error | c << (i*8); - break; - } - msleep(1); - timeout = timestamp_expired(until, NULL); - } - } - - uart_shell_start(); -#ifndef CONFIG_ZEPHYR - if (task_start_called()) - task_enable_task(TASK_ID_CONSOLE); -#endif /* CONFIG_ZEPHYR */ - - /* Exit packet mode */ - board_enable_packet_mode(false); - - CPRINTS("Received 0x%04x", res.error); - - if (timeout) { - CPRINTS("Timeout"); - return CR50_COMM_ERR_TIMEOUT; - } - - return res.error; -} - -static enum cr50_comm_err cmd_to_cr50(enum cr50_comm_cmd cmd, - const uint8_t *data, size_t size) -{ - /* - * This is on the stack instead of .bss because vboot_main currently is - * called only once (from main). Keeping the space unused in .bss would - * be wasteful. - */ - struct { - uint8_t preamble[CR50_UART_RX_BUFFER_SIZE]; - uint8_t packet[CR50_COMM_MAX_REQUEST_SIZE]; - } __packed s; - struct cr50_comm_request *p = (struct cr50_comm_request *)s.packet; - int retry = CR50_COMM_MAX_RETRY; - enum cr50_comm_err rv; - - /* compose a frame = preamble + packet */ - memset(s.preamble, CR50_COMM_PREAMBLE, sizeof(s.preamble)); - p->magic = CR50_PACKET_MAGIC; - p->struct_version = CR50_COMM_PACKET_VERSION; - p->type = cmd; - p->size = size; - memcpy(p->data, data, size); - p->crc = cros_crc8((uint8_t *)&p->type, - sizeof(p->type) + sizeof(p->size) + size); - - do { - rv = send_to_cr50((uint8_t *)&s, - sizeof(s.preamble) + sizeof(*p) + p->size); - if (is_valid_cr50_response(rv)) - break; - msleep(5); - } while (--retry); - - return rv; -} - -static enum cr50_comm_err verify_hash(void) -{ - const uint8_t *hash; - int rv; - - /* Wake up Cr50 beforehand in case it's asleep. */ - board_enable_packet_mode(true); - CPRINTS("Ping Cr50"); - msleep(1); - board_enable_packet_mode(false); - - rv = vboot_get_rw_hash(&hash); - if (rv) - return rv; - - CPRINTS("Verifying hash"); - return cmd_to_cr50(CR50_COMM_CMD_VERIFY_HASH, hash, SHA256_DIGEST_SIZE); -} - -static enum cr50_comm_err set_boot_mode(uint8_t mode) -{ - enum cr50_comm_err rv; - - CPRINTS("Setting boot mode to %s(%d)", boot_mode_to_string(mode), mode); - rv = cmd_to_cr50(CR50_COMM_CMD_SET_BOOT_MODE, - &mode, sizeof(enum boot_mode)); - if (rv != CR50_COMM_SUCCESS) - CPRINTS("Failed to set boot mode"); - return rv; -} - -static bool pd_comm_enabled; - -static void enable_pd(void) -{ - CPRINTS("Enable USB-PD"); - pd_comm_enabled = true; -} - -bool vboot_allow_usb_pd(void) -{ - return pd_comm_enabled; -} - -__overridable void show_critical_error(void) -{ - CPRINTS("%s", __func__); -} - -static void verify_and_jump(void) -{ - enum cr50_comm_err rv = verify_hash(); - - switch (rv) { - case CR50_COMM_ERR_BAD_PAYLOAD: - /* Cr50 should have set NO_BOOT. */ - CPRINTS("Hash mismatch"); - enable_pd(); - break; - case CR50_COMM_SUCCESS: - system_set_reset_flags(EC_RESET_FLAG_EFS); - rv = system_run_image_copy(EC_IMAGE_RW); - CPRINTS("Failed to jump (0x%x)", rv); - system_clear_reset_flags(EC_RESET_FLAG_EFS); - show_critical_error(); - break; - default: - CPRINTS("Failed to verify RW (0x%x)", rv); - show_critical_error(); - } -} - -__overridable void show_power_shortage(void) -{ - CPRINTS("%s", __func__); -} - -static bool is_battery_ready(void) -{ - /* TODO: Add battery check (https://crbug.com/1045216) */ - return true; -} - -void vboot_main(void) -{ - CPRINTS("Main"); - - if (system_is_in_rw()) { - /* - * We come here and immediately return. LED shows power shortage - * but it will be immediately corrected if the adapter can - * provide enough power. - */ - CPRINTS("Already in RW"); - show_power_shortage(); - return; - } - - if (system_is_manual_recovery() || - (system_get_reset_flags() & EC_RESET_FLAG_STAY_IN_RO)) { - if (system_is_manual_recovery()) - CPRINTS("In recovery mode"); - if (!IS_ENABLED(CONFIG_BATTERY) - && !IS_ENABLED(HAS_TASK_KEYSCAN)) { - /* - * For Chromeboxes, we relax security by allowing PD in - * RO. Attackers don't gain meaningful advantage on - * built-in-keyboard-less systems. - * - * Alternatively, we can use NO_BOOT to show a firmware - * screen, strictly requiring BJ adapter and keeping PD - * disabled. - */ - enable_pd(); - return; - } - - /* - * If battery is drained or bad, we will boot in NO_BOOT mode to - * inform the user of the problem. - */ - if (!is_battery_ready()) { - CPRINTS("Battery not ready or bad"); - if (set_boot_mode(BOOT_MODE_NO_BOOT) == - CR50_COMM_SUCCESS) - enable_pd(); - } - - /* We'll enter recovery mode immediately, later, or never. */ - return; - } - - verify_and_jump(); - - /* - * EFS failed. EC-RO may be able to boot AP if: - * - * - Battery is charged or - * - AC adapter supply in RO >= Boot threshold or - * - BJ adapter is plugged. - * - * Once AP boots, software sync will fix the mismatch. If that's the - * reason of the failure, we won't come back here next time. - */ - CPRINTS("Exit"); -} - -void hook_shutdown(void) -{ - CPRINTS("%s", __func__); - - /* - * We filter the cases which can be interfered with if we execute - * system_reset in HOOK_CHIPSET_SHUTDOWN context. Most cases are - * filtered out by system_is_in_rw (e.g. system_common_shutdown, - * check_pending_cutoff). - */ - if (system_is_in_rw()) - return; - - /* - * We can't reset here because it'll completely tear down the power - * and disturb the PCH's power sequence. We instead sysjump. - * - * Note that this does not reduce the security. Even if it's hijacked in - * NO_BOOT mode, an RO still needs to go through a cold reset to clear - * NO_BOOT flag since Cr50 rejects to switch from NO_BOOT to NORMAL. - * If a spoofed matching hash is passed to Cr50, Cr50 would reset EC. - */ - system_set_reset_flags(EC_RESET_FLAG_AP_IDLE); - verify_and_jump(); -} -/* - * There can be hooks which are needed to set external chips to a certain state - * in S5. If the initial state (i.e. AP_OFF state) is different from what those - * hooks realize, they need to be considered. This hook runs last (i.e. - * HOOK_PRIO_LAST) to make our landing on S5 as mild as possible. - */ -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN_COMPLETE, hook_shutdown, HOOK_PRIO_LAST); diff --git a/common/vboot/vb21_lib.c b/common/vboot/vb21_lib.c deleted file mode 100644 index 4e215c14e5..0000000000 --- a/common/vboot/vb21_lib.c +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * Common utility APIs for vboot 2.1 - */ - -#include "common.h" -#include "host_command.h" -#include "rsa.h" -#include "rwsig.h" -#include "system.h" -#include "vb21_struct.h" -#include "vboot.h" - -int vb21_is_packed_key_valid(const struct vb21_packed_key *key) -{ - if (key->c.magic != VB21_MAGIC_PACKED_KEY) - return EC_ERROR_VBOOT_KEY_MAGIC; - if (key->key_size != sizeof(struct rsa_public_key)) - return EC_ERROR_VBOOT_KEY_SIZE; - return EC_SUCCESS; -} - -int vb21_is_signature_valid(const struct vb21_signature *sig, - const struct vb21_packed_key *key) -{ - if (sig->c.magic != VB21_MAGIC_SIGNATURE) - return EC_ERROR_VBOOT_SIG_MAGIC; - if (sig->sig_size != RSANUMBYTES) - return EC_ERROR_VBOOT_SIG_SIZE; - if (key->sig_alg != sig->sig_alg) - return EC_ERROR_VBOOT_SIG_ALGORITHM; - if (key->hash_alg != sig->hash_alg) - return EC_ERROR_VBOOT_HASH_ALGORITHM; - /* Validity check signature offset and data size. */ - if (sig->sig_offset < sizeof(*sig)) - return EC_ERROR_VBOOT_SIG_OFFSET; - if (sig->sig_offset + RSANUMBYTES > CONFIG_RW_SIG_SIZE) - return EC_ERROR_VBOOT_SIG_OFFSET; - if (sig->data_size > CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE) - return EC_ERROR_VBOOT_DATA_SIZE; - return EC_SUCCESS; -} - -const struct vb21_packed_key *vb21_get_packed_key(void) -{ - return (const struct vb21_packed_key *)(CONFIG_RO_PUBKEY_ADDR); -} - -static void read_rwsig_info(struct ec_response_rwsig_info *r) -{ - - const struct vb21_packed_key *vb21_key; - int rv; - - vb21_key = vb21_get_packed_key(); - - r->sig_alg = vb21_key->sig_alg; - r->hash_alg = vb21_key->hash_alg; - r->key_version = vb21_key->key_version; - { BUILD_ASSERT(sizeof(r->key_id) == sizeof(vb21_key->id), - "key ID sizes must match"); } - { BUILD_ASSERT(sizeof(vb21_key->id) == sizeof(vb21_key->id.raw), - "key ID sizes must match"); } - memcpy(r->key_id, vb21_key->id.raw, sizeof(r->key_id)); - - rv = vb21_is_packed_key_valid(vb21_key); - r->key_is_valid = (rv == EC_SUCCESS); -} - -static int command_rwsig_info(int argc, char **argv) -{ - int i; - struct ec_response_rwsig_info r; - - read_rwsig_info(&r); - - ccprintf("sig_alg: %d\n", r.sig_alg); - ccprintf("key_version: %d\n", r.key_version); - ccprintf("hash_alg: %d\n", r.hash_alg); - ccprintf("key_is_valid: %d\n", r.key_is_valid); - - ccprintf("key_id: "); - for (i = 0; i < sizeof(r.key_id); i++) - ccprintf("%x", r.key_id[i]); - ccprintf("\n"); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rwsiginfo, command_rwsig_info, NULL, - "Display rwsig info on console."); - -static enum ec_status -host_command_rwsig_info(struct host_cmd_handler_args *args) -{ - struct ec_response_rwsig_info *r = args->response; - - read_rwsig_info(r); - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} - -DECLARE_HOST_COMMAND(EC_CMD_RWSIG_INFO, host_command_rwsig_info, - EC_VER_MASK(EC_VER_RWSIG_INFO)); diff --git a/common/vboot/vboot.c b/common/vboot/vboot.c deleted file mode 100644 index 910156335d..0000000000 --- a/common/vboot/vboot.c +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * Verify and jump to a RW image if power supply is not sufficient. - */ - -#include "battery.h" -#include "charge_manager.h" -#include "chipset.h" -#include "clock.h" -#include "console.h" -#include "flash.h" -#include "hooks.h" -#include "host_command.h" -#include "rsa.h" -#include "rwsig.h" -#include "stdbool.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,"VB " format, ## args) -#define CPRINTF(format, args...) cprintf(CC_VBOOT,"VB " format, ## args) - -static int has_matrix_keyboard(void) -{ - return 0; -} - -static int verify_slot(enum ec_image slot) -{ - const struct vb21_packed_key *vb21_key; - const struct vb21_signature *vb21_sig; - const struct rsa_public_key *key; - const uint8_t *sig; - const uint8_t *data; - int len; - int rv; - - CPRINTS("Verifying %s", ec_image_to_string(slot)); - - vb21_key = (const struct vb21_packed_key *)( - CONFIG_MAPPED_STORAGE_BASE + - CONFIG_EC_PROTECTED_STORAGE_OFF + - CONFIG_RO_PUBKEY_STORAGE_OFF); - rv = vb21_is_packed_key_valid(vb21_key); - if (rv) { - CPRINTS("Invalid key (%d)", rv); - return EC_ERROR_VBOOT_KEY; - } - key = (const struct rsa_public_key *) - ((const uint8_t *)vb21_key + vb21_key->key_offset); - - if (slot == EC_IMAGE_RW_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); - } - - rv = vb21_is_signature_valid(vb21_sig, vb21_key); - if (rv) { - CPRINTS("Invalid signature (%d)", rv); - return EC_ERROR_INVAL; - } - sig = (const uint8_t *)vb21_sig + vb21_sig->sig_offset; - len = vb21_sig->data_size; - - if (vboot_is_padding_valid(data, len, - CONFIG_RW_SIZE - CONFIG_RW_SIG_SIZE)) { - CPRINTS("Invalid padding"); - return EC_ERROR_INVAL; - } - - rv = vboot_verify(data, len, key, sig); - if (rv) { - CPRINTS("Invalid data (%d)", rv); - return EC_ERROR_INVAL; - } - - CPRINTS("Verified %s", ec_image_to_string(slot)); - - return EC_SUCCESS; -} - -static enum ec_status hc_verify_slot(struct host_cmd_handler_args *args) -{ - const struct ec_params_efs_verify *p = args->params; - enum ec_image slot; - - switch (p->region) { - case EC_FLASH_REGION_ACTIVE: - slot = system_get_active_copy(); - break; - case EC_FLASH_REGION_UPDATE: - slot = system_get_update_copy(); - break; - default: - return EC_RES_INVALID_PARAM; - } - return verify_slot(slot) ? EC_RES_ERROR : EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_EFS_VERIFY, hc_verify_slot, EC_VER_MASK(0)); - -static int verify_and_jump(void) -{ - enum ec_image slot; - int rv; - - /* 1. Decide which slot to try */ - slot = system_get_active_copy(); - - /* 2. Verify the slot */ - rv = verify_slot(slot); - if (rv) { - if (rv == EC_ERROR_VBOOT_KEY) - /* Key error. The other slot isn't worth trying. */ - return rv; - slot = system_get_update_copy(); - /* TODO(chromium:767050): Skip reading key again. */ - rv = verify_slot(slot); - if (rv) - /* Both slots failed */ - return rv; - - /* Proceed with the other slot. If this slot isn't expected, AP - * will catch it and request recovery after a few attempts. */ - if (system_set_active_copy(slot)) - CPRINTS("Failed to activate %s", - ec_image_to_string(slot)); - } - - /* 3. Jump (and reboot) */ - rv = system_run_image_copy(slot); - CPRINTS("Failed to jump (%d)", rv); - - return rv; -} - -/* Request more power: charging battery or more powerful AC adapter */ -__overridable void show_power_shortage(void) -{ - CPRINTS("%s", __func__); -} - -__overridable void show_critical_error(void) -{ - CPRINTS("%s", __func__); -} - -static bool pd_comm_enabled; - -bool vboot_allow_usb_pd(void) -{ - return pd_comm_enabled; -} - -void vboot_main(void) -{ - CPRINTS("Main"); - - if (system_is_in_rw()) { - /* - * We come here and immediately return. LED shows power shortage - * but it will be immediately corrected if the adapter can - * provide enough power. - */ - CPRINTS("Already in RW. Wait for power..."); - show_power_shortage(); - return; - } - - if (!(crec_flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED)) { - /* - * If hardware WP is disabled, PD communication is enabled. - * We can return and wait for more power. - * Note: If software WP is disabled, we still perform EFS even - * though PD communication is enabled. - */ - CPRINTS("HW-WP not asserted."); - show_power_shortage(); - return; - } - - if (system_is_manual_recovery() || - (system_get_reset_flags() & EC_RESET_FLAG_STAY_IN_RO)) { - if (system_is_manual_recovery()) - CPRINTS("Manual recovery"); - - if (battery_is_present() || has_matrix_keyboard()) { - show_power_shortage(); - return; - } - /* We don't request_power because we don't want to assume all - * devices support a non type-c charger. We open up a security - * hole by allowing EC-RO to do PD negotiation but attackers - * don't gain meaningful advantage on devices without a matrix - * keyboard */ - CPRINTS("Enable PD comm"); - pd_comm_enabled = true; - return; - } - - clock_enable_module(MODULE_FAST_CPU, 1); - /* If successful, this won't return. */ - verify_and_jump(); - clock_enable_module(MODULE_FAST_CPU, 0); - - /* Failed to jump. Need recovery. */ - show_critical_error(); -} |