diff options
author | Namyoon Woo <namyoon@chromium.org> | 2020-02-28 09:44:46 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-09 21:48:18 +0000 |
commit | 5ccb5c7cc9c448b66c6f8e0abbb2dd785da0efb7 (patch) | |
tree | 84f6021a658d5b8b11c7612dafac86ede442b27a | |
parent | 97c73303cf9d5f6c8b6e871ddebd01a8e4ce4206 (diff) | |
download | chrome-ec-5ccb5c7cc9c448b66c6f8e0abbb2dd785da0efb7.tar.gz |
remove cr50 related files
BUG=b:149350081
BRANCH=none
TEST=build all, and emerged ec related packages for host and octopus.
$ make buildall -j
$ cros_workon --host list
chromeos-base/chromeos-cr50-dev
chromeos-base/chromeos-ec
chromeos-base/chromeos-ec-headers
chromeos-base/ec-devutils
chromeos-base/ec-utils
chromeos-base/ec-utils-test
dev-util/hdctools
$ sudo emerge chromeos-cr50-dev -j
$ sudo emerge chromeos-ec -j
$ sudo emerge chromeos-ec-headers -j
$ sudo emerge ec-devutils -j
$ sudo emerge ec-utils -j
$ sudo emerge ec-utils-test -j
$ sudo emerge hdctools -j
$ cros_workon-octopus list
chromeos-base/chromeos-ec
chromeos-base/chromeos-ec-headers
chromeos-base/ec-devutils
chromeos-base/ec-utils
chromeos-base/ec-utils-test
dev-util/hdctools
$ sudo emerge-octopus chromeos-ec -j
$ sudo emerge-octopus chromeos-ec-headers -j
$ sudo emerge-octopus ec-devutils -j
$ sudo emerge-octopus ec-utils -j
$ sudo emerge-octopus ec-utils-test -j
$ sudo emerge-octopus hdctools -j
Signed-off-by: Namyoon Woo <namyoon@chromium.org>
Change-Id: If751b26b0635b0021c077338e96eaa8e8dcf17a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2080631
Reviewed-by: Edward Hill <ecgh@chromium.org>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
69 files changed, 4 insertions, 22237 deletions
diff --git a/Makefile.rules b/Makefile.rules index c6851611c2..cf4d80c495 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -141,8 +141,7 @@ cmd_cp_script = cp "$<" "$@" && chmod +x "$@" cmd_libcryptoc_make = $(MAKE) --no-print-directory -C $(CRYPTOCLIB) \ obj=$(realpath $(out))/cryptoc \ - SUPPORT_UNALIGNED=1 \ - CONFIG_UPTO_SHA512=$(CONFIG_UPTO_SHA512) + SUPPORT_UNALIGNED=1 cmd_libcryptoc = $(cmd_libcryptoc_make) -q || $(cmd_libcryptoc_make) # commands for RSA signature: rwsig does not need to sign the whole image diff --git a/board/host/dcrypto.h b/board/host/dcrypto.h deleted file mode 100644 index 31f04e51aa..0000000000 --- a/board/host/dcrypto.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Provides the minimal declarations needed by pinweaver to build on - * CHIP_HOST. While it might be preferable to simply use the original dcrypto.h, - * That would require incorporating additional headers / dependencies such as - * cryptoc. - */ - -#ifndef __CROS_EC_DCRYPTO_HOST_H -#define __CROS_EC_DCRYPTO_HOST_H -#include <stdint.h> -#include <string.h> - -/* Allow tests to return a faked result for the purpose of testing. If - * this is not set, a combination of cryptoc and openssl are used for the - * dcrypto implementation. - */ -#ifndef CONFIG_DCRYPTO_MOCK - -/* If not using the mock struct definitions, use the ones from Cr50. */ -#include "chip/g/dcrypto/dcrypto.h" - -#else /* defined(CONFIG_DCRYPTO_MOCK) */ - -#include <sha256.h> - -#define HASH_CTX sha256_ctx - -/* Used as a replacement for declarations in cryptoc that are used by Cr50, but - * add unnecessary complexity to the test code. - */ -struct dcrypto_mock_ctx_t { - struct HASH_CTX hash; -}; -#define LITE_HMAC_CTX struct dcrypto_mock_ctx_t -#define LITE_SHA256_CTX struct HASH_CTX - -void HASH_update(struct HASH_CTX *ctx, const void *data, size_t len); -uint8_t *HASH_final(struct HASH_CTX *ctx); - -#define AES256_BLOCK_CIPHER_KEY_SIZE 32 -#define SHA256_DIGEST_SIZE 32 - -enum dcrypto_appid { - RESERVED = 0, - NVMEM = 1, - U2F_ATTEST = 2, - U2F_ORIGIN = 3, - U2F_WRAP = 4, - PERSO_AUTH = 5, - PINWEAVER = 6, - /* This enum value should not exceed 7. */ -}; - -void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required); - -void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, - unsigned int len); -const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx); - -int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits, - const uint8_t *iv, const uint8_t *in, size_t in_len); - -struct APPKEY_CTX {}; - -int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx); - -void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx); - -int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], - uint32_t output[8]); - -#endif /* CONFIG_DCRYPTO_MOCK */ - -#endif /* __CROS_EC_HOST_DCRYPTO_H */ diff --git a/chip/host/build.mk b/chip/host/build.mk index 9d77937776..8d2d69f3c3 100644 --- a/chip/host/build.mk +++ b/chip/host/build.mk @@ -16,18 +16,6 @@ chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o endif chip-$(CONFIG_USB_PD_TCPC)+=usb_pd_phy.o -ifeq ($(CONFIG_DCRYPTO),y) -CPPFLAGS += -I$(abspath ./chip/g) -dirs-y += chip/g/dcrypto -endif dirs-y += chip/host/dcrypto chip-$(CONFIG_I2C)+= i2c.o - -chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o -chip-$(CONFIG_DCRYPTO)+= dcrypto/app_cipher.o -chip-$(CONFIG_DCRYPTO)+= dcrypto/app_key.o -chip-$(CONFIG_DCRYPTO)+= dcrypto/sha256.o - -# Object files that can be shared with the Cr50 dcrypto implementation -chip-$(CONFIG_DCRYPTO)+= ../g/dcrypto/hmac.o diff --git a/chip/host/dcrypto/README.md b/chip/host/dcrypto/README.md deleted file mode 100644 index 6812dde311..0000000000 --- a/chip/host/dcrypto/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Rough Dcrypto Implementation on Host for Fuzzing Targets. - -This implementation of the dcrypto API is not complete, but provides the needed -function definitions to fuzz Cr50 code. -The the following should be noted: -* A complete implementation of dcrypto does not add any extra coverage since the - dcrypto code here doesn't match the Cr50 implementation that depends on - a specific hardware accelerator. -* The input data comes from a fuzzer so storage encryption isn't necessary—no - user data is handled. -* For fuzzing fully implementing the crypto functionality isn't useful for the - purpose of finding bugs--it makes the fuzzer take longer to execute without - providing any benefit for the extra cycles. diff --git a/chip/host/dcrypto/aes.c b/chip/host/dcrypto/aes.c deleted file mode 100644 index cc57168cbb..0000000000 --- a/chip/host/dcrypto/aes.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright 2018 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 <openssl/evp.h> - -#define HIDE_EC_STDLIB - -#include "dcrypto.h" -#include "registers.h" - -int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits, - const uint8_t *iv, const uint8_t *in, size_t in_len) -{ - EVP_CIPHER_CTX *ctx; - int ret = 0; - int out_len = 0; - - ctx = EVP_CIPHER_CTX_new(); - if (!ctx) - return 0; - - if (EVP_EncryptInit_ex(ctx, EVP_aes_256_ctr(), NULL, key, iv) != 1) - goto cleanup; - - if (EVP_EncryptUpdate(ctx, out, &out_len, in, in_len) != 1) - goto cleanup; - - if (EVP_EncryptFinal(ctx, out + out_len, &out_len) != 1) - goto cleanup; - ret = 1; - -cleanup: - EVP_CIPHER_CTX_free(ctx); - return ret; -} diff --git a/chip/host/dcrypto/app_cipher.c b/chip/host/dcrypto/app_cipher.c deleted file mode 100644 index ab52484753..0000000000 --- a/chip/host/dcrypto/app_cipher.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2018 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 "dcrypto.h" -#include "util.h" - -void app_compute_hash(uint8_t *p_buf, size_t num_bytes, - uint8_t *p_hash, size_t hash_len) -{ - uint8_t digest[SHA256_DIGEST_SIZE]; - - /* - * Use the built in dcrypto engine to generate the sha1 hash of the - * buffer. - */ - DCRYPTO_SHA256_hash((uint8_t *)p_buf, num_bytes, digest); - - memcpy(p_hash, digest, MIN(hash_len, sizeof(digest))); - - if (hash_len > sizeof(digest)) - memset(p_hash + sizeof(digest), 0, - hash_len - sizeof(digest)); -} - -int app_cipher(const void *salt_p, void *out_p, const void *in_p, size_t size) -{ - /* See README.md for why this is not a real encryption.. */ - size_t i; - const uint8_t *src; - const uint8_t *salt; - uint8_t *dst; - - src = in_p; - salt = salt_p; - dst = out_p; - - for (i = 0; i < size; i++) - dst[i] = src[i] ^ salt[i & 7]; - - return 1; -} - -int crypto_enabled(void) -{ - return 1; -} diff --git a/chip/host/dcrypto/app_key.c b/chip/host/dcrypto/app_key.c deleted file mode 100644 index 58066c84ba..0000000000 --- a/chip/host/dcrypto/app_key.c +++ /dev/null @@ -1,31 +0,0 @@ -/* Copyright 2018 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 "dcrypto.h" - -static int dcrypto_appkey_init_flag_ = -1; - -int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx) -{ - if (dcrypto_appkey_init_flag_ != -1) - return 0; - - dcrypto_appkey_init_flag_ = appid; - return 1; -} - -void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx) -{ - memset(ctx, 0, sizeof(struct APPKEY_CTX)); - dcrypto_appkey_init_flag_ = -1; -} - -int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], - uint32_t output[8]) -{ - /* See README.md for while this is a passthrough. */ - memcpy(output, input, SHA256_DIGEST_SIZE); - return 1; -} diff --git a/chip/host/dcrypto/sha256.c b/chip/host/dcrypto/sha256.c deleted file mode 100644 index 429588c8ac..0000000000 --- a/chip/host/dcrypto/sha256.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright 2018 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 "dcrypto.h" - -void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required) -{ - SHA256_init(ctx); -} - -const uint8_t *DCRYPTO_SHA256_hash(const void *data, uint32_t n, - uint8_t *digest) -{ - SHA256_hash(data, n, digest); - return digest; -} diff --git a/common/build.mk b/common/build.mk index a931b10890..5948e08d51 100644 --- a/common/build.mk +++ b/common/build.mk @@ -41,7 +41,6 @@ common-$(CONFIG_BATTERY_FUEL_GAUGE)+=battery_fuel_gauge.o common-$(CONFIG_BLUETOOTH_LE)+=bluetooth_le.o common-$(CONFIG_BLUETOOTH_LE_STACK)+=btle_hci_controller.o btle_ll.o common-$(CONFIG_CAPSENSE)+=capsense.o -common-$(CONFIG_CASE_CLOSED_DEBUG_V1)+=ccd_config.o common-$(CONFIG_CEC)+=cec.o common-$(CONFIG_CROS_BOARD_INFO)+=cbi.o common-$(CONFIG_CHARGE_MANAGER)+=charge_manager.o @@ -68,15 +67,9 @@ common-$(CONFIG_DPTF)+=dptf.o common-$(CONFIG_EC_EC_COMM_MASTER)+=ec_ec_comm_master.o common-$(CONFIG_EC_EC_COMM_SLAVE)+=ec_ec_comm_slave.o common-$(CONFIG_HOSTCMD_ESPI)+=espi.o -common-$(CONFIG_EXTENSION_COMMAND)+=extension.o common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o common-$(CONFIG_FANS)+=fan.o pwm.o -common-$(CONFIG_FACTORY_MODE)+=factory_mode.o common-$(CONFIG_FLASH)+=flash.o -common-$(CONFIG_FLASH_LOG)+=flash_log.o flash_log_vc.o -common-$(CONFIG_FLASH_NVMEM)+=nvmem.o -common-$(CONFIG_FLASH_NVMEM)+=new_nvmem.o -common-$(CONFIG_FLASH_NVMEM_VARS)+=nvmem_vars.o common-$(CONFIG_FMAP)+=fmap.o common-$(CONFIG_GESTURE_SW_DETECTION)+=gesture.o common-$(CONFIG_HOSTCMD_EVENTS)+=host_event_commands.o @@ -106,8 +99,6 @@ common-$(CONFIG_MAG_CALIBRATE)+= mag_cal.o math_util.o vec3.o mat33.o mat44.o \ common-$(CONFIG_MKBP_EVENT)+=mkbp_event.o common-$(CONFIG_ONEWIRE)+=onewire.o common-$(CONFIG_PECI_COMMON)+=peci.o -common-$(CONFIG_PHYSICAL_PRESENCE)+=physical_presence.o -common-$(CONFIG_PINWEAVER)+=pinweaver.o common-$(CONFIG_POWER_BUTTON)+=power_button.o common-$(CONFIG_POWER_BUTTON_X86)+=power_button_x86.o common-$(CONFIG_PSTORE)+=pstore_commands.o @@ -136,8 +127,6 @@ common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o common-$(CONFIG_THROTTLE_AP)+=thermal.o throttle_ap.o common-$(CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT)+=throttle_ap.o common-$(CONFIG_THROTTLE_AP_ON_BAT_VOLTAGE)+=throttle_ap.o -common-$(CONFIG_TPM_I2CS)+=i2cs_tpm.o -common-$(CONFIG_U2F)+=u2f.o common-$(CONFIG_USB_CHARGER)+=usb_charger.o common-$(CONFIG_USB_CONSOLE_STREAM)+=usb_console_stream.o common-$(CONFIG_USB_I2C)+=usb_i2c.o @@ -172,7 +161,6 @@ common-$(HAS_TASK_PDCMD)+=host_command_pd.o common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o common-$(HAS_TASK_LIGHTBAR)+=lb_common.o lightbar.o common-$(HAS_TASK_MOTIONSENSE)+=motion_sense.o -common-$(HAS_TASK_TPM)+=tpm_registers.o ifneq ($(HAVE_PRIVATE_AUDIO_CODEC_WOV_LIBS),y) common-$(CONFIG_AUDIO_CODEC_WOV)+=hotword_dsp_api.o diff --git a/common/ccd_config.c b/common/ccd_config.c deleted file mode 100644 index 91232df295..0000000000 --- a/common/ccd_config.c +++ /dev/null @@ -1,1553 +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. - * - * Case Closed Debug configuration - */ - -#include "common.h" -#include "byteorder.h" -#include "ccd_config.h" -#include "console.h" -#include "cryptoc/sha256.h" -#include "cryptoc/util.h" -#include "dcrypto.h" -#include "extension.h" -#include "hooks.h" -#include "nvmem_vars.h" -#include "physical_presence.h" -#include "system.h" -#include "system_chip.h" -#include "task.h" -#include "timer.h" -#include "tpm_registers.h" -#include "tpm_vendor_cmds.h" -#include "trng.h" -#include "wp.h" - -#define CPRINTS(format, args...) cprints(CC_CCD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_CCD, format, ## args) - -/* Let's make sure that CCD capability state enum fits into two bits. */ -BUILD_ASSERT(CCD_CAP_STATE_COUNT <= 4); - -/* Restriction state for ccdunlock when no password is set */ -enum ccd_unlock_restrict { - /* Unrestricted */ - CCD_UNLOCK_UNRESTRICTED = 0, - - /* Physical presence required for unlock unless disabled by config */ - CCD_UNLOCK_NEED_PP, - - /* Unlock not allowed */ - CCD_UNLOCK_DISABLED -}; - -/* Minimum time between password attempts */ -#define PASSWORD_RATE_LIMIT_US (3 * SECOND) - -/* Current version of case-closed debugging configuration struct */ -#define CCD_CONFIG_VERSION 0x10 - -/* - * CCD command header; including the subcommand code used to demultiplex - * various CCD commands over the same TPM vendor command. - */ -struct ccd_vendor_cmd_header { - struct tpm_cmd_header tpm_header; - - /* On input, the subcommand. On output, may contain EC return code */ - uint8_t ccd_subcommand; -} __packed; - -/* Size of password salt and digest in bytes */ -#define CCD_PASSWORD_SALT_SIZE 4 -#define CCD_PASSWORD_DIGEST_SIZE 16 - -/* Way longer than practical. */ -#define CCD_MAX_PASSWORD_SIZE 40 - -struct ccd_config { - /* Version (CCD_CONFIG_VERSION) */ - uint8_t version; - - /* - * Flags. These MUST immediately follow version, so that the test - * lab flag is always the LSBit of the first flags byte. - */ - uint8_t flags[3]; - - /* Capabilities */ - uint8_t capabilities[8]; - - /* Password salt (random) */ - uint8_t password_salt[CCD_PASSWORD_SALT_SIZE]; - - /* - * Password digest = truncated - * SHA256_digest(password_salt+device_id+password) - */ - uint8_t password_digest[CCD_PASSWORD_DIGEST_SIZE]; -}; - -/* Nvmem variable name for CCD config */ -static const uint8_t k_ccd_config = NVMEM_VAR_CCD_CONFIG; - -/* Flags which can be set via ccd_set_flag() */ -static const uint32_t k_public_flags = - CCD_FLAG_OVERRIDE_WP_AT_BOOT | - CCD_FLAG_OVERRIDE_WP_STATE_ENABLED | - CCD_FLAG_OVERRIDE_BATT_AT_BOOT | - CCD_FLAG_OVERRIDE_BATT_STATE_CONNECT; - -/* List of CCD capability info; must be in same order as enum ccd_capability */ -static const struct ccd_capability_info cap_info[CCD_CAP_COUNT] = CAP_INFO_DATA; - -static const char *ccd_state_names[CCD_STATE_COUNT] = CCD_STATE_NAMES; -static const char *ccd_cap_state_names[CCD_CAP_STATE_COUNT] = - CCD_CAP_STATE_NAMES; - -static enum ccd_state ccd_state = CCD_STATE_LOCKED; -static struct ccd_config config; -static uint8_t ccd_config_loaded; -static uint8_t force_disabled; -static struct mutex ccd_config_mutex; -static uint8_t ccd_console_active; /* CCD console command is in progress. */ - -/******************************************************************************/ -/* Raw config accessors */ - -/** - * Get CCD flags. - * - * @return the current flags mask. - */ -static uint32_t raw_get_flags(void) -{ - return (uint32_t)(config.flags[0] << 0) - | ((uint32_t)config.flags[1] << 8) - | ((uint32_t)config.flags[2] << 16); -} - -/** - * Set a single CCD flag. - * - * This does NOT call ccd_save_config() or lock the mutex. Caller must do - * those. - * - * @param flag Flag to set - * @param value New value for flag (0=clear, non-zero=set) - */ -static void raw_set_flag(enum ccd_flag flag, int value) -{ - uint32_t f; - - f = raw_get_flags(); - if (value) - f |= flag; - else - f &= ~flag; - - config.flags[0] = (uint8_t)(f >> 0); - config.flags[1] = (uint8_t)(f >> 8); - config.flags[2] = (uint8_t)(f >> 16); -} - -/** - * Get a raw capability state from the config - * - * @param cap Capability to check - * @param translate_default If non-zero, translate CCD_CAP_STATE_DEFAULT - * to the actual default for that config - * @return The capability state. - */ -static enum ccd_capability_state raw_get_cap(enum ccd_capability cap, - int translate_default) -{ - const uint32_t index = cap / CCD_CAPS_PER_BYTE; - const uint32_t shift = (cap % CCD_CAPS_PER_BYTE) * CCD_CAP_BITS; - - int c = (config.capabilities[index] >> shift) & CCD_CAP_BITMASK; - - if (c == CCD_CAP_STATE_DEFAULT && translate_default) - c = cap_info[cap].default_state; - - return c; -} - -/** - * Set a raw capability to the config. - * - * This does NOT call ccd_save_config() or lock the mutex. Caller must do - * those. - * - * @param cap Capability to set - * @param state New state for capability - */ -static void raw_set_cap(enum ccd_capability cap, - enum ccd_capability_state state) -{ - const uint32_t index = cap / CCD_CAPS_PER_BYTE; - const uint32_t shift = (cap % CCD_CAPS_PER_BYTE) * CCD_CAP_BITS; - - config.capabilities[index] &= ~(CCD_CAP_BITMASK << shift); - config.capabilities[index] |= (state & CCD_CAP_BITMASK) << shift; -} - -/** - * Check CCD configuration is reset to default value. - * - * @return 1 if it is in default mode. - * 0 otherwise. - */ -static int raw_check_all_caps_default(void) -{ - uint32_t i; - - for (i = 0; i < CCD_CAP_COUNT; i++) - if (raw_get_cap(i, 0) != CCD_CAP_STATE_DEFAULT) - return 0; - - return 1; -} - -/** - * Check if a password is set. - * @return 1 if password is set, 0 if it's not - */ -static int raw_has_password(void) -{ - uint8_t set = 0; - int i; - - /* Password is set unless salt and digest are all zero */ - for (i = 0; i < sizeof(config.password_salt); i++) - set |= config.password_salt[i]; - for (i = 0; i < sizeof(config.password_digest); i++) - set |= config.password_digest[i]; - - return !!set; -} - -/** - * Calculate the expected digest for a password. - * - * Uses the unique device ID and the salt from the config. - * - * @param digest Pointer to a CCD_PASSWORD_DIGEST_SIZE buffer - * @param password The password to digest - */ -static void ccd_password_digest(uint8_t *digest, const char *password) -{ - HASH_CTX sha; - uint8_t *unique_id; - int unique_id_len; - - unique_id_len = system_get_chip_unique_id(&unique_id); - - DCRYPTO_SHA256_init(&sha, 0); - HASH_update(&sha, config.password_salt, sizeof(config.password_salt)); - HASH_update(&sha, unique_id, unique_id_len); - HASH_update(&sha, password, strlen(password)); - memcpy(digest, HASH_final(&sha), CCD_PASSWORD_DIGEST_SIZE); -} - -/** - * Check the password. - * - * @param password The password to check - * @return EC_SUCCESS, EC_ERROR_BUSY if too soon since last attempt, or - * EC_ERROR_ACCESS_DENIED if mismatch. - */ -static int raw_check_password(const char *password) -{ - /* - * Time of last password attempt; initialized to 0 at boot. Yes, we're - * only keeping the bottom 32 bits of the timer here, so on a - * wraparound (every ~4000 seconds) it's possible for an attacker to - * get one extra attempt. But it still behaves properly at boot, - * requiring the system to be up PASSWORD_RATE_LIMIT_US before allowing - * the first attempt. - */ - static uint32_t last_password_time; - - uint8_t digest[CCD_PASSWORD_DIGEST_SIZE]; - uint32_t t; - - /* If no password is set, match only an empty password */ - if (!raw_has_password()) - return *password ? EC_ERROR_ACCESS_DENIED : EC_SUCCESS; - - /* Rate limit password attempts */ - t = get_time().le.lo; - if (t - last_password_time < PASSWORD_RATE_LIMIT_US) - return EC_ERROR_BUSY; - last_password_time = t; - - /* Calculate the digest of the password */ - ccd_password_digest(digest, password); - - if (safe_memcmp(digest, config.password_digest, - sizeof(config.password_digest))) - return EC_ERROR_ACCESS_DENIED; - - return EC_SUCCESS; -} - -/** - * Clear the password. - * - * This does NOT call ccd_save_config() or lock the mutex. Caller must do - * those. - */ -static void raw_reset_password(void) -{ - memset(config.password_salt, 0, sizeof(config.password_salt)); - memset(config.password_digest, 0, sizeof(config.password_digest)); - raw_set_flag(CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED, 0); -} - -/** - * Set the password. - * - * @param password New password; must be non-empty - */ -static void raw_set_password(const char *password) -{ - /* Get a new salt */ - rand_bytes(config.password_salt, sizeof(config.password_salt)); - - /* Update the password digest */ - ccd_password_digest(config.password_digest, password); - - /* Track whether we were opened when we set the password */ - raw_set_flag(CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED, - ccd_state == CCD_STATE_UNLOCKED); -} - -/******************************************************************************/ -/* Internal methods */ - -/** - * Set the CCD state. - * - * @param state New CCD state - */ -static void ccd_set_state(enum ccd_state state) -{ - if (state == ccd_state) - return; - - ccd_state = state; - - /* Notify CCD users of configuration change */ - hook_notify(HOOK_CCD_CHANGE); -} - -/** - * Load CCD config from nvmem_vars - * - * @return EC_SUCCESS or non-zero error code. - */ -static void ccd_load_config(void) -{ - const struct tuple *t; - - /* Don't reload if we're already loaded */ - if (ccd_config_loaded) - return; - - /* Load config data from nvmem */ - t = getvar(&k_ccd_config, sizeof(k_ccd_config)); - - /* Use defaults if config data is not present */ - if (!t) { - if (board_is_first_factory_boot()) { - /* Give factory/RMA access */ - CPRINTS("CCD using factory config"); - ccd_reset_config(CCD_RESET_FACTORY); - } else { - /* Somehow we lost our config; normal defaults */ - CPRINTS("CCD using default config"); - ccd_reset_config(CCD_RESET_TEST_LAB); - } - goto ccd_is_loaded; - } - - /* Copy the tuple data */ - memcpy(&config, tuple_val(t), MIN(sizeof(config), t->val_len)); - - /* If version or size is wrong, reset to defaults */ - if (config.version != CCD_CONFIG_VERSION || - t->val_len != sizeof(config)) { - CPRINTS("CCD config mismatch; using defaults"); - /* - * If the config data was big enough to hold the test lab bit, - * preserve it. That's guaranteed to be in the same place for - * all data versions. - */ - ccd_reset_config(t->val_len < 2 ? CCD_RESET_TEST_LAB : 0); - } - - freevar(t); - -ccd_is_loaded: - ccd_config_loaded = 1; - - /* Notify CCD users of configuration change */ - hook_notify(HOOK_CCD_CHANGE); -} - -/** - * Save CCD config to nvmem_vars - * - * @return EC_SUCCESS or non-zero error code. - */ -static int ccd_save_config(void) -{ - int rv; - - rv = setvar(&k_ccd_config, sizeof(k_ccd_config), - (const uint8_t *)&config, sizeof(config)); - if (rv) - return rv; - - /* - * Notify CCD users of configuration change. - * Protect this notify with the ccd_config_loaded flag so recipients of - * HOOK_CCD_CHANGE don't call ccd_get/ccd_set before the CCD - * initialization is complete. - */ - if (ccd_config_loaded) - hook_notify(HOOK_CCD_CHANGE); - - return rv; -} - -/** - * Set a CCD capability to a new state. - * - * @param cap Capability to set - * @param state New state for capability - * @return EC_SUCCESS or non-zero error code. - */ -static int ccd_set_cap(enum ccd_capability cap, enum ccd_capability_state state) -{ - if (!ccd_config_loaded) - return EC_ERROR_BUSY; - - if (state == raw_get_cap(cap, 0)) - return EC_SUCCESS; /* Capability not changed */ - - mutex_lock(&ccd_config_mutex); - raw_set_cap(cap, state); - mutex_unlock(&ccd_config_mutex); - - return ccd_save_config(); -} - -int ccd_reset_config(unsigned int flags) -{ - int old_lab = ccd_get_flag(CCD_FLAG_TEST_LAB); - - mutex_lock(&ccd_config_mutex); - - if (flags & CCD_RESET_UNLOCKED_ONLY) { - /* Only set config options that are mutable when unlocked */ - int i; - - /* Reset the password if it was set when unlocked */ - if (ccd_get_flag(CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED)) - raw_reset_password(); - - /* Reset all capabilities that aren't IfOpened */ - for (i = 0; i < CCD_CAP_COUNT; i++) { - if (raw_get_cap(i, 1) == CCD_CAP_STATE_IF_OPENED) - continue; - raw_set_cap(i, CCD_CAP_STATE_DEFAULT); - } - - /* Flags all require IfOpened, so don't touch those */ - } else { - /* Reset the entire config */ - memset(&config, 0, sizeof(config)); - config.version = CCD_CONFIG_VERSION; - /* Update write protect after resetting the config */ - board_wp_follow_ccd_config(); - } - - if (flags & CCD_RESET_FACTORY) { - /* Force factory mode settings */ - int i; - - /* Allow all capabilities all the time */ - for (i = 0; i < CCD_CAP_COUNT; i++) - raw_set_cap(i, CCD_CAP_STATE_ALWAYS); - - raw_set_flag(CCD_FLAG_FACTORY_MODE_ENABLED, 1); - - /* Force WP disabled at boot */ - raw_set_flag(CCD_FLAG_OVERRIDE_WP_AT_BOOT, 1); - raw_set_flag(CCD_FLAG_OVERRIDE_WP_STATE_ENABLED, 0); - board_wp_follow_ccd_config(); - } - - /* Restore test lab flag unless explicitly resetting it */ - if (!(flags & CCD_RESET_TEST_LAB)) - raw_set_flag(CCD_FLAG_TEST_LAB, old_lab); - - mutex_unlock(&ccd_config_mutex); - - return ccd_save_config(); -} - -/** - * Convert a string to a capability index. - * - * @param name Capability name to find - * @return The capability index, or CCD_CAP_COUNT if error - */ -static enum ccd_capability ccd_cap_from_name(const char *name) -{ - int i; - - for (i = 0; i < CCD_CAP_COUNT; i++) { - if (!strcasecmp(name, cap_info[i].name)) - return i; - } - - return CCD_CAP_COUNT; -} - -/** - * Reset the password. - * - * @return EC_SUCCESS or non-zero error code. - */ -static int ccd_reset_password(void) -{ - mutex_lock(&ccd_config_mutex); - raw_reset_password(); - mutex_unlock(&ccd_config_mutex); - - return ccd_save_config(); -} - -/** - * Set the password. - * - * @param password New password; must be non-empty - * @return EC_SUCCESS or non-zero error code. - */ -static int ccd_set_password(const char *password) -{ - mutex_lock(&ccd_config_mutex); - raw_set_password(password); - mutex_unlock(&ccd_config_mutex); - - return ccd_save_config(); -} - -/******************************************************************************/ -/* Handlers for state changes requiring physical presence */ - -/* - * Could be invoked synchronously on the TPM task context, or asynchronously, - * after physical presence is established, on the hooks task context. - * - * The appropriate TPM reset entry point needs to be invoked. Also, make sure - * that the board is always rebooted when TPM is reset. - * - * @param sync Non-zero to invoke synchronously. - */ -static void ccd_open_done(int sync) -{ - int rv; - - /* - * Wiping the TPM may take a while. Delay sleep long enough for the - * open process to finish. - */ - delay_sleep_by(DISABLE_SLEEP_TIME_TPM_WIPE); - - if (!ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_TPM_WIPE)) { - /* Can't open unless wipe succeeds */ - if (sync) - rv = tpm_sync_reset(1); - else - rv = board_wipe_tpm(1); - - if (rv != EC_SUCCESS) { - CPRINTS("CCD open TPM wipe failed"); - return; - } - } - - if (!ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT) || - (!ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_TPM_WIPE) && sync)) - board_reboot_ap(); - - CPRINTS("CCD opened"); - ccd_set_state(CCD_STATE_OPENED); -} - -static void ccd_open_done_async(void) -{ - ccd_open_done(0); -} - -static void ccd_unlock_done(void) -{ - if (!ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT)) - board_reboot_ap(); - - CPRINTS("CCD unlocked"); - ccd_set_state(CCD_STATE_UNLOCKED); -} - -static void ccd_testlab_toggle(void) -{ - int v = !ccd_get_flag(CCD_FLAG_TEST_LAB); - - /* Use raw_set_flag() because the test lab flag is internal */ - mutex_lock(&ccd_config_mutex); - raw_set_flag(CCD_FLAG_TEST_LAB, v); - mutex_unlock(&ccd_config_mutex); - - if (ccd_save_config() == EC_SUCCESS) - CPRINTS("CCD test lab mode %sbled", v ? "ena" : "disa"); - else - CPRINTS("Error setting CCD test lab mode!"); -} - -/******************************************************************************/ -/* External interface */ - -int ccd_has_password(void) -{ - return raw_has_password(); -} - -void ccd_config_init(enum ccd_state state) -{ - /* Set initial state, after making sure it's a valid one */ - if (state != CCD_STATE_UNLOCKED && state != CCD_STATE_OPENED) - state = CCD_STATE_LOCKED; - ccd_state = state; - - ccd_load_config(); -} - -int ccd_get_flag(enum ccd_flag flag) -{ - uint32_t f = raw_get_flags(); - - if (!ccd_config_loaded || force_disabled) - return 0; - - return !!(f & flag); -} - -int ccd_set_flag(enum ccd_flag flag, int value) -{ - if (force_disabled) - return EC_ERROR_ACCESS_DENIED; - - /* Fail if trying to set a private flag */ - if (flag & ~k_public_flags) - return EC_ERROR_ACCESS_DENIED; - - if (!ccd_config_loaded) - return EC_ERROR_BUSY; - - if (ccd_get_flag(flag) == !!value) - return EC_SUCCESS; - - mutex_lock(&ccd_config_mutex); - raw_set_flag(flag, value); - mutex_unlock(&ccd_config_mutex); - return ccd_save_config(); -} - -int ccd_is_cap_enabled(enum ccd_capability cap) -{ - if (!ccd_config_loaded || force_disabled) - return 0; - - switch (raw_get_cap(cap, 1)) { - case CCD_CAP_STATE_ALWAYS: - return 1; - case CCD_CAP_STATE_UNLESS_LOCKED: - return ccd_state != CCD_STATE_LOCKED; - case CCD_CAP_STATE_IF_OPENED: - default: - return ccd_state == CCD_STATE_OPENED; - } -} - -enum ccd_state ccd_get_state(void) -{ - return ccd_state; -} - -void ccd_disable(void) -{ - CPRINTS("CCD disabled"); - force_disabled = 1; - ccd_set_state(CCD_STATE_LOCKED); -} - -int ccd_get_factory_mode(void) -{ - return ccd_get_flag(CCD_FLAG_FACTORY_MODE_ENABLED); -} - -/******************************************************************************/ -/* Console commands */ - -static int command_ccd_info(void) -{ - int i; - - ccprintf("State: %s%s\n", ccd_state_names[ccd_state], - force_disabled ? " (Disabled)" : ""); - ccprintf("Password: %s\n", raw_has_password() ? "set" : "none"); - ccprintf("Flags: 0x%06x\n", raw_get_flags()); - - ccprintf("Capabilities: %ph\n", HEX_BUF(config.capabilities, 8)); - for (i = 0; i < CCD_CAP_COUNT; i++) { - int c = raw_get_cap(i, 0); - - ccprintf(" %-15s %c %d=%s", - cap_info[i].name, - ccd_is_cap_enabled(i) ? 'Y' : '-', - c, ccd_cap_state_names[c]); - if (c == CCD_CAP_STATE_DEFAULT) - ccprintf(" (%s)", - ccd_cap_state_names[cap_info[i].default_state]); - ccprintf("\n"); - cflush(); - } - - ccprintf("TPM:%s%s\n", - board_fwmp_allows_unlock() ? "" : " fwmp_lock", - board_vboot_dev_mode_enabled() ? " dev_mode" : ""); - - ccprintf("Capabilities are %s.\n", raw_check_all_caps_default() ? - "default" : "modified"); - - ccputs("Use 'ccd help' to print subcommands\n"); - return EC_SUCCESS; -} - -static int command_ccd_reset(int argc, char **argv) -{ - int flags = 0; - - if (argc > 1) { - if (!strcasecmp(argv[1], "factory")) - flags = CCD_RESET_FACTORY; - else - return EC_ERROR_PARAM1; - } - - switch (ccd_state) { - case CCD_STATE_OPENED: - ccprintf("%s settings.\n", flags & CCD_RESET_FACTORY ? - "Opening factory " : "Resetting all"); - /* Note that this does not reset the testlab flag */ - return ccd_reset_config(flags); - - case CCD_STATE_UNLOCKED: - ccprintf("Resetting unlocked settings.\n"); - return ccd_reset_config(CCD_RESET_UNLOCKED_ONLY); - - default: - return EC_ERROR_ACCESS_DENIED; - } -} - -static int command_ccd_set(int argc, char **argv) -{ - enum ccd_capability cap; - enum ccd_capability_state old; - enum ccd_capability_state new; - - /* Only works if unlocked or opened */ - if (ccd_state == CCD_STATE_LOCKED) - return EC_ERROR_ACCESS_DENIED; - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - /* Get capability to set */ - cap = ccd_cap_from_name(argv[1]); - if (cap == CCD_CAP_COUNT) - return EC_ERROR_PARAM1; - - /* Get new state */ - for (new = CCD_CAP_STATE_DEFAULT; new < CCD_CAP_STATE_COUNT; new++) { - if (!strcasecmp(argv[2], ccd_cap_state_names[new])) - break; - } - if (new == CCD_CAP_STATE_COUNT) - return EC_ERROR_PARAM2; - - /* Get current state */ - old = raw_get_cap(cap, 1); - - /* If we're only unlocked, can't change to/from IfOpened */ - if (ccd_state == CCD_STATE_UNLOCKED && - (new == CCD_CAP_STATE_IF_OPENED || old == CCD_CAP_STATE_IF_OPENED)) - return EC_ERROR_ACCESS_DENIED; - - /* Set new state */ - return ccd_set_cap(cap, new); -} - -static int do_ccd_password(char *password) -{ - /* Only works if unlocked or opened */ - if (ccd_state == CCD_STATE_LOCKED) - return EC_ERROR_ACCESS_DENIED; - - if (raw_has_password()) { - const char clear_prefix[] = {'c', 'l', 'e', 'a', 'r', ':'}; - - /* - * The only allowed action at this point is to clear the - * password. To do it the user is supposed to enter - * 'clear:<passwd>' - */ - if (strncasecmp(password, clear_prefix, sizeof(clear_prefix))) - return EC_ERROR_ACCESS_DENIED; - - if (raw_check_password(password + sizeof(clear_prefix)) != - EC_SUCCESS) - return EC_ERROR_ACCESS_DENIED; - - return ccd_reset_password(); - } - - /* Set new password */ - return ccd_set_password(password); -} - -/* - * Common wrapper for CCD commands which are passed through the TPM task - * context. - * - * All commands could have a single parameter, which is the password (to be - * set, cleared, or entered to open/unlock). If argc value exceeds 1, the - * pointer to password is set, it is checked not to exceed maximum size. - * - * If the check succeeds, prepare a message containing a TPM vendor command, - * have the TPM task process the message and report the result to the caller. - * - * Message header is always the same, the payload is the password, if - * supplied. - * - * Expected output is nothing on success, or a single byte EC return code. - */ -static int ccd_command_wrapper(int argc, char *password, - enum ccd_vendor_subcommands subcmd) -{ - uint8_t buf[sizeof(struct ccd_vendor_cmd_header) + - CCD_MAX_PASSWORD_SIZE]; - struct ccd_vendor_cmd_header *vch = (struct ccd_vendor_cmd_header *)buf; - size_t password_size = 0; - uint32_t return_code; - - if (argc > 1) { - password_size = strlen(password); - if (password_size > CCD_MAX_PASSWORD_SIZE) - return EC_ERROR_PARAM1; - } - - /* Build the extension command to set/clear CCD password. */ - vch->tpm_header.tag = htobe16(0x8001); /* TPM_ST_NO_SESSIONS */ - vch->tpm_header.size = htobe32(sizeof(*vch) + password_size); - vch->tpm_header.command_code = htobe32(TPM_CC_VENDOR_BIT_MASK); - vch->tpm_header.subcommand_code = htobe16(VENDOR_CC_CCD); - vch->ccd_subcommand = subcmd; - - memcpy(vch + 1, password, password_size); - tpm_alt_extension(&vch->tpm_header, sizeof(buf)); - - /* - * Return status in the command code field now, in case of error, - * error code is the first byte after the header. - */ - return_code = be32toh(vch->tpm_header.command_code); - if ((return_code != VENDOR_RC_SUCCESS) && - (return_code != (VENDOR_RC_IN_PROGRESS|VENDOR_RC_ERR))) { - return vch->ccd_subcommand; - } - return EC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_open(struct vendor_cmd_params *p) -{ - int is_long = 1; - int need_pp = 1; - int rv; - char *buffer = p->buffer; - const char *why_denied = "forced"; - - if (force_disabled) - goto denied; - - if (ccd_state == CCD_STATE_OPENED) - return VENDOR_RC_SUCCESS; - - /* FWMP blocks open even if a password is set */ - if (!board_fwmp_allows_unlock()) { - why_denied = "fwmp"; - goto denied; - } - - /* Make sure open is allowed */ - if (raw_has_password()) { - /* Open allowed if correct password is specified */ - - if (!p->in_size) { - /* ...which it wasn't */ - p->out_size = 1; - buffer[0] = EC_ERROR_PARAM_COUNT; - return VENDOR_RC_PASSWORD_REQUIRED; - } - - /* - * We know there is plenty of room in the TPM buffer this is - * stored in. - */ - buffer[p->in_size] = '\0'; - rv = raw_check_password(buffer); - if (rv) { - p->out_size = 1; - buffer[0] = rv; - return VENDOR_RC_INTERNAL_ERROR; - } - } else if (!board_battery_is_present()) { - /* Open allowed with no password if battery is removed */ - } else if ((ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_DEV_MODE) || - (board_vboot_dev_mode_enabled())) && - (ccd_is_cap_enabled(CCD_CAP_OPEN_FROM_USB) || - !(p->flags & VENDOR_CMD_FROM_USB))) { - /* - * Open allowed with no password if dev mode enabled and - * command came from the AP. CCD capabilities can be used to - * bypass these checks. - */ - } else { - /* - * - Battery is present - * - Either not in developer mode or the command came from USB - */ - why_denied = "open from AP in devmode or remove batt"; - goto denied; - } - - /* Fail and abort if already checking physical presence */ - if (physical_detect_busy()) { - physical_detect_abort(); - p->out_size = 1; - buffer[0] = EC_ERROR_BUSY; - return VENDOR_RC_INTERNAL_ERROR; - } - - /* Reduce physical presence if enabled via config */ - if (ccd_is_cap_enabled(CCD_CAP_OPEN_WITHOUT_LONG_PP)) - is_long = 0; - if (!is_long && ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_SHORT_PP)) - need_pp = 0; - - /* Bypass physical presence check entirely if battery is removed */ - if (ccd_is_cap_enabled(CCD_CAP_REMOVE_BATTERY_BYPASSES_PP) && - !board_battery_is_present()) { - need_pp = 0; - } - - if (need_pp) { - /* Start physical presence detect */ - ccprintf("Starting CCD open...\n"); - rv = physical_detect_start(is_long, ccd_open_done_async); - if (rv != EC_SUCCESS) { - p->out_size = 1; - buffer[0] = rv; - return VENDOR_RC_INTERNAL_ERROR; - } - return VENDOR_RC_IN_PROGRESS; - } - - /* No physical presence required; go straight to done */ - ccd_open_done(1); - - return VENDOR_RC_SUCCESS; - -denied: - /* Open not allowed for some reason */ - CPRINTS("%s denied: %s", __func__, why_denied); - p->out_size = 1; - buffer[0] = EC_ERROR_ACCESS_DENIED; - return VENDOR_RC_NOT_ALLOWED; -} - -static enum vendor_cmd_rc ccd_unlock(struct vendor_cmd_params *p) -{ - int need_pp = 1; - int rv; - char *buffer = p->buffer; - - if (force_disabled) { - p->out_size = 1; - buffer[0] = EC_ERROR_ACCESS_DENIED; - return VENDOR_RC_NOT_ALLOWED; - } - - if (ccd_state == CCD_STATE_UNLOCKED) - return VENDOR_RC_SUCCESS; - - /* Can go from opened to unlocked with no delay or password */ - if (ccd_state == CCD_STATE_OPENED) { - ccd_unlock_done(); - return VENDOR_RC_SUCCESS; - } - - /* Only allowed if password is already set, and not blocked by FWMP */ - if (!raw_has_password() || !board_fwmp_allows_unlock()) { - p->out_size = 1; - buffer[0] = EC_ERROR_ACCESS_DENIED; - return VENDOR_RC_NOT_ALLOWED; - } - - /* Make sure password was specified */ - if (!p->in_size) { - p->out_size = 1; - buffer[0] = EC_ERROR_PARAM_COUNT; - return VENDOR_RC_PASSWORD_REQUIRED; - } - - /* - * Check the password. We know there is plenty of room in the TPM - * buffer this is stored in. - */ - buffer[p->in_size] = '\0'; - rv = raw_check_password(buffer); - if (rv) { - p->out_size = 1; - buffer[0] = rv; - return VENDOR_RC_INTERNAL_ERROR; - } - - /* Fail and abort if already checking physical presence */ - if (physical_detect_busy()) { - physical_detect_abort(); - p->out_size = 1; - buffer[0] = EC_ERROR_BUSY; - return VENDOR_RC_INTERNAL_ERROR; - } - - /* Bypass physical presence check if configured to do so */ - if (ccd_is_cap_enabled(CCD_CAP_UNLOCK_WITHOUT_SHORT_PP)) - need_pp = 0; - - /* Bypass physical presence check entirely if battery is removed */ - if (ccd_is_cap_enabled(CCD_CAP_REMOVE_BATTERY_BYPASSES_PP) && - !board_battery_is_present()) { - need_pp = 0; - } - - if (need_pp) { - /* Start physical presence detect */ - ccprintf("Starting CCD unlock...\n"); - rv = physical_detect_start(0, ccd_unlock_done); - if (rv != EC_SUCCESS) { - p->out_size = 1; - buffer[0] = rv; - return VENDOR_RC_INTERNAL_ERROR; - } - return VENDOR_RC_IN_PROGRESS; - } - - /* Unlock immediately */ - ccd_unlock_done(); - - return VENDOR_RC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_lock(struct vendor_cmd_params *p) -{ - /* Lock always works */ - ccprintf("CCD locked.\n"); - ccd_set_state(CCD_STATE_LOCKED); - return VENDOR_RC_SUCCESS; -} - - - -/* NOTE: Testlab command is console-only; no TPM vendor command for this */ -static int command_ccd_testlab(int argc, char **argv) -{ - int newflag = 0; - - if (force_disabled) - return EC_ERROR_ACCESS_DENIED; - - if (argc < 2) { - ccprintf("CCD test lab mode %sbled\n", - ccd_get_flag(CCD_FLAG_TEST_LAB) ? "ena" : "disa"); - return EC_SUCCESS; - } - - if (!strcasecmp(argv[1], "open")) { - if (!ccd_get_flag(CCD_FLAG_TEST_LAB)) - return EC_ERROR_ACCESS_DENIED; - - /* Go directly to open state without wiping TPM or rebooting */ - ccd_set_state(CCD_STATE_OPENED); - return EC_SUCCESS; - } - - /* All other commands require CCD opened */ - if (ccd_state != CCD_STATE_OPENED) - return EC_ERROR_ACCESS_DENIED; - - if (!parse_bool(argv[1], &newflag)) - return EC_ERROR_PARAM1; - - if (newflag == ccd_get_flag(CCD_FLAG_TEST_LAB)) - return EC_SUCCESS; /* No change */ - - /* If we're still here, need to toggle test lab flag */ - ccprintf("Requesting change of test lab flag.\n"); - if (newflag) - ccprintf("NOTE: THIS WILL MAKE THIS DEVICE INSECURE!!!\n"); - return physical_detect_start(0, ccd_testlab_toggle); -} - -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1_UNSAFE -/** - * Test command to forcibly reset CCD config - */ -static int command_ccd_oops(void) -{ - /* Completely reset CCD config and go to opened state */ - force_disabled = 0; - ccprintf("Aborting physical detect...\n"); - physical_detect_abort(); - ccprintf("Resetting CCD config...\n"); - ccd_reset_config(CCD_RESET_TEST_LAB); - ccprintf("Opening CCD...\n"); - ccd_set_state(CCD_STATE_OPENED); - return EC_SUCCESS; -} -#endif /* CONFIG_CASE_CLOSED_DEBUG_V1_UNSAFE */ - -#ifdef CONFIG_CMD_CCD_DISABLE -static int command_ccd_disable(void) -{ - ccd_disable(); - return EC_SUCCESS; -} -#endif /* CONFIG_CMD_CCD_DISABLE */ - -static int command_ccd_help(void) -{ - int i; - - ccputs("usage: ccd [cmd [args]]\n\n" - "get (or just 'ccd')\n" - "\tPrint current config\n\n" - "lock\n" - "unlock [password]\n" - "open [password]\n" - "\tSet CCD state\n\n" - "set <capability> ["); - cflush(); - - for (i = 0; i < CCD_CAP_STATE_COUNT; i++) - ccprintf("%s%s", i ? " | " : "", ccd_cap_state_names[i]); - ccputs("]\n" - "\tSet capability to state\n\n" - "password [<new password> | clear]\n" - "\tSet or clear CCD password\n\n" - "reset [factory]\n" - "\tReset CCD config\n\n" - "testlab [enable | disable | open]\n" - "\tToggle testlab mode or force CCD open\n\n"); - cflush(); - -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1_UNSAFE - ccputs("oops\n" - "\tForce-reset CCD config\n\n"); -#endif -#ifdef CONFIG_CMD_CCD_DISABLE - ccputs("disable\n" - "\tTemporarily disable CCD\n\n"); -#endif - - return EC_SUCCESS; -} - -/** - * Case closed debugging config command. - */ -static int command_ccd_body(int argc, char **argv) -{ - /* If no args or 'get', print info */ - if (argc < 2 || !strcasecmp(argv[1], "get")) - return command_ccd_info(); - - /* Check test lab command first */ - if (!strcasecmp(argv[1], "testlab")) - return command_ccd_testlab(argc - 1, argv + 1); - - /* Commands to set state */ - if (!strcasecmp(argv[1], "lock")) - return ccd_command_wrapper(0, NULL, CCDV_LOCK); - if (!strcasecmp(argv[1], "unlock")) { - if (!raw_has_password()) { - ccprintf("Unlock only allowed after password is set\n"); - return EC_ERROR_ACCESS_DENIED; - } - return ccd_command_wrapper(argc - 1, argv[2], CCDV_UNLOCK); - } - if (!strcasecmp(argv[1], "open")) - return ccd_command_wrapper(argc - 1, argv[2], CCDV_OPEN); - - /* Commands to configure capabilities */ - if (!strcasecmp(argv[1], "set")) - return command_ccd_set(argc - 1, argv + 1); - if (!strcasecmp(argv[1], "password")) { - if (argc != 3) - return EC_ERROR_PARAM_COUNT; - return ccd_command_wrapper(argc - 1, argv[2], CCDV_PASSWORD); - } - if (!strcasecmp(argv[1], "reset")) - return command_ccd_reset(argc - 1, argv + 1); - - /* Optional commands */ -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1_UNSAFE - if (!strcasecmp(argv[1], "oops")) - return command_ccd_oops(); -#endif -#ifdef CONFIG_CMD_CCD_DISABLE - if (!strcasecmp(argv[1], "disable")) - return command_ccd_disable(); -#endif - - /* Anything else (including "help") prints help */ - return command_ccd_help(); -} - -static int command_ccd(int argc, char **argv) -{ - int rv; - - ccd_console_active = 1; - rv = command_ccd_body(argc, argv); - ccd_console_active = 0; - - return rv; -} -DECLARE_SAFE_CONSOLE_COMMAND(ccd, command_ccd, - "[help | ...]", - "Configure case-closed debugging"); - -/* - * Handle the CCVD_PASSWORD subcommand. - * - * The payload of the command is a text string to use to set or clear the - * password. - */ -static enum vendor_cmd_rc ccd_password(struct vendor_cmd_params *p) -{ - int rv = EC_SUCCESS; - char password[CCD_MAX_PASSWORD_SIZE + 1]; - char *response = p->buffer; - - /* - * Only allow setting a password from the AP, not USB. This increases - * the effort required for an attacker to set one externally, even if - * they have access to a system someone left in the opened state. - * - * An attacker can still set testlab mode or open up the CCD config, - * but those changes are reversible by the device owner. - */ - if (p->flags & VENDOR_CMD_FROM_USB) { - p->out_size = 1; - *response = EC_ERROR_ACCESS_DENIED; - return VENDOR_RC_NOT_ALLOWED; - } - - if (!p->in_size || (p->in_size >= sizeof(password))) { - rv = EC_ERROR_PARAM1; - } else { - memcpy(password, p->buffer, p->in_size); - password[p->in_size] = '\0'; - rv = do_ccd_password(password); - always_memset(password, 0, p->in_size); - } - - if (rv != EC_SUCCESS) { - *response = rv; - p->out_size = 1; - return VENDOR_RC_INTERNAL_ERROR; - } - - return VENDOR_RC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_pp_poll(struct vendor_cmd_params *p) -{ - char *buffer = p->buffer; - - if ((ccd_state == CCD_STATE_OPENED) || - (ccd_state == CCD_STATE_UNLOCKED)) { - buffer[0] = CCD_PP_DONE; - } else { - switch (physical_presense_fsm_state()) { - case PP_AWAITING_PRESS: - buffer[0] = CCD_PP_AWAITING_PRESS; - break; - case PP_BETWEEN_PRESSES: - buffer[0] = CCD_PP_BETWEEN_PRESSES; - break; - default: - buffer[0] = CCD_PP_CLOSED; - break; - } - } - p->out_size = 1; - return VENDOR_RC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_pp_poll_unlock(struct vendor_cmd_params *p) -{ - char *buffer = p->buffer; - - if ((ccd_state != CCD_STATE_OPENED) && - (ccd_state != CCD_STATE_UNLOCKED)) - return ccd_pp_poll(p); - - p->out_size = 1; - buffer[0] = CCD_PP_DONE; - - return VENDOR_RC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_pp_poll_open(struct vendor_cmd_params *p) -{ - char *buffer = p->buffer; - - if (ccd_state != CCD_STATE_OPENED) - return ccd_pp_poll(p); - - p->out_size = 1; - buffer[0] = CCD_PP_DONE; - - return VENDOR_RC_SUCCESS; -} - -static enum vendor_cmd_rc ccd_get_info(struct vendor_cmd_params *p) -{ - int i; - struct ccd_info_response response = {}; - - for (i = 0; i < CCD_CAP_COUNT; i++) { - int index; - int shift; - - /* Each capability takes 2 bits. */ - index = i / (32 / CCD_CAP_BITS); - shift = (i % (32 / CCD_CAP_BITS)) * CCD_CAP_BITS; - response.ccd_caps_current[index] |= raw_get_cap(i, 1) << shift; - response.ccd_caps_defaults[index] |= - cap_info[i].default_state << shift; - } - - response.ccd_flags = htobe32(raw_get_flags()); - response.ccd_state = ccd_get_state(); - response.ccd_indicator_bitmap = raw_has_password() ? - CCD_INDICATOR_BIT_HAS_PASSWORD : 0; - response.ccd_indicator_bitmap |= raw_check_all_caps_default() ? - CCD_INDICATOR_BIT_ALL_CAPS_DEFAULT : 0; - response.ccd_force_disabled = force_disabled; - for (i = 0; i < ARRAY_SIZE(response.ccd_caps_current); i++) { - response.ccd_caps_current[i] = - htobe32(response.ccd_caps_current[i]); - response.ccd_caps_defaults[i] = - htobe32(response.ccd_caps_defaults[i]); - } - - p->out_size = sizeof(response); - memcpy(p->buffer, &response, sizeof(response)); - - return VENDOR_RC_SUCCESS; -} - -/* - * Common TPM Vendor command handler used to demultiplex various CCD commands - * which need to be available both throuh CLI and over /dev/tpm0. - */ -static enum vendor_cmd_rc ccd_vendor(struct vendor_cmd_params *p) -{ - enum vendor_cmd_rc (*handler)(struct vendor_cmd_params *p); - enum vendor_cmd_rc rc; - - /* - * The command buffer points to the next byte after tpm header, i.e. to - * the CCD subcommand. Cache the pointer to make it easier to access - * and manipulate. - */ - char *buffer = p->buffer; - - /* - * Make sure the buffer is large enough to accommodate any CCD - * subcommand response (plus one byte, since the response is shifted), - * so we can skip size checks in the processing functions. - */ - if (p->out_size < sizeof(struct ccd_info_response) + 1) { - p->out_size = 0; - return VENDOR_RC_RESPONSE_TOO_BIG; - } - - /* Now we can assume no output data unless proven otherwise */ - p->out_size = 0; - - /* Pick what to do based on subcommand. */ - switch (buffer[0]) { - case CCDV_PASSWORD: - handler = ccd_password; - break; - - case CCDV_OPEN: - handler = ccd_open; - break; - - case CCDV_UNLOCK: - handler = ccd_unlock; - break; - - case CCDV_LOCK: - handler = ccd_lock; - break; - - case CCDV_PP_POLL_UNLOCK: - handler = ccd_pp_poll_unlock; - break; - - case CCDV_PP_POLL_OPEN: - handler = ccd_pp_poll_open; - break; - - case CCDV_GET_INFO: - handler = ccd_get_info; - break; - - default: - CPRINTS("%s:%d - unknown subcommand", __func__, __LINE__); - return VENDOR_RC_NO_SUCH_SUBCOMMAND; - } - - /* Shift buffer past the subcommand when calling the handler */ - p->buffer = buffer + 1; - p->in_size--; - rc = handler(p); - p->buffer = buffer; - p->in_size++; - - /* - * Move response up for the master to see it in the right - * place in the response buffer. We have to do this because the - * first byte of the buffer on input was the subcommand, so we - * passed buffer + 1 in the handler call above. - */ - memmove(buffer, buffer + 1, p->out_size); - return rc; -} -DECLARE_VENDOR_COMMAND_P(VENDOR_CC_CCD, ccd_vendor); - -static enum vendor_cmd_rc ccd_disable_factory_mode(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) -{ - int rv = EC_SUCCESS; - int error_line; - - do { - if (raw_has_password()) { - error_line = __LINE__; - rv = EC_ERROR_ACCESS_DENIED; - break; - } - - /* Check if physical presence is required to unlock. */ - if (!ccd_is_cap_enabled(CCD_CAP_REMOVE_BATTERY_BYPASSES_PP) || - board_battery_is_present()) { - const uint8_t required_capabilities[] = { - CCD_CAP_OPEN_WITHOUT_TPM_WIPE, - CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT, - CCD_CAP_OPEN_WITHOUT_LONG_PP, - CCD_CAP_UNLOCK_WITHOUT_SHORT_PP - }; - unsigned int i; - - for (i = 0; - i < ARRAY_SIZE(required_capabilities); - i++) { - if (!ccd_is_cap_enabled - (required_capabilities[i])) - break; - } - - if (i < ARRAY_SIZE(required_capabilities)) { - CPRINTF("Capability %d is not present\n", - required_capabilities[i]); - error_line = __LINE__; - rv = EC_ERROR_ACCESS_DENIED; - break; - } - } - - ccd_set_state(CCD_STATE_OPENED); - - rv = command_ccd_reset(0, NULL); - if (rv != EC_SUCCESS) { - error_line = __LINE__; - break; - } - - - ccd_lock(NULL); - - /* - * We do it here to make sure that the device comes out of - * factory mode with WP enabled, but in general CCD reset needs - * to enforce WP state. - * - * TODO(rspangler): sort out CCD state and WP correlation, - * b/73075443. - */ - board_wp_follow_ccd_config(); - - /* - * Use raw_set_flag() because the factory mode flag is internal - */ - mutex_lock(&ccd_config_mutex); - raw_set_flag(CCD_FLAG_FACTORY_MODE_ENABLED, 0); - mutex_unlock(&ccd_config_mutex); - - *response_size = 0; - return VENDOR_RC_SUCCESS; - } while (0); - - CPRINTF("%s: error in line %d\n", __func__, error_line); - - ((uint8_t *)buf)[0] = (uint8_t)rv; - *response_size = 1; - return VENDOR_RC_INTERNAL_ERROR; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_DISABLE_FACTORY, ccd_disable_factory_mode); diff --git a/common/extension.c b/common/extension.c deleted file mode 100644 index d2a26a6cd2..0000000000 --- a/common/extension.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2015 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 "byteorder.h" -#include "console.h" -#include "extension.h" -#include "link_defs.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_EXTENSION, format, ## args) - -uint32_t extension_route_command(struct vendor_cmd_params *p) -{ - struct extension_command *cmd_p; - struct extension_command *end_p; - const char *why_ignore = "not found"; - -#ifdef DEBUG_EXTENSION - CPRINTS("%s(%d,%s) is=%d os=%d", __func__, p->code, - p->flags & VENDOR_CMD_FROM_USB ? "USB" : "AP", - p->in_size, p->out_size); -#endif - - /* Filter commands from USB */ - if (p->flags & VENDOR_CMD_FROM_USB) { - switch (p->code) { -#ifdef CR50_DEV - case VENDOR_CC_IMMEDIATE_RESET: - case VENDOR_CC_INVALIDATE_INACTIVE_RW: - case VENDOR_CC_SET_BOARD_ID: - case VENDOR_CC_TPM_MODE: - case VENDOR_CC_SN_SET_HASH: - case VENDOR_CC_SN_INC_RMA: - case VENDOR_CC_ENDORSEMENT_SEED: -#endif /* defined(CR50_DEV) */ - case EXTENSION_POST_RESET: /* Always need to reset. */ - case VENDOR_CC_CCD: - case VENDOR_CC_GET_BOARD_ID: - case VENDOR_CC_RMA_CHALLENGE_RESPONSE: - case VENDOR_CC_SPI_HASH: /* Requires physical presence. */ - case VENDOR_CC_TURN_UPDATE_ON: - break; - default: - /* Otherwise, we don't allow this command. */ - why_ignore = "usb"; - goto ignore_cmd; - } - } - -#ifdef CONFIG_BOARD_ID_SUPPORT - /* - * If board ID is mismatched, allow only the commands needed to upgrade - * Cr50 firmware. - */ - if (board_id_is_mismatched()) { - switch (p->code) { - case EXTENSION_FW_UPGRADE: - case VENDOR_CC_REPORT_TPM_STATE: - case VENDOR_CC_TURN_UPDATE_ON: - case EXTENSION_POST_RESET: - break; - default: - why_ignore = "BoardID mismatch"; - goto ignore_cmd; - } - } -#endif - - /* Find the command handler */ - cmd_p = (struct extension_command *)&__extension_cmds; - end_p = (struct extension_command *)&__extension_cmds_end; - while (cmd_p != end_p) { - if (cmd_p->command_code == p->code) - return cmd_p->handler(p); - cmd_p++; - } - -ignore_cmd: - /* Command not found or not allowed */ - CPRINTS("%s: ignore %d: %s", __func__, p->code, why_ignore); - p->out_size = 0; - return VENDOR_RC_NO_SUCH_COMMAND; -} diff --git a/common/factory_mode.c b/common/factory_mode.c deleted file mode 100644 index c1d6789b91..0000000000 --- a/common/factory_mode.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2018 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. - */ - -/* CCD factory enable */ - -#include "ccd_config.h" -#include "console.h" -#include "extension.h" -#include "hooks.h" -#include "system.h" -#include "tpm_registers.h" -#include "tpm_vendor_cmds.h" - -#define CPRINTS(format, args...) cprints(CC_CCD, format, ## args) - -static uint8_t wait_for_factory_ccd_change; -static uint8_t reset_required_; - -static void factory_config_saved(int saved) -{ - wait_for_factory_ccd_change = 0; - - CPRINTS("%s: %s%s", __func__, saved ? "done" : "failed", - reset_required_ ? ", rebooting" : ""); - - if (!reset_required_) - return; - - cflush(); - system_reset(SYSTEM_RESET_HARD); -} - -static void ccd_config_changed(void) -{ - if (!wait_for_factory_ccd_change) - return; - - factory_config_saved(1); -} -DECLARE_HOOK(HOOK_CCD_CHANGE, ccd_config_changed, HOOK_PRIO_LAST); - -static void force_system_reset(void) -{ - CPRINTS("ccd hook didn't reset the system"); - factory_config_saved(0); -} -DECLARE_DEFERRED(force_system_reset); - -static void factory_enable_deferred(void) -{ - int rv; - - if (board_wipe_tpm(reset_required_) != EC_SUCCESS) - return; - - CPRINTS("%s: TPM reset done, enabling factory mode", __func__); - - wait_for_factory_ccd_change = 1; - rv = ccd_reset_config(CCD_RESET_FACTORY); - if (rv != EC_SUCCESS) - factory_config_saved(0); - - if (reset_required_) { - /* - * Cr50 will reset once factory mode is enabled. If it hasn't in - * TPM_RESET_TIME, declare factory enable failed and force the - * reset. - */ - hook_call_deferred(&force_system_reset_data, TPM_RESET_TIME); - } -} -DECLARE_DEFERRED(factory_enable_deferred); - -void enable_ccd_factory_mode(int reset_required) -{ - /* - * Wiping the TPM may take a while. Delay sleep long enough for the - * factory enable process to finish. - */ - delay_sleep_by(DISABLE_SLEEP_TIME_TPM_WIPE); - - reset_required_ |= !!reset_required; - hook_call_deferred(&factory_enable_deferred_data, - TPM_PROCESSING_TIME); -} diff --git a/common/flash_log.c b/common/flash_log.c deleted file mode 100644 index 798f48a2a6..0000000000 --- a/common/flash_log.c +++ /dev/null @@ -1,589 +0,0 @@ -/* Copyright 2019 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 "console.h" -#include "crc8.h" -#include "flash_log.h" -#include "flash.h" -#include "hooks.h" -#include "shared_mem.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* - * A few assumptions this log facility design is based on are: - * - * - the log is stored in a flash space configured per board/chip combination. - * Chip level physical access functions are used for writing and erasing. - * - * - flash space access control is transparent for the log facility, if - * necessary, chip driver can register a callback for flash access control. - * - * - log events are rare, attempts to log concurrent events could fail. - * - * - log events are retrieved by the host periodically, much sooner than log - * overflows - * - * - as presented this facility is not suitable for saving panics' - * information, because flash drivers usually require OS services like - * interrupts, events, etc. - * - * - at the point of logging an entry there is still 200 bytes or so of stack - * is available. - * - * With the above in mind, here is the basic design: - * - * Entries in the log are of variable size, this layer is completely oblivious - * to the entries' contents. Each entry is saved in the log prepended by a - * header, which includes the following fields: - * - * - entry type, 1 byte - * - the timestamp the entry is saved at, 4 bytes, if real time is not - * available a monotonously increasing number is used - * - entry size, one byte, size is limited to 63 bytes maximum, two top bits - * of the size byte could be used as flags. - * - the entry crc, 1 byte - * - * To satisfy flash access limitations, this facility pads log entries to a - * multiple of the physical flash write size. Padding bytes value is set to - * FE_LOG_PAD. Having a fixed padding value will make it easier to examine log - * space snapshots by third party software. The users of this service are - * oblivious to the padding, they write and read back entries of arbitrary not - * necessarily aligned sizes in 0..MAX_FLASH_LOG_PAYLOAD_SIZE range. - * - * The log is kept in one flash page. Entries are of variable size, as defined - * by entry header. For read accesses log is mapped directly into the address - * space, write accesses are handled by chip specific drivers. - * - * On each startup, if the log is more than three quarters full, the log flash - * space is erased and a quarter space worth from top of the log is written - * back at the bottom of the erased space. - * - * If an entry would not fit into the log it is silently dropped. - * - * Log entries can not be written or read from within interrupt processing - * routines. - * - * Only one read or write access can be in progress at a time. Attempts to log - * new events while a log entry is being saved or retrieved will be ignored. - * Attempts to retrieve an entry while another entry is being saved or - * retrieved will return the appropriate return value. - * - * At run time log compaction is attempted if a request to add an entry is - * made and the log is more than 90% full. If compaction is not possible (for - * example, if memory allocation fails) and the new entry does not fit, it - * would be dropped. - * - * The above mentioned failures are tracked and when log becomes operational - * again (for instance memory heap grew back), log entries are added to record - * previously encountered failures. - * - * The API to retrieve log entries gets the timestamp of the last retrieved - * entry as an input parameter and returns the next entry exists. Sequence of - * invocations of the log entry retrieval API starting with timestamp of zero - * and then repeating with the timestamp of the previously retrieved entry - * allows to traverse the entire log. - * - * Initialization function verifies log integrity. When initializing from an - * erased space, the initialization function saves a new entry of type - * FE_LOG_START. If log corruption is detected, the initialization function - * tries to compact the log and adds a new entry of type FE_LOG_CORRUPTED on - * top of the compacted log. - */ - -/* - * Structure keeping the context of the last entry retrieval access. If the - * next retrieval passed in timestamp saved in prev_timestamp, log search - * starts at read_cursor. - */ -static struct { - uint16_t read_cursor; - uint32_t prev_timestamp; -} log_read_context; - -/* Location where next entry is going to be added. */ -static uint16_t log_write_cursor; -/* - * Base time in seconds, during init set to the time of the latest present log - * entry +1, expected be set by the host to current time. Log entries - * timestamps are set to this value plus uptime. - */ -static uint32_t log_tstamp_base; - -/* - * Keep track of the last used timestamp value to make sure there are no two - * entries with the same timestamp. - */ -test_mockable_static uint32_t last_used_timestamp; - -/* Set to True after log has been initialized. */ -static uint8_t log_inited; -test_mockable_static uint8_t log_event_in_progress; -test_mockable_static uint32_t lock_failures_count; -static uint32_t overflow_failures_count; - -/* - * Callback set by the chip if flash log space access requires additional - * access control. - */ -static void (*platform_flash_control)(int enable); - -/* - * Helper function, convert offset in the log into a physical address in - * flash. - */ -static const void *log_offset_to_addr(uint16_t log_offset) -{ - return (const void *)(CONFIG_FLASH_LOG_BASE + log_offset); -} - -/* Wrappers around chip flash access functions. */ -static void flash_log_erase(void) -{ - flash_physical_erase(CONFIG_FLASH_LOG_BASE - CONFIG_PROGRAM_MEMORY_BASE, - CONFIG_FLASH_LOG_SPACE); -} - -static void flash_log_write(uint16_t log_offset, const void *data, - size_t data_size) -{ - flash_physical_write(log_offset + CONFIG_FLASH_LOG_BASE - - CONFIG_PROGRAM_MEMORY_BASE, - data_size, data); -} - -/* Wrappers around platform flash control function, if registered. */ -static void flash_log_write_enable(void) -{ - if (platform_flash_control) - platform_flash_control(1); -} - -static void flash_log_write_disable(void) -{ - if (platform_flash_control) - platform_flash_control(0); -} - -/* - * Wrapper around crc8 calculation to avoid excessive typecasting throughout - * the rest of the file. - */ -static uint8_t calc_crc8(const void *buf, size_t size, uint8_t prev) -{ - return crc8_arg((const uint8_t *)buf, size, prev); -} - -/* Try grabbing the lock, non blocking, return True if succeeded. */ -static int flash_log_lock_successful(void) -{ - if (in_interrupt_context()) - return 0; - - if (!log_inited) - return 0; - - interrupt_disable(); - if (log_event_in_progress) { - /* What a coincidence! */ - interrupt_enable(); - return 0; - } - log_event_in_progress = 1; - interrupt_enable(); - return 1; -} - -/* - * Verify entry validity, i.e. that it does fit into the log, has size within - * range and its crc8 matches. - */ -static int entry_is_valid(const struct flash_log_entry *r) -{ - size_t entry_size; - uint32_t entry_offset; - struct flash_log_entry copy; - - entry_size = FLASH_LOG_ENTRY_SIZE(r->size); - entry_offset = (uintptr_t)r - CONFIG_FLASH_LOG_BASE; - - if ((entry_offset + entry_size) > CONFIG_FLASH_LOG_SPACE) - return 0; - - /* Crc of the entry is calculated with the crc field set to zero. */ - copy = *r; - copy.crc = 0; - copy.crc = calc_crc8(©, sizeof(copy), 0); - copy.crc = calc_crc8(r + 1, FLASH_LOG_PAYLOAD_SIZE(r->size), copy.crc); - return (copy.crc == r->crc); -} - -/* Attempt compacting the log. Could fail if memory allocation fails. */ -static void try_compacting(void) -{ - char *buf; - uint16_t read_cursor = 0; - uint16_t compac_cursor = 0; - - /* Try rewriting the top 25% of the log into its bottom. */ - /* - * Fist allocate a buffer large enough to keep a quarter of the - * log. - */ - if (shared_mem_acquire(COMPACTION_SPACE_PRESERVE, &buf) != EC_SUCCESS) - return; - - while (read_cursor < log_write_cursor) { - const struct flash_log_entry *r; - size_t entry_space; - - r = log_offset_to_addr(read_cursor); - if (!entry_is_valid(r)) - break; - - entry_space = FLASH_LOG_ENTRY_SIZE(r->size); - - if ((log_write_cursor - read_cursor) <= - COMPACTION_SPACE_PRESERVE) { - memcpy(buf + compac_cursor, r, entry_space); - compac_cursor += entry_space; - } - - read_cursor += entry_space; - } - - flash_log_write_enable(); - flash_log_erase(); - flash_log_write(0, buf, compac_cursor); - log_write_cursor = compac_cursor; - flash_log_write_disable(); - - shared_mem_release(buf); - - log_read_context.read_cursor = 0; - log_read_context.prev_timestamp = 0; -} - -static enum ec_error_list flash_log_add_event_core(uint8_t type, uint8_t size, - void *payload) -{ - union entry_u e; - size_t padded_entry_size; - size_t entry_size; - enum ec_error_list rv = EC_ERROR_INVAL; - uint32_t new_timestamp; - - if (size > MAX_FLASH_LOG_PAYLOAD_SIZE) - return rv; - - if (!flash_log_lock_successful()) { - lock_failures_count++; - return rv; - } - - /* The entry will take this much space in the flash. */ - padded_entry_size = FLASH_LOG_ENTRY_SIZE(size); - - if (log_write_cursor > RUN_TIME_LOG_FULL_WATERMARK) - try_compacting(); - - if (padded_entry_size > (CONFIG_FLASH_LOG_SPACE - log_write_cursor)) { - /* - * Compaction must have failed or was not allowed, and no room - * to log. - */ - overflow_failures_count++; - goto log_add_exit; - } - - /* Copy the payload into the entry if necessary. */ - if (size) - memcpy(e.r.payload, payload, size); - - entry_size = sizeof(e.r) + size; - - new_timestamp = flash_log_get_tstamp(); - - /* - * Avoid rolling back or logging more than one entry with the same - * timestamp. - */ - if (last_used_timestamp >= new_timestamp) - last_used_timestamp += 1; - else - last_used_timestamp = new_timestamp; - - e.r.timestamp = last_used_timestamp; - e.r.size = size; - e.r.type = type; - e.r.crc = 0; - e.r.crc = calc_crc8(e.entry, entry_size, 0); - - /* Add padding if necessary. */ - while (entry_size < padded_entry_size) - e.entry[entry_size++] = FE_LOG_PAD; - - flash_log_write_enable(); - flash_log_write(log_write_cursor, e.entry, padded_entry_size); - flash_log_write_disable(); - - log_write_cursor += padded_entry_size; - - rv = EC_SUCCESS; - -log_add_exit: - log_event_in_progress = 0; - - return rv; -} - -/* - * Report the failure count, using the passed in type. If report attempt is - * successful, reset the counter. - * - * Even though the counter is 4 bytes in size, the log entry payload is a one - * byte value capped at 255: the failure counter is extremely unlikely to - * exceed this value, and if it does - we don't really care about the exact - * number. - */ -static void report_failure(enum flash_event_type type, uint32_t *counter) -{ - uint8_t reported_counter; - - /* - * Let's truncate the value at one byte, it is extremely unlikely to - * exceed it. - */ - reported_counter = *counter; - if (reported_counter > 255) - reported_counter = 255; - - if (flash_log_add_event_core(type, sizeof(reported_counter), - &reported_counter) == EC_SUCCESS) - *counter = 0; -} - -void flash_log_add_event(uint8_t type, uint8_t size, void *payload) -{ - if (lock_failures_count) - report_failure(FE_LOG_LOCKS, &lock_failures_count); - - if (overflow_failures_count) - report_failure(FE_LOG_OVERFLOWS, &overflow_failures_count); - - flash_log_add_event_core(type, size, payload); -} - -int flash_log_dequeue_event(uint32_t event_after, void *buffer, - size_t buffer_size) -{ - const struct flash_log_entry *r; - int rv = 0; - size_t copy_size; - - if (!flash_log_lock_successful()) - return -EC_ERROR_BUSY; - - if (!event_after || (event_after < log_read_context.prev_timestamp)) { - /* Will have to start over. */ - log_read_context.read_cursor = 0; - log_read_context.prev_timestamp = 0; - } - - if (log_read_context.read_cursor > - (CONFIG_FLASH_LOG_SPACE - sizeof(*r))) - /* No more room in the log. */ - goto log_read_exit; - - do { - r = log_offset_to_addr(log_read_context.read_cursor); - if (r->timestamp == CONFIG_FLASH_ERASED_VALUE32) - /* Points at erased space, no more entries. */ - goto log_read_exit; - - if (!entry_is_valid(r)) { - rv = -EC_ERROR_INVAL; - goto log_read_exit; - } - - log_read_context.read_cursor += FLASH_LOG_ENTRY_SIZE(r->size); - - } while (r->timestamp <= event_after); - - /* - * If we are here, we found the next event, let's see if it fits into - * the buffer. - */ - copy_size = FLASH_LOG_PAYLOAD_SIZE(r->size) + sizeof(*r); - if (copy_size > buffer_size) { - rv = -EC_ERROR_MEMORY_ALLOCATION; - /* To be on the safe side will start over next time. */ - log_read_context.read_cursor = 0; - log_read_context.prev_timestamp = 0; - goto log_read_exit; - } - - log_read_context.prev_timestamp = r->timestamp; - memcpy(buffer, r, copy_size); - rv = copy_size; - -log_read_exit: - log_event_in_progress = 0; - return rv; -} - -void flash_log_register_flash_control_callback( - void (*flash_control)(int enable)) -{ - platform_flash_control = flash_control; -} - -test_export_static void flash_log_init(void) -{ - uint16_t read_cursor = 0; - const struct flash_log_entry *r; - - r = log_offset_to_addr(read_cursor); - while (entry_is_valid(r)) { - last_used_timestamp = r->timestamp; - read_cursor += FLASH_LOG_ENTRY_SIZE(r->size); - r = log_offset_to_addr(read_cursor); - } - - /* Should be updated by the AP soon after booting. */ - log_tstamp_base = last_used_timestamp + 1; - - log_write_cursor = read_cursor; - log_inited = 1; - - flash_log_write_enable(); - if (r->timestamp != CONFIG_FLASH_ERASED_VALUE32) { - /* Log space must be corrupted, compact it. */ - try_compacting(); - flash_log_add_event(FE_LOG_CORRUPTED, 0, NULL); - flash_log_write_disable(); - return; - } - - /* - * Timestamp field is set to all ones, presumably this points to free - * space in the log. - * - * Is there anything at all in the log? - */ - if (read_cursor) { - /* - * Next write will have to come here unless compacting changes - * that. - */ - if (read_cursor > STARTUP_LOG_FULL_WATERMARK) - try_compacting(); - } else { - flash_log_add_event(FE_LOG_START, 0, NULL); - } - flash_log_write_disable(); -} -DECLARE_HOOK(HOOK_INIT, flash_log_init, HOOK_PRIO_DEFAULT); - -uint32_t flash_log_get_tstamp(void) -{ - return log_tstamp_base + get_time().val/1000000; -} - -enum ec_error_list flash_log_set_tstamp(uint32_t tstamp) -{ - if (tstamp <= last_used_timestamp) - return EC_ERROR_INVAL; - - log_tstamp_base = tstamp - get_time().val/1000000; - - return EC_SUCCESS; -} - -#ifdef CONFIG_CMD_FLASH_LOG -/* - * Display Flash event log. - */ -static int command_flash_log(int argc, char **argv) -{ - uint32_t stamp = 0; - union entry_u e; - int rv; - uint32_t type; - size_t size; - size_t i; - - if (argc > 1) { - if (!strcasecmp(argv[1], "-e")) { - ccprintf("Erasing flash log\n"); - flash_log_write_enable(); - flash_log_erase(); - flash_log_write_disable(); - - log_read_context.read_cursor = 0; - log_read_context.prev_timestamp = 0; - log_write_cursor = 0; - - argc--; - argv++; - } - } - if (argc < 3) { - if (argc == 2) - stamp = atoi(argv[1]); - - /* Retrieve entries newer than 'stamp'. */ - while ((rv = flash_log_dequeue_event(stamp, e.entry, - sizeof(e))) > 0) { - size_t i; - - ccprintf("%10u:%02x", e.r.timestamp, e.r.type); - for (i = 0; i < FLASH_LOG_PAYLOAD_SIZE(e.r.size); i++) { - if (i && !(i % 16)) - ccprintf("\n "); - ccprintf(" %02x", e.r.payload[i]); - } - ccprintf("\n"); - cflush(); - stamp = e.r.timestamp; - } - if (rv) - ccprintf("Warning: Last attempt to dequeue returned " - "%d\n", - rv); - return EC_SUCCESS; - } - - if (argc != 3) { - ccprintf("type and size of the entry are required\n"); - return EC_ERROR_PARAM_COUNT; - } - - type = atoi(argv[1]); - size = atoi(argv[2]); - - if (type >= FLASH_LOG_NO_ENTRY) { - ccprintf("type must not exceed %d\n", FLASH_LOG_NO_ENTRY - 1); - return EC_ERROR_PARAM2; - } - - if (size > MAX_FLASH_LOG_PAYLOAD_SIZE) { - ccprintf("size must not exceed %d\n", - MAX_FLASH_LOG_PAYLOAD_SIZE); - return EC_ERROR_PARAM3; - } - - for (i = 0; i < size; i++) - e.r.payload[i] = type + i; - flash_log_add_event(type, size, e.r.payload); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(flog, command_flash_log, - "[-e] ][[stamp]|[<type> <size>]]", - "Dump on the console the flash log contents," - "optionally erasing it\n" - "or add a new entry of <type> and <size> bytes"); -#endif diff --git a/common/flash_log_vc.c b/common/flash_log_vc.c deleted file mode 100644 index 5d1515a754..0000000000 --- a/common/flash_log_vc.c +++ /dev/null @@ -1,74 +0,0 @@ -/* Copyright 2019 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 "console.h" -#include "extension.h" -#include "endian.h" -#include "flash_log.h" -#include "util.h" - -static enum vendor_cmd_rc vc_pop_log_entry(enum vendor_cmd_cc code, void *buf, - size_t input_size, - size_t *response_size) -{ - uint32_t prev_timestamp; - int byte_size; - - *response_size = 0; /* In case there is an error. */ - - if (input_size != sizeof(prev_timestamp)) - return VENDOR_RC_BOGUS_ARGS; - - memcpy(&prev_timestamp, buf, sizeof(prev_timestamp)); - - byte_size = flash_log_dequeue_event( - prev_timestamp, buf, - FLASH_LOG_ENTRY_SIZE(MAX_FLASH_LOG_PAYLOAD_SIZE)); - - if (byte_size >= 0) { - *response_size = byte_size; - return VENDOR_RC_SUCCESS; - } - - /* Negative value should fit into a byte. */ - *response_size = 1; - ((uint8_t *)buf)[0] = -byte_size; - - return VENDOR_RC_INTERNAL_ERROR; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_POP_LOG_ENTRY, vc_pop_log_entry); - -static enum vendor_cmd_rc vc_flog_tstamp(enum vendor_cmd_cc code, void *buf, - size_t input_size, - size_t *response_size) -{ - uint32_t tstamp; - enum ec_error_list rv; - - if (!input_size) { - /* This is a request to report current flash log time. */ - tstamp = htobe32(flash_log_get_tstamp()); - memcpy(buf, &tstamp, sizeof(tstamp)); - *response_size = sizeof(tstamp); - return VENDOR_RC_SUCCESS; - } - - if (input_size != sizeof(tstamp)) - return VENDOR_RC_BOGUS_ARGS; - - memcpy(&tstamp, buf, sizeof(tstamp)); - tstamp = be32toh(tstamp); - rv = flash_log_set_tstamp(tstamp); - - if (rv == EC_SUCCESS) { - *response_size = 0; - return VENDOR_RC_SUCCESS; - } - - *response_size = 1; - *((uint8_t *)buf) = (uint8_t)rv; - return VENDOR_RC_BOGUS_ARGS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_FLOG_TIMESTAMP, vc_flog_tstamp); diff --git a/common/hooks.c b/common/hooks.c index dcdb4d8ee4..2dd0289741 100644 --- a/common/hooks.c +++ b/common/hooks.c @@ -48,9 +48,6 @@ static const struct hook_ptrs hook_list[] = { {__hooks_base_attached_change, __hooks_base_attached_change_end}, {__hooks_pwrbtn_change, __hooks_pwrbtn_change_end}, {__hooks_battery_soc_change, __hooks_battery_soc_change_end}, -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1 - {__hooks_ccd_change, __hooks_ccd_change_end}, -#endif #ifdef CONFIG_USB_SUSPEND {__hooks_usb_change, __hooks_usb_change_end}, #endif diff --git a/common/i2cs_tpm.c b/common/i2cs_tpm.c deleted file mode 100644 index 4518eddbb9..0000000000 --- a/common/i2cs_tpm.c +++ /dev/null @@ -1,261 +0,0 @@ -/* Copyright 2016 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 "gpio.h" -#include "hooks.h" -#include "i2cs.h" -#include "registers.h" -#include "system.h" -#include "tpm_registers.h" - -/* - * This implements adaptaition layer between i2cs (i2c slave) port and TPM. - * - * The adaptation layer is stateless, it processes the i2cs "write complete" - * interrupts on the interrupt context. - * - * Each "write complete" interrupt is associated with some data receved from - * the master. If the package received from the master contains just one byte - * payload, the value of this byte is considered the address of the TPM2 - * register to reach, read or write. - * - * Real TPM register addresses can be two bytes in size (even within locality - * zero), to keep the i2c protocol simple and efficient, the real TPM register - * addresses are re-mapped into i2c specific TPM register addresses. - * - * If the payload includes bytes following the address byte - those are the - * data to be written to the addressed register. The number of bytes of data - * could be anything between 1 and 62. The HW fifo is 64 bytes deep and that - * means that only 63 bytes can be written without the write pointer wrapping - * around to itself. Outside of the TPM fifo register, all other registers are - * either 1 byte or 4 byte writes. - * - * The master knows how many bytes to write into FIFO or to read from it by - * consulting the "burst size" field of the TPM status register. This happens - * transparently for this layer. - * - * Data destined to and coming from the FIFO register is treated as a byte - * stream. - * - * Data for and from all other registers are either 1 byte or 4 bytes as - * specified in a register's "reg_size" field of the I2C -> TPM mapping - * table. Multi-byte registers are received and transmitted in CPU byte order - * which for the Cr50 is little endian. - * TODO (scollyer crosbug.com/p/56539): Should modify the register access code - * so that the Host can access 1-4 bytes of a given register. - * - * Master write accesses followed by data result in the register address - * mapped, data converted, if necessary, and passed to the tpm register task. - * - * Master write accesses requesting register reads result in the register - * address mappend and accessing the tpm task to retrieve the proper register - * data, converting it, if necessary, and passing it to the 12cs controller to - * make available for master read accesses. - * - * Again, both read and write accesses complete on the same interrupt context - * they were invoked on. - */ - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_I2C, outstr) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) - -struct i2c_tpm_reg_map { - uint8_t i2c_address; - uint8_t reg_size; - uint16_t tpm_address; -}; -static const struct i2c_tpm_reg_map i2c_to_tpm[] = { - {0, 1, 0}, /* TPM Access */ - {1, 4, 0x18}, /* TPM Status */ - {5, 0, 0x24}, /* TPM Fifo, variable size. */ - {6, 4, 0xf00}, /* TPM DID VID */ - {0xa, 4, 0x14}, /* TPM TPM_INTF_CAPABILITY */ - {0xe, 1, 0xf04}, /* TPM RID */ - {0xf, 0, 0xf90}, /* TPM_FW_VER */ -}; - -/* Used to track number of times i2cs hw read fifo was adjusted */ -static uint32_t i2cs_fifo_adjust_count; -/* Used to track number of write mismatch errors */ -static uint32_t i2cs_write_error_count; - -static void process_read_access(uint16_t reg_size, - uint16_t tpm_reg, uint8_t *data) -{ - int i; - uint8_t reg_value[4]; - - /* - * The master wants to read the register, read the value and pass it - * to the controller. - */ - if (reg_size == 1 || reg_size == 4) { - /* Always read regsize number of bytes */ - tpm_register_get(tpm_reg, reg_value, reg_size); - /* - * For 1 or 4 byte register reads there should not be any data - * buffered in the i2cs hw read fifo. This function will check - * the current fifo queue depth and if non-zero, will adjust the - * fw pointer to force it to 0. - */ - if (i2cs_zero_read_fifo_buffer_depth()) - /* Count each instance that fifo was adjusted */ - i2cs_fifo_adjust_count++; - for (i = 0; i < reg_size; i++) - i2cs_post_read_data(reg_value[i]); - return; - } - - /* - * FIFO accesses do not require endianness conversion, but to find out - * how many bytes to read we need to consult the burst size field of - * the tpm status register. - */ - reg_size = tpm_get_burst_size(); - - /* - * Now, this is a hack, but we are short on SRAM, so let's reuse the - * receive buffer for the FIFO data sotrage. We know that the ISR has - * a 64 byte buffer were it moves received data. - */ - /* Back pointer up by one to point to beginning of buffer */ - data -= 1; - tpm_register_get(tpm_reg, data, reg_size); - /* Transfer TPM fifo data to the I2CS HW fifo */ - i2cs_post_read_fill_fifo(data, reg_size); -} - -static void process_write_access(uint16_t reg_size, uint16_t tpm_reg, - uint8_t *data, size_t i2cs_data_size) -{ - /* This is an actual write request. */ - - /* - * If reg_size is 0, then this is a fifo register write. Send the stream - * down directly - */ - if (reg_size == 0) { - tpm_register_put(tpm_reg, data, i2cs_data_size); - return; - } - - if (i2cs_data_size != reg_size) { - i2cs_write_error_count++; - return; - } - - /* Write the data to the appropriate TPM register */ - tpm_register_put(tpm_reg, data, reg_size); -} - -static void wr_complete_handler(void *i2cs_data, size_t i2cs_data_size) -{ - size_t i; - uint16_t tpm_reg; - uint8_t *data = i2cs_data; - const struct i2c_tpm_reg_map *i2c_reg_entry = NULL; - uint16_t reg_size; - - if (i2cs_data_size < 1) { - /* - * This is a misformatted request, should never happen, just - * ignore it. - */ - CPRINTF("%s: empty receive payload\n", __func__); - return; - } - - /* Let's find real TPM register address. */ - for (i = 0; i < ARRAY_SIZE(i2c_to_tpm); i++) - if (i2c_to_tpm[i].i2c_address == *data) { - i2c_reg_entry = i2c_to_tpm + i; - break; - } - - if (!i2c_reg_entry) { - CPRINTF("%s: unsupported i2c tpm address 0x%x\n", - __func__, *data); - return; - } - - /* - * OK, we know the tpm register address. Note that only full register - * accesses are supported for multybyte registers, - * TODO (scollyer crosbug.com/p/56539): Look at modifying this so we - * can handle 1 - 4 byte accesses at any any I2C register address we - * support. - */ - tpm_reg = i2c_reg_entry->tpm_address; - reg_size = i2c_reg_entry->reg_size; - - i2cs_data_size--; - data++; - - if (!i2cs_data_size) - process_read_access(reg_size, tpm_reg, data); - else - process_write_access(reg_size, tpm_reg, - data, i2cs_data_size); - - /* - * Since cr50 does not provide i2c clock stretching, we need some - * onther means of flow controlling the host. Let's generate a pulse - * on the AP interrupt line for that. - */ - gpio_set_level(GPIO_INT_AP_L, 0); - gpio_set_level(GPIO_INT_AP_L, 1); -} - -static void i2cs_if_stop(void) -{ - i2cs_register_write_complete_handler(NULL); -} - -static void i2cs_if_start(void) -{ - i2cs_register_write_complete_handler(wr_complete_handler); -} - -static void i2cs_if_register(void) -{ - if (!board_tpm_uses_i2c()) - return; - - tpm_register_interface(i2cs_if_start, i2cs_if_stop); - i2cs_fifo_adjust_count = 0; - i2cs_write_error_count = 0; -} -DECLARE_HOOK(HOOK_INIT, i2cs_if_register, HOOK_PRIO_LAST); - -static int command_i2cs(int argc, char **argv) -{ - static uint16_t base_read_recovery_count; - struct i2cs_status status; - - i2cs_get_status(&status); - - ccprintf("rd fifo adjust cnt = %d\n", i2cs_fifo_adjust_count); - ccprintf("wr mismatch cnt = %d\n", i2cs_write_error_count); - ccprintf("read recovered cnt = %d\n", status.read_recovery_count - - base_read_recovery_count); - if (argc < 2) - return EC_SUCCESS; - - if (!strcasecmp(argv[1], "reset")) { - i2cs_fifo_adjust_count = 0; - i2cs_write_error_count = 0; - base_read_recovery_count = status.read_recovery_count; - ccprintf("i2cs error counts reset\n"); - } else - return EC_ERROR_PARAM1; - - return EC_SUCCESS; -} -DECLARE_SAFE_CONSOLE_COMMAND(i2cstpm, command_i2cs, - "reset", - "Display fifo adjust count"); diff --git a/common/new_nvmem.c b/common/new_nvmem.c deleted file mode 100644 index 445d731f86..0000000000 --- a/common/new_nvmem.c +++ /dev/null @@ -1,3217 +0,0 @@ -/* Copyright 2019 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 <stdint.h> -#include <string.h> - -#include "test/nvmem_test.h" - -#include "common.h" -#include "board.h" -#include "console.h" -#include "crypto_api.h" -#include "flash.h" -#include "flash_log.h" -#include "new_nvmem.h" -#include "nvmem.h" -#include "nvmem_vars.h" -#include "shared_mem.h" -#include "system.h" -#include "system_chip.h" -#include "task.h" -#include "timer.h" - -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args) -/* - * ==== Overview - * - * This file is the implementation of the new TPM NVMEM flash storage layer. - * These are major differences compared to the legacy implementation: - * - * NVMEM TPM objects are stored in flash in separate containers, each one - * protected by hash and possibly encrypted. When nvmem_commit() is invoked, - * only objects changed in the NVMEM cache are updated in the flash. - * - * The (key, value) pairs are also stored in flash in the same kind of - * separate containers. There is no special area allocated for the (key, value) - * pairs in flash, they are interleaved with TPM objects. - * - * The (key, value) pairs are not kept in the NVMEM cache, they are stored in - * flash only. This causes a few deviations from the legacy (key, value) pair - * interface: - * - * - no need to initialize (key, value) storage separately, initvars() API is - * not there. - * - * - when the user is retrieving a (key, value) object, he/she is given a - * dynamically allocated buffer, which needs to be explicitly released by - * calling the new API: freevar(). - * - * - the (key. value) pairs, if modified, are updated in flash immediately, - * not after nvmem_commit() is called. - * - * Storing (key, value) pairs in the flash frees up 272 bytes of the cache - * space previously used, but makes it more difficult to control how flash - * memory is split between TPM objects and (key, value) pairs. A soft limit of - * 1K is introduced, limiting the total space used by (key, value) pairs data, - * not including tuple headers. - * - * ===== Organizing flash storage - * - * The total space used by the NVMEM in flash is reduced from 24 to 20 - * kilobytes, five 2K pages at the top of each flash bank. These pages are - * concatenated into a single storage space, based on the page header placed - * at the bottom of each page (struct nn_page_header). The page header - * includes a 21 bit page number (this allows to order pages properly on - * initialization), the offset of the first data object in the page and the - * hash of the entire header. - * - * Yet another limitation of the new scheme is that no object stored in NVMEM - * can exceed the flash page size less the page header size and container - * header size. This allows for objects as large as 2035 bytes. Objects can - * span flash pages. Note that reserved TPM object STATE_CLEAR_DATA exceeds 2K - * in size, this is why one of its components (the .pcrSave field) is stored - * in flash separately. - * - * ===== Object containers - * - * The container header (struct nn_container) describes the contained TPM - * object or (key, value) pair, along with the size, and also includes the - * hash of the entire container calculated when the hash field is set to zero. - * - * When an object needs to be updated, it is stored at the end of the used - * flash space in a container with the higher .generation field value, and - * then the older container's type field is erased, thus marking it as a - * deleted object. The idea is that when initializing NVMEM cache after reset, - * in case two instances of the same object are found in the flash because the - * new instance was saved, but the old instance was not erased because of some - * failure, the instance with larger .generation field value wins. Note that - * this error recovery procedure is supplemented by use of transaction - * delimiter objects described below. - * - * The container type field is duplicated in the container header, this allows - * verification of the container hash after even the object was erased. - * - * In order to be able to erase the type the container must start at the 4 - * byte boundary. This in turn requires that each container is padded such - * that total storage taken by the container is divisible by 4. - * - * To be able to tell if two containers contain two instances of the same - * object, one needs to be able to identify the object stored in the container. - * For the three distinct types of objects it works as follows: - * - * - (key, value) pair: key, stored in the contained tuple. - * - * - reserved tpm object: the first byte stored in the container. PCR - * values from STATE_CLEAR_DATA.pcrSave field are stored as separate - * reserved objects with the appropriate first bytes. - * - * - evictable tpm object: the first 4 bytes stored in the container, the - * evictable TTPM object ID. - * - * Don't forget that the contents are usually encrypted. Decryption is needed - * each time a stored object needs to be examined. - * - * Reserved objects of types STATE_CLEAR_DATA and STATE_RESET_DATA are very - * big and are stored in the flash in marshaled form. On top of 'regular' TPM2 - * style marshaling, PCRs found in the STATE_CLEAR_DATA object are stored in - * separate containers. - * - * ===== Storage compaction - * - * Keeping adding changed values at the end of the flash space would - * inevitably cause space overflow, unless something is done about it. This is - * where flash compaction kicks in: as soon as there are just three free flash - * pages left the stored objects are moved to the end of the space, which - * results in earlier used pages being freed and added to the pool of - * available flash pages. - * - * A great improvement to this storage compaction process would be grouping - * the objects such that the rarely changing ones occupy flash pages at the - * lower page indices. In this case when compaction starts, the pages not - * containing erased objects would not have to be re-written. This - * optimization is left as a future enhancement. - * - * ===== Committing TPM changes - * - * When nvmem_commit() is invoked it is necessary to identify which TPM - * objects in the cache have changed and require saving. Remember, that (key, - * value) pairs are not held in the cache any more and are saved in the flash - * immediately, so they do not have to be dealt with during commit. - * - * The commit procedure starts with iterating over the evictable objects space - * in the NVMEM cache, storing in an array offsets of all evictable objects it - * finds there. Then it iterates over flash contents skipping over (key, - * value) pairs. - * - * For each reserved object stored in flash, it compares its stored value with - * the value stored in the cache at known fixed location. If the value has - * changed, a new reserved object instance is saved in flash. This approach - * requires that all reserved objects are present in the flash, otherwise - * there is nothing to compare the cached instance of the object with. This is - * enforced by the init function. - * - * For each evictable object stored in flash, it checks if that object is - * still in the cache using the previously collected array of offsets. If the - * object is not in the cache, it must have been deleted by the TPM. The - * function deletes it from the flash as well. If the object is in the cache, - * its offset is removed from the array to indicate that the object has been - * processed. Then if the object value has changed, the new instance is added - * and the old instance erased. After this the only offsets left in the array - * are offsets of new objects, not yet saved in the flash. All these remaining - * objects get saved. - * - * To ensure transaction integrity, object deletions are just scheduled and - * not processed immediately, the deletion happens after all new instances - * have been saved in flash. See more about transaction delimiters below. - * - * ===== Migration from legacy storage and reclaiming flash space - * - * To be able to migrate existing devices from the legacy storage format the - * initialization code checks if a full 12K flash partition is still present, - * and if so - copies its contents into the cache and invokes the migration - * function. The function erases the alternative partition and creates a list - * of 5 pages available for the new format (remember, the flash footprint of - * the new scheme is smaller, only 10K is available in each half). - * - * The (key, value) pairs and TPM objects are stored in the new format as - * described, and then the legacy partition is erased and its pages are added - * to the list of free pages. This approach would fail if the existing TPM - * storage would exceed 10K, but this is extremely unlikely, especially since - * the large reserved objects are stored by the new scheme in marshaled form. - * This frees up a lot of flash space. - * - * Eventually it will be possible to reclaim the bottom 2K page per flash half - * currently used by the legacy scheme, but this would be possible only after - * migration is over. The plan is to keep a few Cr50 versions supporting the - * migration process, and then drop the migration code and rearrange the - * memory map and reclaim the freed pages. Chrome OS will always carry a - * migrating capable Cr50 version along with the latest one to make sure that - * even Chrome OS devices which had not updated their Cr50 code in a long - * while can be migrated in two steps. - * - * ===== Initialization, including erased/corrupted flash - * - * On regular startup (no legacy partition found) the flash pages dedicated to - * NVMEM storage are examined, pages with valid headers are included in the - * list of available pages, sorted by the page number. Erased pages are kept - * in a separate list. Pages which are not fully erased (but do not have a - * valid header) are considered corrupted, are erased, and added to the second - * list. - * - * After that the contents of the ordered flash pages is read, all discovered - * TPM objects are verified and saved in the cache. - * - * To enforce that all reserved TPM objects are present in the flash, the init - * routine maintains a bitmap of the reserved objects it found while - * initializing. In the case when after the scan of the entire NVMEM flash it - * turns out that some reserved objects have not been encountered, the init - * routine creates new flash instances of the missing reserved objects with - * default value of zero. This takes care of both initializing from empty - * flash and a case when a reserved object disappears due to a bug. - * - * ===== Transactions support - * - * It is important to make sure that TPM changes are grouped together. It came - * naturally with the legacy scheme where each time nvmem_save() was called, - * the entire cache snapshot was saved in the flash. With the new scheme some - * extra effort is required. - * - * Transaction delimiters are represented by containers of the appropriate - * type and the payload size of zero. When nvmem_save() operation is started, - * the new objects get written into flash and the objects requiring deletion - * are kept in the list. Once all new objects are added to the flash, the - * transaction delimiter is written, ending up at the top of the used flash. - * After that the objects scheduled for deletion are deleted, and then the - * transaction delimiter is also marked 'deleted'. - * - * So, during initialization the flash could be in one of three states: - * - * - thre is an erased transaction delimiter at the top - * . this is the normal state after successful commit operation. - * - * - there is transaction delimiter at the top, but it is not erased. - * . this is the case where the new objects were saved in flash, but some of - * the old instances might still be present not erased. The recovery - * procedure finds all duplicates of the objects present between two most - * recent delimiters and erases them. - * - * - there is no transaction delimiter on the top. - * . this is the case where nvmem_save() was interrupted before all new - * values have been written into the flash. The recovery procedure finds - * all TPM objects above the last valid delimiter in the flash and erases - * them all. - * - * ===== Handling failures - * - * This implementation is no better in handling failures than the legacy one, - * it in fact is even worse, because if a failure happened during legacy - * commit operation, at least the earlier saved partition would be available. - * If failure happens during this implementation's save or compaction process, - * there is a risk of ending up with a corrupted or inconsistent flash - * contents, even though the use of transaction delimiters narrows the failure - * window significantly. - * - * This first draft is offered for review and to facilitate testing and - * discussion about how failures should be addressed. - * - * ===== Missing stuff - * - * Presently not much thought has been given to locking and preventing - * problems caused by task preemption. The legacy scheme is still in place, - * but it might require improvements. - */ - -/* - * This code relies on the fact that space dedicated to flash NVMEM storage is - * sufficient to guarantee that the entire NVMEM snapshot can fit into it - * comfortably. The assert below is a very liberal computation which - * guarantees this assumption. Note that marshaling huge reserved structures - * reduces amount of required flash space, and this is not accounted for in - * this calculation. Space allocated for 200 container descriptors is also way - * more than required. - */ - -/* - * Fuzz testing does not enforce proper size definitions, causing the below - * assert failure. - */ -BUILD_ASSERT((NEW_NVMEM_TOTAL_PAGES * CONFIG_FLASH_BANK_SIZE) > - (MAX_VAR_TOTAL_SPACE + - NV_MEMORY_SIZE + - 200 * (sizeof(struct nn_container)) + - CONFIG_FLASH_BANK_SIZE * 2)); - -/* Maximum number of evictable objects we support. */ -#define MAX_STORED_EVICTABLE_OBJECTS 20 -/* - * Container for storing (key, value) pairs, a.k.a. vars during read. Actual - * vars would never be this large, but when looking for vars we need to be - * able to iterate over and verify all objects in the flash, hence the max - * body size. - */ -struct max_var_container { - struct nn_container c_header; - struct tuple t_header; - uint8_t body[CONFIG_FLASH_BANK_SIZE - sizeof(struct nn_container) - - sizeof(struct tuple)]; -} __packed; - -/* - * Limit of the number of objects which can be updated in one TPM transaction, - * reserved and evictable total. This is much more than practical maximum. - */ -#define MAX_DELETE_CANDIDATES 30 -static struct delete_candidates { - size_t num_candidates; - const struct nn_container *candidates[MAX_DELETE_CANDIDATES]; -} *del_candidates; - -/* - * This array contains a list of flash pages indices (0..255 range) sorted by - * the page header page number filed. Erased pages are kept at the tail of the - * list. - */ -static uint8_t page_list[NEW_NVMEM_TOTAL_PAGES]; -static uint32_t next_evict_obj_base; -static uint8_t init_in_progress; -/* - * Mutex to protect flash space containing NVMEM objects. All operations - * modifying the flash contents or relying on its consistency (like searching - * in the flash) should acquire this mutex before proceeding. - * - * The interfaces grabbing this mutex are - * - * new_nvmem_migrate() - * new_nvmem_init() - * new_nvmem_save() - * getvar() - * setvar() - * nvmem_erase_tpm_data() - * - * The only static function using the mutex is browse_flash_contents() which - * can be invoked from the CLI and while it never modifies the flash contents, - * it still has to be protected to be able to properly iterate over the entire - * flash contents. - */ -static struct mutex flash_mtx; - -/* - * Wrappers around locking/unlocking mutex make it easier to debug issues by - * adding with minimal code changes like printouts of line numbers where the - * functions are invoked from. - */ -static void lock_mutex(int line_num) -{ - mutex_lock(&flash_mtx); -} - -static void unlock_mutex(int line_num) -{ - mutex_unlock(&flash_mtx); -} - -/* - * Total space taken by key, value pairs in flash. It is limited to give TPM - * objects priority. - */ -test_export_static uint16_t total_var_space; - -/* The main context used when adding objects to NVMEM. */ -test_export_static struct access_tracker master_at; - -test_export_static enum ec_error_list browse_flash_contents(int print); -static enum ec_error_list save_container(struct nn_container *nc); -static void invalidate_nvmem_flash(void); - -/* Log NVMEM problem as per passed in payload and size, and reboot. */ -static void report_failure(struct nvmem_failure_payload *payload, - size_t payload_union_size) -{ - if (init_in_progress) { - /* - * This must be a rolling reboot, let's invalidate flash - * storage to stop this. - */ - invalidate_nvmem_flash(); - } - - flash_log_add_event(FE_LOG_NVMEM, - payload_union_size + - offsetof(struct nvmem_failure_payload, - size), - payload); - - ccprintf("Logging failure %d, will %sreinit\n", payload->failure_type, - init_in_progress ? "" : "not "); - - if (init_in_progress) { - struct nvmem_failure_payload fp; - - fp.failure_type = NVMEMF_NVMEM_WIPE; - - flash_log_add_event( - FE_LOG_NVMEM, - offsetof(struct nvmem_failure_payload, size), &fp); - } - - cflush(); - - system_reset(SYSTEM_RESET_MANUALLY_TRIGGERED | SYSTEM_RESET_HARD); -} - -static void report_no_payload_failure(enum nvmem_failure_type type) -{ - struct nvmem_failure_payload fp; - - fp.failure_type = type; - report_failure(&fp, 0); -} - -/* - * This function allocates a buffer of the requested size. - * - * Heap space could be very limited and at times there could be not enough - * memory in the heap to allocate. This should not be considered a failure, - * polling should be used instead. On a properly functioning device the memory - * would become available. If it is not - there is not much we can do, we'll - * have to reboot adding a log entry. - */ -static void *get_scratch_buffer(size_t size) -{ - char *buf; - int i; - struct nvmem_failure_payload fp; - - /* - * Wait up to a 5 seconds in case some other operation is under - * way. - */ - for (i = 0; i < 50; i++) { - int rv; - - rv = shared_mem_acquire(size, &buf); - if (rv == EC_SUCCESS) { - if (i) - CPRINTS("%s: waited %d cycles!", __func__, i); - return buf; - } - usleep(100 * MSEC); - } - - fp.failure_type = NVMEMF_MALLOC; - fp.size = size; - report_failure(&fp, sizeof(fp.size)); - - /* Just to keep the compiler happy, this is never reached. */ - return NULL; -} - -/* Helper function returning actual size used by NVMEM in flash. */ -static size_t total_used_size(void) -{ - return master_at.list_index * CONFIG_FLASH_BANK_SIZE + - master_at.mt.data_offset; -} -/* - * Helper functions to set a bit a bit at a certain index in a bitmap array - * and to check if the bit is set. The caller must guarantee that the bitmap - * array is large enough for the index. - */ -static int bitmap_bit_check(const uint8_t *bitmap, size_t index) -{ - return bitmap[index / 8] & (1 << (index % 8)); -} - -static int bitmap_bit_set(uint8_t *bitmap, size_t index) -{ - return bitmap[index / 8] |= (1 << (index % 8)); -} - -/* Convenience functions used to reduce amount of typecasting. */ -static void app_compute_hash_wrapper(void *buf, size_t size, void *hash, - size_t hash_size) -{ - app_compute_hash(buf, size, hash, hash_size); -} - -static STATE_CLEAR_DATA *get_scd(void) -{ - NV_RESERVED_ITEM ri; - - NvGetReserved(NV_STATE_CLEAR, &ri); - - return (STATE_CLEAR_DATA *)((uint8_t *)nvmem_cache_base(NVMEM_TPM) + - ri.offset); -} - -/* - * Make sure page header hash is different between prod and other types of - * images. - */ -static uint32_t calculate_page_header_hash(struct nn_page_header *ph) -{ - uint32_t hash; - static const uint32_t salt[] = {1, 2, 3, 4}; - - BUILD_ASSERT(sizeof(hash) == - offsetof(struct nn_page_header, page_hash)); - - app_cipher(salt, &hash, ph, sizeof(hash)); - - return hash; -} - -/* Veirify page header hash. */ -static int page_header_is_valid(struct nn_page_header *ph) -{ - return calculate_page_header_hash(ph) == ph->page_hash; -} - -/* Convert flash page number in 0..255 range into actual flash address. */ -static struct nn_page_header *flash_index_to_ph(uint8_t index) -{ - return (struct nn_page_header *)((index * CONFIG_FLASH_BANK_SIZE) + - CONFIG_PROGRAM_MEMORY_BASE); -} - -static const void *page_cursor(const struct page_tracker *pt) -{ - return (void *)((uintptr_t)pt->ph + pt->data_offset); -} - -/* - * Return flash page pointed at by a certain page_list element if the page is - * valid. If the index is out of range, or page is not initialized properly - * return NULL. - */ -test_export_static struct nn_page_header *list_element_to_ph(size_t el) -{ - struct nn_page_header *ph; - - if (el >= ARRAY_SIZE(page_list)) - return NULL; - - ph = flash_index_to_ph(page_list[el]); - - if (page_header_is_valid(ph)) - return ph; - - return NULL; -} - -/* - * Read into buf or skip if buf is NULL the next num_bytes in the storage, at - * the location determined by the passed in access tracker. Start from the - * very beginning if the passed in access tracker is empty. - * - * If necessary - concatenate contents from different pages bypassing page - * headers. - * - * If user is reading the container header (as specified by the - * container_fetch argument), save in the context the location of the - * container. - * - * If not enough bytes are available in the storage to satisfy the request - - * log error and reboot. - */ -static size_t nvmem_read_bytes(struct access_tracker *at, size_t num_bytes, - void *buf, int container_fetch) -{ - size_t togo; - struct nvmem_failure_payload fp; - - if (!at->list_index && !at->mt.data_offset) { - /* Start from the beginning. */ - at->mt.ph = list_element_to_ph(0); - at->mt.data_offset = at->mt.ph->data_offset; - } - - if (container_fetch) { - at->ct.data_offset = at->mt.data_offset; - at->ct.ph = at->mt.ph; - } - - if ((at->mt.data_offset + num_bytes) < CONFIG_FLASH_BANK_SIZE) { - /* - * All requested data fits and does not even reach the top of - * the page. - */ - if (buf) - memcpy(buf, page_cursor(&at->mt), num_bytes); - - at->mt.data_offset += num_bytes; - return num_bytes; - } - - /* Data is split between pages. */ - /* To go in the current page. */ - togo = CONFIG_FLASH_BANK_SIZE - at->mt.data_offset; - if (buf) { - memcpy(buf, page_cursor(&at->mt), togo); - /* Next portion goes here. */ - buf = (uint8_t *)buf + togo; - } - - /* - * Determine how much is there to read in the next page. - * - * Since object size is limited to page size - * less page header size, we are guaranteed that the object would not - * span more than one page boundary. - */ - togo = num_bytes - togo; - - /* Move to the next page. */ - at->list_index++; - at->mt.ph = list_element_to_ph(at->list_index); - - if (!at->mt.ph && togo) { - /* - * No more data to read. Could the end of used flash be close - * to the page boundary, so that there is no room to read an - * erased container header? - */ - if (!container_fetch) { - fp.failure_type = NVMEMF_READ_UNDERRUN; - fp.underrun_size = num_bytes - togo; - /* This will never return. */ - report_failure(&fp, sizeof(fp.underrun_size)); - } - - /* - * Simulate reading of the container header filled with all - * ones, which would be an indication of the end of storage, - * the caller will roll back ph, data_offset and list index as - * appropriate. - */ - memset(buf, 0xff, togo); - } else if (at->mt.ph) { - if (at->mt.ph->data_offset < (sizeof(*at->mt.ph) + togo)) { - fp.failure_type = NVMEMF_PH_SIZE_MISMATCH; - fp.ph.ph_offset = at->mt.ph->data_offset; - fp.ph.expected = sizeof(*at->mt.ph) + togo; - /* This will never return. */ - report_failure(&fp, sizeof(fp.ph)); - } - if (buf) - memcpy(buf, at->mt.ph + 1, togo); - - at->mt.data_offset = sizeof(*at->mt.ph) + togo; - } - - return num_bytes; -} - -/* - * Convert passed in absolute address into flash memory offset and write the - * passed in blob into the flash. - */ -static enum ec_error_list write_to_flash(const void *flash_addr, - const void *obj, size_t size) -{ - return flash_physical_write( - (uintptr_t)flash_addr - CONFIG_PROGRAM_MEMORY_BASE, size, obj); -} - -/* - * Corrupt headers of all active pages thus invalidating the entire NVMEM - * flash storage. - */ -static void invalidate_nvmem_flash(void) -{ - size_t i; - struct nn_page_header *ph; - struct nn_page_header bad_ph; - - memset(&bad_ph, 0, sizeof(bad_ph)); - - for (i = 0; i < ARRAY_SIZE(page_list); i++) { - ph = list_element_to_ph(i); - if (!ph) - continue; - write_to_flash(ph, &bad_ph, sizeof(*ph)); - } -} - -/* - * When initializing flash for the first time - set the proper first page - * header. - */ -static enum ec_error_list set_first_page_header(void) -{ - struct nn_page_header ph = {}; - enum ec_error_list rv; - struct nn_page_header *fph; /* Address in flash. */ - - ph.data_offset = sizeof(ph); - ph.page_hash = calculate_page_header_hash(&ph); - fph = flash_index_to_ph(page_list[0]); - rv = write_to_flash(fph, &ph, sizeof(ph)); - - if (rv == EC_SUCCESS) { - /* Make sure master page tracker is ready. */ - memset(&master_at, 0, sizeof(master_at)); - master_at.mt.data_offset = ph.data_offset; - master_at.mt.ph = fph; - } - - return rv; -} - -/* - * Verify that the passed in container is valid, specifically that its hash - * matches its contents. - */ -static int container_is_valid(struct nn_container *ch) -{ - struct nn_container dummy_c; - uint32_t hash; - uint32_t preserved_hash; - uint8_t preserved_type; - - preserved_hash = ch->container_hash; - preserved_type = ch->container_type; - - ch->container_type = ch->container_type_copy; - ch->container_hash = 0; - app_compute_hash_wrapper(ch, ch->size + sizeof(*ch), &hash, - sizeof(hash)); - - ch->container_hash = preserved_hash; - ch->container_type = preserved_type; - - dummy_c.container_hash = hash; - - return dummy_c.container_hash == ch->container_hash; -} - -static uint32_t aligned_container_size(const struct nn_container *ch) -{ - const size_t alignment_mask = CONFIG_FLASH_WRITE_SIZE - 1; - - return (ch->size + sizeof(*ch) + alignment_mask) & ~alignment_mask; -} - -/* - * Function which allows to iterate through all objects stored in flash. The - * passed in context keeps track of where the previous object retrieval ended. - * - * Return: - * EC_SUCCESS if an object is retrieved and verified - * EC_ERROR_MEMORY_ALLOCATION if 'erased' object reached (not an error). - * EC_ERROR_INVAL if verification failed or read is out of sync. - */ -test_export_static enum ec_error_list get_next_object(struct access_tracker *at, - struct nn_container *ch, - int include_deleted) -{ - uint32_t salt[4]; - uint8_t ctype; - - salt[3] = 0; - - do { - size_t aligned_remaining_size; - struct nn_container temp_ch; - - nvmem_read_bytes(at, sizeof(temp_ch), &temp_ch, 1); - ctype = temp_ch.container_type; - - /* Should we check for the container being all 0xff? */ - if (ctype == NN_OBJ_ERASED) { - /* Roll back container size. */ - at->mt.data_offset = at->ct.data_offset; - at->mt.ph = at->ct.ph; - - /* - * If the container header happened to span between - * two pages or end at the page boundary - roll back - * page index saved in the context. - */ - if ((CONFIG_FLASH_BANK_SIZE - at->mt.data_offset) <= - sizeof(struct nn_container)) - at->list_index--; - - return EC_ERROR_MEMORY_ALLOCATION; - } - - /* - * The read data is a container header, copy it into the user - * provided space and continue reading there. - */ - *ch = temp_ch; - aligned_remaining_size = - aligned_container_size(ch) - sizeof(*ch); - - if (aligned_remaining_size) { - if (aligned_remaining_size > - (CONFIG_FLASH_BANK_SIZE - sizeof(*ch))) { - /* Never returns. */ - report_no_payload_failure( - NVMEMF_INCONSISTENT_FLASH_CONTENTS); - } - - nvmem_read_bytes(at, aligned_remaining_size, ch + 1, 0); - - salt[0] = at->ct.ph->page_number; - salt[1] = at->ct.data_offset; - salt[2] = ch->container_hash; - - /* Decrypt in place. */ - if (!app_cipher(salt, ch + 1, ch + 1, ch->size)) - report_no_payload_failure(NVMEMF_CIPHER_ERROR); - } - - /* And calculate hash. */ - if (!container_is_valid(ch)) { - struct nvmem_failure_payload fp; - - if (!init_in_progress) - report_no_payload_failure( - NVMEMF_CONTAINER_HASH_MISMATCH); - /* - * During init there might be a way to deal with - * this, let's just log this and continue. - */ - fp.failure_type = NVMEMF_CONTAINER_HASH_MISMATCH; - flash_log_add_event( - FE_LOG_NVMEM, - offsetof(struct nvmem_failure_payload, size), - &fp); - - return EC_ERROR_INVAL; - } - - /* - * Keep track of the most recently encountered delimiter, - * finalized or not. - */ - if (ch->container_type_copy == NN_OBJ_TRANSACTION_DEL) { - include_deleted = 1; /* Always return all delimiters. */ - - /* But keep track only of finalized ones. */ - if (ch->container_type == NN_OBJ_OLD_COPY) { - at->dt.ph = at->ct.ph; - at->dt.data_offset = at->ct.data_offset; - } - } - - } while (!include_deleted && (ctype == NN_OBJ_OLD_COPY)); - - return EC_SUCCESS; -} - -/* - * Add a delimiter object at the top of the flash. The container type field is - * not erased. - * - * This is an indication that after nvmem_commit() invocation all updated - * objects have been saved in the flash, but the old instances of the objects - * have not yet been deleted. - */ -static enum ec_error_list add_delimiter(void) -{ - struct nn_container ch; - - memset(&ch, 0, sizeof(ch)); - - ch.container_type = ch.container_type_copy = NN_OBJ_TRANSACTION_DEL; - - return save_container(&ch); -} - -/* - * Erase the container type field of the previously saved delimiter, thus - * indicating that nvmem save transaction is completed. - */ -static enum ec_error_list finalize_delimiter(const struct nn_container *del) -{ - struct nn_container c; - - c = *del; - c.container_type = NN_OBJ_OLD_COPY; - - return write_to_flash(del, &c, sizeof(c)); -} - -/* Add delimiter indicating that flash is in a consistent state. */ -static enum ec_error_list add_final_delimiter(void) -{ - const struct nn_container *del; - - del = page_cursor(&master_at.mt); - add_delimiter(); - - return finalize_delimiter(del); -} - -/* Erase flash page and add it to the pool of empty pages. */ -static void release_flash_page(struct access_tracker *at) -{ - uint8_t page_index = page_list[0]; - void *flash; - - flash = flash_index_to_ph(page_index); - flash_physical_erase((uintptr_t)flash - CONFIG_PROGRAM_MEMORY_BASE, - CONFIG_FLASH_BANK_SIZE); - memmove(page_list, page_list + 1, - (ARRAY_SIZE(page_list) - 1) * sizeof(page_list[0])); - page_list[ARRAY_SIZE(page_list) - 1] = page_index; - at->list_index--; - master_at.list_index--; -} - -/* Reshuffle flash contents dropping deleted objects. */ -test_export_static enum ec_error_list compact_nvmem(void) -{ - const void *fence_ph; - enum ec_error_list rv = EC_SUCCESS; - size_t before; - struct nn_container *ch; - struct access_tracker at = {}; - int saved_object_count; - int final_delimiter_needed = 1; - - /* How much space was used before compaction. */ - before = total_used_size(); - - /* One page is enough even for the largest object. */ - ch = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - - /* - * Page where we should stop compaction, all pages before this would - * be recycled. - */ - fence_ph = master_at.mt.ph; - saved_object_count = 0; - - do { - switch (get_next_object(&at, ch, 0)) { - case EC_SUCCESS: - break; - - case EC_ERROR_MEMORY_ALLOCATION: - shared_mem_release(ch); - return EC_SUCCESS; - - default: - /* - * The error has been reported already. - * - * This must be compaction after startup with - * inconsistent nvmemory state, let's make sure the - * top page is recycled. - */ - if (at.mt.ph != fence_ph) - release_flash_page(&at); - shared_mem_release(ch); - return EC_ERROR_INVAL; - } - - /* Re-store the object in compacted flash. */ - switch (ch->container_type) { - case NN_OBJ_TUPLE: - case NN_OBJ_TPM_RESERVED: - case NN_OBJ_TPM_EVICTABLE: - ch->generation++; - if (save_container(ch) != EC_SUCCESS) { - ccprintf("%s: Saving FAILED\n", __func__); - shared_mem_release(ch); - return EC_ERROR_INVAL; - } - saved_object_count++; - break; - default: - break; - } - - if (at.list_index != 0) { - /* - * We are done with a pre-compaction page, use a - * delimiter to indicate that a bunch of objects are - * being deleted and finalize the delimiter once the - * old page is erased. - * - * Return the erased page to the pool of empty pages - * and rearrange the list of active pages. - */ - const void *del; - - if (saved_object_count) { - del = page_cursor(&master_at.mt); - add_delimiter(); - } - - release_flash_page(&at); -#if defined(NVMEM_TEST_BUILD) - if (failure_mode == TEST_FAIL_WHEN_COMPACTING) { - shared_mem_release(ch); - return EC_SUCCESS; - } -#endif - - if (saved_object_count) { - finalize_delimiter(del); - saved_object_count = 0; - } - /* - * No need in another delimiter if data ends on a page - * boundary. - */ - final_delimiter_needed = 0; - } else { - final_delimiter_needed = 1; - } - } while (at.mt.ph != fence_ph); - - shared_mem_release(ch); - - if (final_delimiter_needed) - add_final_delimiter(); - - CPRINTS("Compaction done, went from %zd to %zd bytes", before, - total_used_size()); - return rv; -} - -static void start_new_flash_page(size_t data_size) -{ - struct nn_page_header ph = {}; - - ph.data_offset = sizeof(ph) + data_size; - ph.page_number = master_at.mt.ph->page_number + 1; - ph.page_hash = calculate_page_header_hash(&ph); - master_at.list_index++; - if (master_at.list_index == ARRAY_SIZE(page_list)) - report_no_payload_failure(NVMEMF_PAGE_LIST_OVERFLOW); - - master_at.mt.ph = - (const void *)(((uintptr_t)page_list[master_at.list_index] * - CONFIG_FLASH_BANK_SIZE) + - CONFIG_PROGRAM_MEMORY_BASE); - - write_to_flash(master_at.mt.ph, &ph, sizeof(ph)); - master_at.mt.data_offset = sizeof(ph); -} - -/* - * Save in the flash an object represented by the passed in container. Add new - * pages to the list of used pages if necessary. - */ -static enum ec_error_list save_object(const struct nn_container *cont) -{ - const void *save_data = cont; - size_t save_size = aligned_container_size(cont); - size_t top_room; - -#if defined(NVMEM_TEST_BUILD) - if (failure_mode == TEST_FAILED_HASH) - save_size -= sizeof(uint32_t); -#endif - - top_room = CONFIG_FLASH_BANK_SIZE - master_at.mt.data_offset; - if (save_size >= top_room) { - - /* Let's finish the current page. */ - write_to_flash((uint8_t *)master_at.mt.ph + - master_at.mt.data_offset, - cont, top_room); - - /* Remaining data and size to be written on the next page. */ - save_data = (const void *)((uintptr_t)save_data + top_room); - save_size -= top_room; - start_new_flash_page(save_size); -#if defined(NVMEM_TEST_BUILD) - if (save_size && (failure_mode == TEST_SPANNING_PAGES)) { - ccprintf("%s:%d corrupting...\n", __func__, __LINE__); - return EC_SUCCESS; - } -#endif - } - - if (save_size) { - write_to_flash((uint8_t *)master_at.mt.ph + - master_at.mt.data_offset, - save_data, save_size); - master_at.mt.data_offset += save_size; - } - - return EC_SUCCESS; -} - -/* - * Functions to check if the passed in blob is all zeros or all 0xff, in both - * cases would be considered an uninitialized value. This is used when - * marshaling certaing structures and PCRs. - */ -static int is_all_value(const uint8_t *p, size_t size, uint8_t value) -{ - size_t i; - - for (i = 0; i < size; i++) - if (p[i] != value) - return 0; - - return 1; -} - -test_export_static int is_uninitialized(const void *p, size_t size) -{ - return is_all_value(p, size, 0xff); -} - -static int is_all_zero(const void *p, size_t size) -{ - return is_all_value(p, size, 0); -} - -static int is_empty(const void *pcr_base, size_t pcr_size) -{ - return is_uninitialized(pcr_base, pcr_size) || - is_all_zero(pcr_base, pcr_size); -} - -/* - * A convenience function checking if the passed in blob is not empty, and if - * so - save the blob in the destination memory. - * - * Return number of bytes placed in dst or zero, if the blob was empty. - */ -static size_t copy_pcr(const uint8_t *pcr_base, size_t pcr_size, uint8_t *dst) -{ - /* - * We rely on the fact that all 16 PCRs of every PCR bank saved in the - * NVMEM's reserved space are originally set to all zeros. - * - * If all 0xFF is read - this is considered an artifact of trying to - * retrieve PCRs from legacy flash snapshot from the state when PCRs - * were not saved in the reserved space at all, i.e. also indicates an - * empty PCR. - */ - if (is_empty(pcr_base, pcr_size)) - return 0; /* No need to save this. */ - - memcpy(dst, pcr_base, pcr_size); - - return pcr_size; -} - -/* - * A convenience structure and array, allowing quick access to PCR banks - * contained in the STATE_CLEAR_DATA:pcrSave field. This helps when - * marshailing/unmarshaling PCR contents. - */ -struct pcr_descriptor { - uint16_t pcr_array_offset; - uint8_t pcr_size; -} __packed; - -static const struct pcr_descriptor pcr_arrays[] = { - {offsetof(PCR_SAVE, sha1), SHA1_DIGEST_SIZE}, - {offsetof(PCR_SAVE, sha256), SHA256_DIGEST_SIZE}, - {offsetof(PCR_SAVE, sha384), SHA384_DIGEST_SIZE}, - {offsetof(PCR_SAVE, sha512), SHA512_DIGEST_SIZE} -}; -#define NUM_OF_PCRS (ARRAY_SIZE(pcr_arrays) * NUM_STATIC_PCR) - -/* Just in case we ever get to reducing the PCR set one way or another. */ -BUILD_ASSERT(ARRAY_SIZE(pcr_arrays) == 4); -BUILD_ASSERT(NUM_OF_PCRS == 64); -/* - * Iterate over PCRs contained in the STATE_CLEAR_DATA structure in the NVMEM - * cache and save nonempty ones in the flash. - */ -static void migrate_pcr(STATE_CLEAR_DATA *scd, size_t array_index, - size_t pcr_index, struct nn_container *ch) -{ - const struct pcr_descriptor *pdsc; - uint8_t *p_container_body; - uint8_t *pcr_base; - uint8_t reserved_index; /* Unique ID of this PCR in reserved storage. */ - - p_container_body = (uint8_t *)(ch + 1); - pdsc = pcr_arrays + array_index; - pcr_base = (uint8_t *)&scd->pcrSave + pdsc->pcr_array_offset + - pdsc->pcr_size * pcr_index; - reserved_index = NV_VIRTUAL_RESERVE_LAST + - array_index * NUM_STATIC_PCR + pcr_index; - - if (!copy_pcr(pcr_base, pdsc->pcr_size, p_container_body + 1)) - return; - - p_container_body[0] = reserved_index; - ch->size = pdsc->pcr_size + 1; - save_container(ch); -} - -/* - * Some NVMEM structures end up in the NVMEM cache with a wrong alignment. If - * a passed in pointer is not aligned at a 4 byte boundary, this function will - * save the 4 bytes above the blob in the passed in space and then move the - * blob up so that it is properly aligned. - */ -static void *preserve_struct(void *p, size_t size, uint32_t *preserved) -{ - uint32_t misalignment = ((uintptr_t)p & 3); - void *new_p; - - if (!misalignment) - return p; /* Nothing to adjust. */ - - memcpy(preserved, (uint8_t *)p + size, sizeof(*preserved)); - new_p = (void *)((((uintptr_t)p) + 3) & ~3); - memmove(new_p, p, size); - - return new_p; -} - -static void maybe_restore_struct(void *new_p, void *old_p, size_t size, - uint32_t *preserved) -{ - if (!memcmp(new_p, old_p, size)) - return; - - memmove(old_p, new_p, size); - memcpy((uint8_t *)old_p + size, preserved, sizeof(*preserved)); -} - -/* - * Note that PCRs are not marshaled here, but the rest of the structre, below - * and above the PCR array is. - */ -static uint16_t marshal_state_clear(STATE_CLEAR_DATA *scd, uint8_t *dst) -{ - PCR_AUTHVALUE *new_pav; - STATE_CLEAR_DATA *new_scd; - size_t bottom_size; - size_t i; - size_t top_size; - uint32_t preserved; - uint8_t *base; - int room; - - bottom_size = offsetof(STATE_CLEAR_DATA, pcrSave); - top_size = sizeof(scd->pcrAuthValues); - - if (is_empty(scd, bottom_size) && - is_empty(&scd->pcrAuthValues, top_size) && - is_empty(&scd->pcrSave.pcrCounter, sizeof(scd->pcrSave.pcrCounter))) - return 0; - - /* Marshaling STATE_CLEAR_DATA will never need this much. */ - room = CONFIG_FLASH_BANK_SIZE; - - new_scd = preserve_struct(scd, bottom_size, &preserved); - - base = dst; - - *dst++ = (!!new_scd->shEnable) | ((!!new_scd->ehEnable) << 1) | - ((!!new_scd->phEnableNV) << 2); - - memcpy(dst, &new_scd->platformAlg, sizeof(new_scd->platformAlg)); - dst += sizeof(new_scd->platformAlg); - - room -= (dst - base); - - TPM2B_DIGEST_Marshal(&new_scd->platformPolicy, &dst, &room); - - TPM2B_AUTH_Marshal(&new_scd->platformAuth, &dst, &room); - - memcpy(dst, &new_scd->pcrSave.pcrCounter, - sizeof(new_scd->pcrSave.pcrCounter)); - dst += sizeof(new_scd->pcrSave.pcrCounter); - room -= sizeof(new_scd->pcrSave.pcrCounter); - - maybe_restore_struct(new_scd, scd, bottom_size, &preserved); - - new_pav = preserve_struct(&scd->pcrAuthValues, top_size, &preserved); - for (i = 0; i < ARRAY_SIZE(new_scd->pcrAuthValues.auth); i++) - TPM2B_DIGEST_Marshal(new_pav->auth + i, &dst, &room); - - maybe_restore_struct(new_pav, &scd->pcrAuthValues, top_size, - &preserved); - - return dst - base; -} - -static uint16_t marshal_state_reset_data(STATE_RESET_DATA *srd, uint8_t *dst) -{ - STATE_RESET_DATA *new_srd; - uint32_t preserved; - uint8_t *base; - int room; - - if (is_empty(srd, sizeof(*srd))) - return 0; - - /* Marshaling STATE_RESET_DATA will never need this much. */ - room = CONFIG_FLASH_BANK_SIZE; - - new_srd = preserve_struct(srd, sizeof(*srd), &preserved); - - base = dst; - - TPM2B_AUTH_Marshal(&new_srd->nullProof, &dst, &room); - TPM2B_DIGEST_Marshal((TPM2B_DIGEST *)(&new_srd->nullSeed), &dst, &room); - UINT32_Marshal(&new_srd->clearCount, &dst, &room); - UINT64_Marshal(&new_srd->objectContextID, &dst, &room); - - memcpy(dst, new_srd->contextArray, sizeof(new_srd->contextArray)); - room -= sizeof(new_srd->contextArray); - dst += sizeof(new_srd->contextArray); - - memcpy(dst, &new_srd->contextCounter, sizeof(new_srd->contextCounter)); - room -= sizeof(new_srd->contextCounter); - dst += sizeof(new_srd->contextCounter); - - TPM2B_DIGEST_Marshal(&new_srd->commandAuditDigest, &dst, &room); - UINT32_Marshal(&new_srd->restartCount, &dst, &room); - UINT32_Marshal(&new_srd->pcrCounter, &dst, &room); - -#ifdef TPM_ALG_ECC - UINT64_Marshal(&new_srd->commitCounter, &dst, &room); - TPM2B_NONCE_Marshal(&new_srd->commitNonce, &dst, &room); - - memcpy(dst, new_srd->commitArray, sizeof(new_srd->commitArray)); - room -= sizeof(new_srd->commitArray); - dst += sizeof(new_srd->commitArray); -#endif - - maybe_restore_struct(new_srd, srd, sizeof(*srd), &preserved); - - return dst - base; -} - -/* - * Migrate all reserved objects found in the NVMEM cache after intializing - * from legacy NVMEM storage. - */ -static enum ec_error_list migrate_tpm_reserved(struct nn_container *ch) -{ - STATE_CLEAR_DATA *scd = NULL; - STATE_RESET_DATA *srd; - size_t pcr_type_index; - uint8_t *p_tpm_nvmem = nvmem_cache_base(NVMEM_TPM); - uint8_t *p_container_body = (uint8_t *)(ch + 1); - uint8_t index; - - ch->container_type = ch->container_type_copy = NN_OBJ_TPM_RESERVED; - - for (index = 0; index < NV_VIRTUAL_RESERVE_LAST; index++) { - NV_RESERVED_ITEM ri; - int copy_needed = 1; - - NvGetReserved(index, &ri); - p_container_body[0] = index; - - switch (index) { - case NV_STATE_CLEAR: - scd = (STATE_CLEAR_DATA *)(p_tpm_nvmem + ri.offset); - ri.size = - marshal_state_clear(scd, p_container_body + 1); - copy_needed = 0; - break; - - case NV_STATE_RESET: - srd = (STATE_RESET_DATA *)(p_tpm_nvmem + ri.offset); - ri.size = marshal_state_reset_data( - srd, p_container_body + 1); - copy_needed = 0; - break; - } - - if (copy_needed) { - /* - * Copy data into the stage area unless already done - * by marshaling function above. - */ - memcpy(p_container_body + 1, p_tpm_nvmem + ri.offset, - ri.size); - } - - ch->size = ri.size + 1; - save_container(ch); - } - - /* - * Now all components but the PCRs from STATE_CLEAR_DATA have been - * saved, let's deal with those PCR arrays. We want to save each PCR - * in a separate container, as if all PCRs are extended, the total - * combined size of the arrays would exceed flash page size. Also, - * PCRs are most likely to change one or very few at a time. - */ - for (pcr_type_index = 0; pcr_type_index < ARRAY_SIZE(pcr_arrays); - pcr_type_index++) { - size_t pcr_index; - - for (pcr_index = 0; pcr_index < NUM_STATIC_PCR; pcr_index++) - migrate_pcr(scd, pcr_type_index, pcr_index, ch); - } - - return EC_SUCCESS; -} - -/* - * Migrate all evictable objects found in the NVMEM cache after intializing - * from legacy NVMEM storage. - */ -static enum ec_error_list migrate_objects(struct nn_container *ch) -{ - uint32_t next_obj_base; - uint32_t obj_base; - uint32_t obj_size; - void *obj_addr; - - ch->container_type = ch->container_type_copy = NN_OBJ_TPM_EVICTABLE; - - obj_base = s_evictNvStart; - obj_addr = nvmem_cache_base(NVMEM_TPM) + obj_base; - memcpy(&next_obj_base, obj_addr, sizeof(next_obj_base)); - - while (next_obj_base && (next_obj_base <= s_evictNvEnd)) { - - obj_size = next_obj_base - obj_base - sizeof(obj_size); - memcpy(ch + 1, (uint32_t *)obj_addr + 1, obj_size); - - ch->size = obj_size; - save_container(ch); - - obj_base = next_obj_base; - obj_addr = nvmem_cache_base(NVMEM_TPM) + obj_base; - - memcpy(&next_obj_base, obj_addr, sizeof(next_obj_base)); - } - - return EC_SUCCESS; -} - -static enum ec_error_list migrate_tpm_nvmem(struct nn_container *ch) -{ - /* Call this to initialize NVMEM indices. */ - NvEarlyStageFindHandle(0); - - migrate_tpm_reserved(ch); - migrate_objects(ch); - - return EC_SUCCESS; -} - -static enum ec_error_list save_var(const uint8_t *key, uint8_t key_len, - const uint8_t *val, uint8_t val_len, - struct max_var_container *vc) -{ - const int total_size = - key_len + val_len + offsetof(struct max_var_container, body); - enum ec_error_list rv; - int local_alloc = !vc; - - if (local_alloc) { - vc = get_scratch_buffer(total_size); - vc->c_header.generation = 0; - } - - /* Fill up tuple body. */ - vc->t_header.key_len = key_len; - vc->t_header.val_len = val_len; - memcpy(vc->body, key, key_len); - memcpy(vc->body + key_len, val, val_len); - - /* Set up container header. */ - vc->c_header.container_type_copy = vc->c_header.container_type = - NN_OBJ_TUPLE; - vc->c_header.encrypted = 1; - vc->c_header.size = sizeof(struct tuple) + val_len + key_len; - - rv = save_container(&vc->c_header); - if (rv == EC_SUCCESS) - total_var_space += key_len + val_len; - - if (local_alloc) - shared_mem_release(vc); - - return rv; -} - -/* - * Migrate all (key, value) pairs found in the NVMEM cache after intializing - * from legacy NVMEM storage. - */ -static enum ec_error_list migrate_vars(struct nn_container *ch) -{ - const struct tuple *var; - - /* - * During migration (key, value) pairs need to be manually copied from - * the NVMEM cache. - */ - set_local_copy(); - var = NULL; - total_var_space = 0; - - while ((var = legacy_getnextvar(var)) != NULL) - save_var(var->data_, var->key_len, var->data_ + var->key_len, - var->val_len, (struct max_var_container *)ch); - - return EC_SUCCESS; -} - -static int erase_partition(unsigned int act_partition, int erase_backup) -{ - enum ec_error_list rv; - size_t flash_base; - - /* - * This is the first time we save using the new scheme, let's prepare - * the flash space. First determine which half is the backup now and - * erase it. - */ - flash_base = (act_partition ^ erase_backup) ? CONFIG_FLASH_NVMEM_BASE_A - : CONFIG_FLASH_NVMEM_BASE_B; - flash_base -= CONFIG_PROGRAM_MEMORY_BASE; - - rv = flash_physical_erase(flash_base, NVMEM_PARTITION_SIZE); - - if (rv != EC_SUCCESS) { - ccprintf("%s: flash erase failed\n", __func__); - return -rv; - } - - return flash_base + CONFIG_FLASH_BANK_SIZE; -} - -/* - * This function is called once in a lifetime, when Cr50 boots up and a legacy - * partition if found in the flash. - */ -enum ec_error_list new_nvmem_migrate(unsigned int act_partition) -{ - int flash_base; - int i; - int j; - struct nn_container *ch; - - if (!crypto_enabled()) - return EC_ERROR_INVAL; - - /* - * This is the first time we save using the new scheme, let's prepare - * the flash space. First determine which half is the backup now and - * erase it. - */ - flash_base = erase_partition(act_partition, 1); - if (flash_base < 0) { - ccprintf("%s: backup partition erase failed\n", __func__); - return -flash_base; - } - - ch = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - - lock_mutex(__LINE__); - - /* Populate half of page_list with available page offsets. */ - for (i = 0; i < ARRAY_SIZE(page_list) / 2; i++) - page_list[i] = flash_base / CONFIG_FLASH_BANK_SIZE + i; - - set_first_page_header(); - - ch->encrypted = 1; - ch->generation = 0; - - migrate_vars(ch); - migrate_tpm_nvmem(ch); - - shared_mem_release(ch); - - add_final_delimiter(); - - unlock_mutex(__LINE__); - - if (browse_flash_contents(0) != EC_SUCCESS) - /* Never returns. */ - report_no_payload_failure(NVMEMF_MIGRATION_FAILURE); - - CPRINTS("Migration success, used %zd bytes of flash", - total_used_size()); - - /* - * Now we can erase the active partition and add its flash to the pool. - */ - flash_base = erase_partition(act_partition, 0); - if (flash_base < 0) - /* Never returns. */ - report_no_payload_failure(NVMEMF_LEGACY_ERASE_FAILURE); - - /* - * Populate the second half of the page_list with pages retrieved from - * legacy partition. - */ - for (j = 0; j < ARRAY_SIZE(page_list) / 2; j++) - page_list[i + j] = flash_base / CONFIG_FLASH_BANK_SIZE + j; - - return EC_SUCCESS; -} - -/* Check if the passed in flash page is empty, if not - erase it. */ -static void verify_empty_page(void *ph) -{ - uint32_t *word_p = ph; - size_t i; - - for (i = 0; i < (CONFIG_FLASH_BANK_SIZE / sizeof(*word_p)); i++) { - if (word_p[i] != (uint32_t)~0) { - CPRINTS("%s: corrupted page at %pP!", __func__, word_p); - flash_physical_erase((uintptr_t)word_p - - CONFIG_PROGRAM_MEMORY_BASE, - CONFIG_FLASH_BANK_SIZE); - break; - } - } -} - -/* - * At startup initialize the list of pages which contain NVMEM data and erased - * pages. The list (in fact an array containing indices of the pages) is - * sorted by the page number found in the page header. Pages which do not - * contain valid page header are checked to be erased and are placed at the - * tail of the list. - */ -static void init_page_list(void) -{ - size_t i; - size_t j; - size_t page_list_index = 0; - size_t tail_index; - struct nn_page_header *ph; - - tail_index = ARRAY_SIZE(page_list); - - for (i = 0; i < ARRAY_SIZE(page_list); i++) { - uint32_t page_index; - - /* - * This will yield indices of top pages first, first from the - * bottom half of the flash, and then from the top half. We - * know that flash is 512K in size, and pages are 2K in size, - * the indices will be in 123..127 and 251..255 range. - */ - if (i < (ARRAY_SIZE(page_list) / 2)) { - page_index = (CONFIG_FLASH_NEW_NVMEM_BASE_A - - CONFIG_PROGRAM_MEMORY_BASE) / - CONFIG_FLASH_BANK_SIZE + - i; - } else { - page_index = (CONFIG_FLASH_NEW_NVMEM_BASE_B - - CONFIG_PROGRAM_MEMORY_BASE) / - CONFIG_FLASH_BANK_SIZE - - ARRAY_SIZE(page_list) / 2 + i; - } - - ph = flash_index_to_ph(page_index); - - if (!page_header_is_valid(ph)) { - /* - * this is not a valid page, let's plug it in into the - * tail of the list. - */ - page_list[--tail_index] = page_index; - verify_empty_page(ph); - continue; - } - - /* This seems a valid page, let's put it in order. */ - for (j = 0; j < page_list_index; j++) { - struct nn_page_header *prev_ph; - - prev_ph = list_element_to_ph(j); - - if (prev_ph->page_number > ph->page_number) { - /* Need to move up. */ - memmove(page_list + j + 1, page_list + j, - sizeof(page_list[0]) * - (page_list_index - j)); - break; - } - } - - page_list[j] = page_index; - page_list_index++; - } - - if (!page_list_index) { - CPRINTS("Init nvmem from scratch"); - set_first_page_header(); - page_list_index++; - } -} - -/* - * The passed in pointer contains marshaled STATE_CLEAR structure as retrieved - * from flash. This function unmarshals it and places in the NVMEM cache where - * it belongs. Note that PCRs were not marshaled. - */ -static void unmarshal_state_clear(uint8_t *pad, int size, uint32_t offset) -{ - STATE_CLEAR_DATA *real_scd; - STATE_CLEAR_DATA *scd; - size_t i; - uint32_t preserved; - uint8_t booleans; - - real_scd = (STATE_CLEAR_DATA *)((uint8_t *)nvmem_cache_base(NVMEM_TPM) + - offset); - - memset(real_scd, 0, sizeof(*real_scd)); - if (!size) - return; - - memcpy(&preserved, real_scd + 1, sizeof(preserved)); - - scd = (void *)(((uintptr_t)real_scd + 3) & ~3); - - /* Need proper unmarshal. */ - booleans = *pad++; - scd->shEnable = !!(booleans & 1); - scd->ehEnable = !!(booleans & (1 << 1)); - scd->phEnableNV = !!(booleans & (1 << 2)); - size--; - - memcpy(&scd->platformAlg, pad, sizeof(scd->platformAlg)); - pad += sizeof(scd->platformAlg); - size -= sizeof(scd->platformAlg); - - TPM2B_DIGEST_Unmarshal(&scd->platformPolicy, &pad, &size); - TPM2B_AUTH_Unmarshal(&scd->platformAuth, &pad, &size); - - memcpy(&scd->pcrSave.pcrCounter, pad, sizeof(scd->pcrSave.pcrCounter)); - pad += sizeof(scd->pcrSave.pcrCounter); - size -= sizeof(scd->pcrSave.pcrCounter); - - for (i = 0; i < ARRAY_SIZE(scd->pcrAuthValues.auth); i++) - TPM2B_DIGEST_Unmarshal(scd->pcrAuthValues.auth + i, &pad, - &size); - - memmove(real_scd, scd, sizeof(*scd)); - memcpy(real_scd + 1, &preserved, sizeof(preserved)); -} - -/* - * The passed in pointer contains marshaled STATE_RESET structure as retrieved - * from flash. This function unmarshals it and places in the NVMEM cache where - * it belongs. - */ -static void unmarshal_state_reset(uint8_t *pad, int size, uint32_t offset) -{ - STATE_RESET_DATA *real_srd; - STATE_RESET_DATA *srd; - uint32_t preserved; - - real_srd = (STATE_RESET_DATA *)((uint8_t *)nvmem_cache_base(NVMEM_TPM) + - offset); - - memset(real_srd, 0, sizeof(*real_srd)); - if (!size) - return; - - memcpy(&preserved, real_srd + 1, sizeof(preserved)); - - srd = (void *)(((uintptr_t)real_srd + 3) & ~3); - - TPM2B_AUTH_Unmarshal(&srd->nullProof, &pad, &size); - TPM2B_DIGEST_Unmarshal((TPM2B_DIGEST *)(&srd->nullSeed), &pad, &size); - UINT32_Unmarshal(&srd->clearCount, &pad, &size); - UINT64_Marshal(&srd->objectContextID, &pad, &size); - - memcpy(srd->contextArray, pad, sizeof(srd->contextArray)); - size -= sizeof(srd->contextArray); - pad += sizeof(srd->contextArray); - - memcpy(&srd->contextCounter, pad, sizeof(srd->contextCounter)); - size -= sizeof(srd->contextCounter); - pad += sizeof(srd->contextCounter); - - TPM2B_DIGEST_Unmarshal(&srd->commandAuditDigest, &pad, &size); - UINT32_Unmarshal(&srd->restartCount, &pad, &size); - UINT32_Unmarshal(&srd->pcrCounter, &pad, &size); - -#ifdef TPM_ALG_ECC - UINT64_Unmarshal(&srd->commitCounter, &pad, &size); - TPM2B_NONCE_Unmarshal(&srd->commitNonce, &pad, &size); - - memcpy(srd->commitArray, pad, sizeof(srd->commitArray)); - size -= sizeof(srd->commitArray); -#endif - - memmove(real_srd, srd, sizeof(*srd)); - memcpy(real_srd + 1, &preserved, sizeof(preserved)); -} - -/* - * Based on the passed in index, find the location of the PCR in the NVMEM - * cache and copy it there. - */ -static void restore_pcr(size_t pcr_index, uint8_t *pad, size_t size) -{ - const STATE_CLEAR_DATA *scd; - const struct pcr_descriptor *pcrd; - void *cached; /* This PCR's position in the NVMEM cache. */ - - if (pcr_index > NUM_OF_PCRS) - return; /* This is an error. */ - - pcrd = pcr_arrays + pcr_index / NUM_STATIC_PCR; - if (pcrd->pcr_size != size) - return; /* This is an error. */ - - scd = get_scd(); - cached = (uint8_t *)&scd->pcrSave + pcrd->pcr_array_offset + - pcrd->pcr_size * (pcr_index % NUM_STATIC_PCR); - - memcpy(cached, pad, size); -} - -/* Restore a reserved object found in flash on initialization. */ -static void restore_reserved(void *pad, size_t size, uint8_t *bitmap) -{ - NV_RESERVED_ITEM ri; - uint16_t type; - void *cached; - - /* - * Index is saved as a single byte, update pad to point at the - * payload. - */ - type = *(uint8_t *)pad++; - size--; - - if (type < NV_VIRTUAL_RESERVE_LAST) { - NvGetReserved(type, &ri); - - bitmap_bit_set(bitmap, type); - - switch (type) { - case NV_STATE_CLEAR: - unmarshal_state_clear(pad, size, ri.offset); - break; - - case NV_STATE_RESET: - unmarshal_state_reset(pad, size, ri.offset); - break; - - default: - cached = ((uint8_t *)nvmem_cache_base(NVMEM_TPM) + - ri.offset); - memcpy(cached, pad, size); - break; - } - return; - } - - restore_pcr(type - NV_VIRTUAL_RESERVE_LAST, pad, size); -} - -/* Restore an evictable object found in flash on initialization. */ -static void restore_object(void *pad, size_t size) -{ - uint8_t *dest; - - if (!next_evict_obj_base) - next_evict_obj_base = s_evictNvStart; - - dest = ((uint8_t *)nvmem_cache_base(NVMEM_TPM) + next_evict_obj_base); - next_evict_obj_base += size + sizeof(next_evict_obj_base); - memcpy(dest, &next_evict_obj_base, sizeof(next_evict_obj_base)); - - dest += sizeof(next_evict_obj_base); - memcpy(dest, pad, size); - dest += size; - - memset(dest, 0, sizeof(next_evict_obj_base)); -} - -/* - * When starting from scratch (flash fully erased) there would be no reserved - * objects in NVMEM, and for the commit to work properly, every single - * reserved object needs to be present in the flash so that its value is - * compared with the cache contents. - * - * There is also an off chance of a bug where a reserved value is lost in the - * flash - it would never be reinstated even after TPM reinitializes. - * - * The reserved_bitmap array is a bitmap of all detected reserved objects, - * those not in the array are initialized to a dummy initial value. - */ -static enum ec_error_list verify_reserved(uint8_t *reserved_bitmap, - struct nn_container *ch) -{ - enum ec_error_list rv; - int i; - uint8_t *container_body; - int delimiter_needed = 0; - - /* All uninitted reserved objects set to zero. */ - memset(ch, 0, CONFIG_FLASH_BANK_SIZE); - - ch->container_type = ch->container_type_copy = NN_OBJ_TPM_RESERVED; - ch->encrypted = 1; - container_body = (uint8_t *)(ch + 1); - - rv = EC_SUCCESS; - - for (i = 0; i < NV_VIRTUAL_RESERVE_LAST; i++) { - NV_RESERVED_ITEM ri; - - if (bitmap_bit_check(reserved_bitmap, i)) - continue; - - NvGetReserved(i, &ri); - container_body[0] = i; - - switch (i) { - /* - * No need to save these on initialization from - * scratch, unmarshaling code will properly expand - * size of zero. - */ - case NV_STATE_CLEAR: - case NV_STATE_RESET: - ri.size = 0; - break; - - /* - * This is used for Ram Index field, prepended by - * size. Set the size to minimum, the size of the size - * field. - */ - case NV_RAM_INDEX_SPACE: - ri.size = sizeof(uint32_t); - break; - - default: - break; - } - - delimiter_needed = 1; - - ch->size = ri.size + 1; - rv = save_container(ch); - - /* Clean up encrypted contents. */ - memset(container_body + 1, 0, ri.size); - - if (rv != EC_SUCCESS) - break; - } - - if (delimiter_needed && (rv == EC_SUCCESS)) - add_final_delimiter(); - - return rv; -} - -static enum ec_error_list invalidate_object(const struct nn_container *ch) -{ - struct nn_container c_copy; - - c_copy = *ch; - c_copy.container_type = NN_OBJ_OLD_COPY; - - return write_to_flash(ch, &c_copy, sizeof(uint32_t)); -} - -static enum ec_error_list delete_object(const struct access_tracker *at, - struct nn_container *ch) -{ - const void *flash_ch; - - flash_ch = page_cursor(&at->ct); - - if (memcmp(ch, flash_ch, sizeof(uint32_t))) - report_no_payload_failure(NVMEMF_PRE_ERASE_MISMATCH); - - if (!del_candidates) - return invalidate_object(flash_ch); - - /* - * Do not delete the object yet, save it in the list of delete - * candidates. - */ - if (del_candidates->num_candidates == - ARRAY_SIZE(del_candidates->candidates)) - report_no_payload_failure(NVMEMF_EXCESS_DELETE_OBJECTS); - - del_candidates->candidates[del_candidates->num_candidates++] = flash_ch; - return EC_SUCCESS; -} - -static enum ec_error_list verify_last_section( - const struct page_tracker *prev_del, struct nn_container *ch) -{ - /* - * This is very inefficient, but we do this only when recovering from - * botched nvmem saves. - * - * For each object found between prev_del and last_del we need to - * check if there are earlier instances of these objects in the flash - * which are not yet deleted, and delete them if found. - */ - struct object { - uint8_t cont_type; - union { - uint32_t handle; /* For evictables. */ - uint8_t id; /* For reserved objects. */ - struct { /* For tuples. */ - uint32_t key_hash; - uint8_t key_len; - }; - }; - }; - struct new_objects { - uint8_t num_objects; - struct object objects[2 * MAX_DELETE_CANDIDATES]; - }; - - struct access_tracker at; - struct new_objects *newobjs; - struct object *po; - uint8_t ctype; - struct page_tracker top_del; - struct max_var_container *vc; - int i; - - newobjs = get_scratch_buffer(sizeof(struct new_objects)); - - at.mt = *prev_del; - for (i = 0; i < ARRAY_SIZE(page_list); i++) - if (list_element_to_ph(i) == at.mt.ph) { - at.list_index = i; - break; - } - - po = newobjs->objects; - - while (get_next_object(&at, ch, 0) == EC_SUCCESS) { - ctype = ch->container_type; - - /* Speculative assignment, might be unused. */ - po->cont_type = ctype; - switch (ctype) { - case NN_OBJ_TPM_RESERVED: - po->id = *((uint8_t *)(ch + 1)); - break; - - case NN_OBJ_TPM_EVICTABLE: - po->handle = *((uint32_t *)(ch + 1)); - break; - - case NN_OBJ_TUPLE: - vc = (struct max_var_container *)ch; - po->key_len = vc->t_header.key_len; - app_compute_hash_wrapper(vc->t_header.data_, - po->key_len, &po->key_hash, - sizeof(po->key_hash)); - break; - default: - continue; - } - if (++(newobjs->num_objects) == ARRAY_SIZE(newobjs->objects)) - /* Never returns. */ - report_no_payload_failure(NVMEMF_SECTION_VERIFY); - po++; - } - - /* - * Last object read from flash should have been a non-finalized - * delimiter. - */ - if (ch->container_type != NN_OBJ_TRANSACTION_DEL) { - struct nvmem_failure_payload fp; - - fp.failure_type = NVMEMF_UNEXPECTED_LAST_OBJ; - fp.last_obj_type = ch->container_type; - /* Never returns. */ - report_failure(&fp, sizeof(fp.last_obj_type)); - } - - /* - * Now we have a cache of of objects which were updated but their old - * instances could have been left in the flash. Let's iterate over the - * flash and delete those if found. - */ - memset(&at, 0, sizeof(at)); - while ((at.mt.ph != prev_del->ph) && - (at.mt.data_offset != prev_del->data_offset)) { - size_t i; - size_t key_size; - uint32_t key; - - if (get_next_object(&at, ch, 0) != EC_SUCCESS) - report_no_payload_failure(NVMEMF_MISSING_OBJECT); - - ctype = ch->container_type; - - switch (ctype) { - case NN_OBJ_TPM_RESERVED: - key = *((uint8_t *)(ch + 1)); - key_size = sizeof(uint8_t); - break; - - case NN_OBJ_TPM_EVICTABLE: - key = *((uint32_t *)(ch + 1)); - key_size = sizeof(uint32_t); - break; - - case NN_OBJ_TUPLE: - vc = (struct max_var_container *)ch; - key_size = vc->t_header.key_len; - app_compute_hash_wrapper(vc->t_header.data_, key_size, - &key, sizeof(key)); - break; - - default: - continue; - } - - for (i = 0, po = newobjs->objects; i < newobjs->num_objects; - i++, po++) { - if (po->cont_type != ctype) - continue; - - if ((ctype == NN_OBJ_TPM_RESERVED) && (po->id != key)) - continue; - - if ((ctype == NN_OBJ_TPM_EVICTABLE) && - (po->handle != key)) - continue; - - if ((ctype == NN_OBJ_TUPLE) && - ((po->key_len != key_size) || - (key != po->key_hash))) - continue; - - /* - * This indeed is a leftover which needs to be - * deleted. - */ - delete_object(&at, ch); - } - } - shared_mem_release(newobjs); - if (master_at.mt.data_offset > sizeof(struct nn_page_header)) { - top_del.ph = master_at.mt.ph; - top_del.data_offset = - master_at.mt.data_offset - sizeof(struct nn_container); - } else { - top_del.ph = list_element_to_ph(master_at.list_index - 1); - top_del.data_offset = - CONFIG_FLASH_BANK_SIZE - -sizeof(struct nn_container); - } - - return finalize_delimiter(page_cursor(&top_del)); -} - -/* - * This function is called during initialization after the entire flash - * contents were scanned, to verify that flash is in a valid state. - */ -static enum ec_error_list verify_delimiter(struct nn_container *nc) -{ - enum ec_error_list rv; - /* Used to read starting at last good delimiter. */ - struct access_tracker dpt = {}; - - if ((master_at.list_index == 0) && - (master_at.mt.data_offset == sizeof(struct nn_page_header))) { - /* This must be an init from scratch, no delimiter yet. */ - if (!master_at.dt.ph) - return EC_SUCCESS; - - /* This is bad, will have to wipe out everything. */ - return EC_ERROR_INVAL; - } - - if (nc->container_type_copy == NN_OBJ_TRANSACTION_DEL) { - if (nc->container_type == NN_OBJ_OLD_COPY) - return EC_SUCCESS; - /* - * The delimiter is there, but it has not been finalized, - * which means that there might be objects in the flash which - * were not updated after the last delimiter was written. - */ - return verify_last_section(&master_at.dt, nc); - } - - /* - * The delimiter is not there, everything above the last verified - * delimiter must go. - * - * First, create a context for retrieving objects starting at the last - * valid delimiter, make sure list index is set properly. - */ - dpt.mt = master_at.dt; - if (dpt.mt.ph == master_at.mt.ph) { - dpt.list_index = master_at.list_index; - } else { - uint8_t i; - - for (i = 0; i < master_at.list_index; i++) - if (list_element_to_ph(i) == dpt.mt.ph) { - dpt.list_index = i; - break; - } - } - - while ((rv = get_next_object(&dpt, nc, 0)) == EC_SUCCESS) - delete_object(&dpt, nc); - - if (rv == EC_ERROR_INVAL) { - /* - * There must have been an interruption of the saving process, - * let's wipe out flash to the end of the current page and - * compact the storage. - */ - size_t remainder_size; - const void *p = page_cursor(&master_at.ct); - - if (dpt.ct.ph != dpt.mt.ph) { - /* - * The last retrieved object is spanning flash page - * boundary. - * - * If this is not the last object in the flash, this - * is an unrecoverable init failure. - */ - if ((dpt.mt.ph != master_at.mt.ph) || - (list_element_to_ph(dpt.list_index - 1) != - dpt.ct.ph)) - report_no_payload_failure( - NVMEMF_CORRUPTED_INIT); - /* - * Let's erase the page where the last object spilled - * into. - */ - flash_physical_erase((uintptr_t)dpt.mt.ph - - CONFIG_PROGRAM_MEMORY_BASE, - CONFIG_FLASH_BANK_SIZE); - /* - * And move it to the available pages part of the - * pages list. - */ - master_at.list_index -= 1; - master_at.mt = dpt.ct; - } - - remainder_size = CONFIG_FLASH_BANK_SIZE - dpt.ct.data_offset; - memset(nc, 0, remainder_size); - write_to_flash(p, nc, remainder_size); - /* Make sure compaction starts with the new page. */ - start_new_flash_page(0); - compact_nvmem(); - } else { - /* Add delimiter at the very top. */ - add_final_delimiter(); - } - - /* Need to re-read the NVMEM cache. */ - return EC_ERROR_TRY_AGAIN; -} - -/* - * At startup iterate over flash contents and move TPM objects into the - * appropriate locations in the NVMEM cache. - */ -static enum ec_error_list retrieve_nvmem_contents(void) -{ - int rv; - int tries; - struct max_var_container *vc; - struct nn_container *nc; - uint8_t res_bitmap[(NV_PSEUDO_RESERVE_LAST + 7) / 8]; - - /* No saved object will exceed CONFIG_FLASH_BANK_SIZE in size. */ - nc = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - - /* - * Depending on the state of flash, we might have to do this three - * times. - */ - for (tries = 0; tries < 3; tries++) { - memset(&master_at, 0, sizeof(master_at)); - memset(nvmem_cache_base(NVMEM_TPM), 0, - nvmem_user_sizes[NVMEM_TPM]); - memset(res_bitmap, 0, sizeof(res_bitmap)); - next_evict_obj_base = 0; - - while ((rv = get_next_object(&master_at, nc, 0)) == - EC_SUCCESS) { - switch (nc->container_type) { - case NN_OBJ_TUPLE: - vc = (struct max_var_container *)nc; - total_var_space += vc->t_header.key_len + - vc->t_header.val_len; - break; /* Keep tuples in flash. */ - case NN_OBJ_TPM_RESERVED: - restore_reserved(nc + 1, nc->size, res_bitmap); - break; - - case NN_OBJ_TPM_EVICTABLE: - restore_object(nc + 1, nc->size); - break; - default: - break; - } - } - - rv = verify_delimiter(nc); - - if (rv != EC_ERROR_TRY_AGAIN) - break; - } - - if (rv != EC_SUCCESS) - report_no_payload_failure(NVMEMF_UNRECOVERABLE_INIT); - - rv = verify_reserved(res_bitmap, nc); - - shared_mem_release(nc); - - return rv; -} - -enum ec_error_list new_nvmem_init(void) -{ - enum ec_error_list rv; - timestamp_t start, init; - - if (!crypto_enabled()) - return EC_ERROR_INVAL; - - init_in_progress = 1; - - total_var_space = 0; - - /* Initialize NVMEM indices. */ - NvEarlyStageFindHandle(0); - - lock_mutex(__LINE__); - - init_page_list(); - - start = get_time(); - - rv = retrieve_nvmem_contents(); - - init = get_time(); - - unlock_mutex(__LINE__); - - init_in_progress = 0; - - CPRINTS("init took %d", (uint32_t)(init.val - start.val)); - - return rv; -} - -/* - * Browse through the flash storage and save all evictable objects' offsets in - * the passed in array. This is used to keep track of objects added or deleted - * by the TPM library. - */ -test_export_static size_t init_object_offsets(uint16_t *offsets, size_t count) -{ - size_t num_objects = 0; - uint32_t next_obj_base; - uint32_t obj_base; - void *obj_addr; - - obj_base = s_evictNvStart; - obj_addr = (uint8_t *)nvmem_cache_base(NVMEM_TPM) + obj_base; - memcpy(&next_obj_base, obj_addr, sizeof(next_obj_base)); - - while (next_obj_base && (next_obj_base <= s_evictNvEnd)) { - if (num_objects == count) { - /* What do we do here?! */ - ccprintf("Too many objects!\n"); - break; - } - - offsets[num_objects++] = - obj_base - s_evictNvStart + sizeof(next_obj_base); - - obj_addr = nvmem_cache_base(NVMEM_TPM) + next_obj_base; - obj_base = next_obj_base; - memcpy(&next_obj_base, obj_addr, sizeof(next_obj_base)); - } - - return num_objects; -} - -static enum ec_error_list update_object(const struct access_tracker *at, - struct nn_container *ch, - void *cached_object, size_t new_size) -{ - size_t copy_size = new_size; - size_t preserved_size; - uint32_t preserved_hash; - uint8_t *dst = (uint8_t *)(ch + 1); - - preserved_size = ch->size; - preserved_hash = ch->container_hash; - - /* - * Need to copy data into the container, skip reserved type if it is a - * reserved object. - */ - if (ch->container_type == NN_OBJ_TPM_RESERVED) { - dst++; - copy_size--; - } - memcpy(dst, cached_object, copy_size); - - ch->generation++; - ch->size = new_size; - save_container(ch); - - ch->generation--; - ch->size = preserved_size; - ch->container_hash = preserved_hash; - return delete_object(at, ch); -} - -static enum ec_error_list update_pcr(const struct access_tracker *at, - struct nn_container *ch, uint8_t index, - uint8_t *cached) -{ - uint8_t preserved; - - cached--; - preserved = cached[0]; - cached[0] = index; - update_object(at, ch, cached, ch->size); - cached[0] = preserved; - - return EC_SUCCESS; -} - -static enum ec_error_list save_pcr(struct nn_container *ch, - uint8_t reserved_index, const void *pcr, - size_t pcr_size) -{ - uint8_t *container_body; - - ch->container_type = ch->container_type_copy = NN_OBJ_TPM_RESERVED; - ch->encrypted = 1; - ch->size = pcr_size + 1; - ch->generation = 0; - - container_body = (uint8_t *)(ch + 1); - container_body[0] = reserved_index; - memcpy(container_body + 1, pcr, pcr_size); - - return save_container(ch); -} - -static enum ec_error_list maybe_save_pcr(struct nn_container *ch, - size_t pcr_index) -{ - const STATE_CLEAR_DATA *scd; - const struct pcr_descriptor *pcrd; - const void *cached; - size_t pcr_size; - - pcrd = pcr_arrays + pcr_index / NUM_STATIC_PCR; - scd = get_scd(); - - pcr_size = pcrd->pcr_size; - - cached = (const uint8_t *)&scd->pcrSave + pcrd->pcr_array_offset + - pcr_size * (pcr_index % NUM_STATIC_PCR); - - if (is_empty(cached, pcr_size)) - return EC_SUCCESS; - - return save_pcr(ch, pcr_index + NV_VIRTUAL_RESERVE_LAST, cached, - pcr_size); -} - -/* - * The process_XXX functions below are used to check and if necessary add, - * update or delete objects from the flash based on the NVMEM cache - * contents. - */ -static enum ec_error_list process_pcr(const struct access_tracker *at, - struct nn_container *ch, uint8_t index, - const uint8_t *saved, uint8_t *pcr_bitmap) -{ - STATE_CLEAR_DATA *scd; - const struct pcr_descriptor *pcrd; - size_t pcr_bitmap_index; - size_t pcr_index; - size_t pcr_size; - uint8_t *cached; - - pcr_bitmap_index = index - NV_VIRTUAL_RESERVE_LAST; - - if (pcr_bitmap_index > NUM_OF_PCRS) - return EC_ERROR_INVAL; - - pcrd = pcr_arrays + pcr_bitmap_index / NUM_STATIC_PCR; - pcr_index = pcr_bitmap_index % NUM_STATIC_PCR; - - pcr_size = pcrd->pcr_size; - - if (pcr_size != (ch->size - 1)) - return EC_ERROR_INVAL; /* This is an error. */ - - /* Find out base address of the cached PCR. */ - scd = get_scd(); - cached = (uint8_t *)&scd->pcrSave + pcrd->pcr_array_offset + - pcr_size * pcr_index; - - /* Set bitmap bit to indicate that this PCR was looked at. */ - bitmap_bit_set(pcr_bitmap, pcr_bitmap_index); - - if (memcmp(saved, cached, pcr_size)) - return update_pcr(at, ch, index, cached); - - return EC_SUCCESS; -} - -static enum ec_error_list process_reserved(const struct access_tracker *at, - struct nn_container *ch, - uint8_t *pcr_bitmap) -{ - NV_RESERVED_ITEM ri; - size_t new_size; - uint8_t *saved; - uint8_t index; - void *cached; - - /* - * Find out this object's location in the cache (first byte of the - * contents is the index of the reserved object. - */ - saved = (uint8_t *)(ch + 1); - index = *saved++; - - NvGetReserved(index, &ri); - - if (ri.size) { - void *marshaled; - - cached = (uint8_t *)nvmem_cache_base(NVMEM_TPM) + ri.offset; - - /* - * For NV_STATE_CLEAR and NV_STATE_RESET cases Let's marshal - * cached data to be able to compare it with saved data. - */ - if (index == NV_STATE_CLEAR) { - marshaled = ((uint8_t *)(ch + 1)) + ch->size; - new_size = marshal_state_clear(cached, marshaled); - cached = marshaled; - } else if (index == NV_STATE_RESET) { - marshaled = ((uint8_t *)(ch + 1)) + ch->size; - new_size = marshal_state_reset_data(cached, marshaled); - cached = marshaled; - } else { - new_size = ri.size; - } - - if ((new_size == (ch->size - 1)) && - !memcmp(saved, cached, new_size)) - return EC_SUCCESS; - - return update_object(at, ch, cached, new_size + 1); - } - - /* This must be a PCR. */ - return process_pcr(at, ch, index, saved, pcr_bitmap); -} - -static enum ec_error_list process_object(const struct access_tracker *at, - struct nn_container *ch, - uint16_t *tpm_object_offsets, - size_t *num_objects) -{ - size_t i; - uint32_t cached_size; - uint32_t cached_type; - uint32_t flash_type; - uint32_t next_obj_base; - uint8_t *evict_start; - void *pcache; - - evict_start = (uint8_t *)nvmem_cache_base(NVMEM_TPM) + s_evictNvStart; - memcpy(&flash_type, ch + 1, sizeof(flash_type)); - for (i = 0; i < *num_objects; i++) { - - /* Find TPM object in the NVMEM cache. */ - pcache = evict_start + tpm_object_offsets[i]; - memcpy(&cached_type, pcache, sizeof(cached_type)); - if (cached_type == flash_type) - break; - } - - if (i == *num_objects) { - /* - * This object is not in the cache any more, delete it from - * flash. - */ - return delete_object(at, ch); - } - - memcpy(&next_obj_base, (uint8_t *)pcache - sizeof(next_obj_base), - sizeof(next_obj_base)); - cached_size = next_obj_base - s_evictNvStart - tpm_object_offsets[i]; - if ((cached_size != ch->size) || memcmp(ch + 1, pcache, cached_size)) { - /* - * Object changed. Let's delete the old copy and save the new - * one. - */ - update_object(at, ch, pcache, ch->size); - } - - tpm_object_offsets[i] = tpm_object_offsets[*num_objects - 1]; - *num_objects -= 1; - - return EC_SUCCESS; -} - -static enum ec_error_list save_new_object(uint16_t obj_base, void *buf) -{ - size_t obj_size; - struct nn_container *ch = buf; - uint32_t next_obj_base; - void *obj_addr; - - obj_addr = (uint8_t *)nvmem_cache_base(NVMEM_TPM) + obj_base + - s_evictNvStart; - memcpy(&next_obj_base, obj_addr - sizeof(next_obj_base), - sizeof(next_obj_base)); - obj_size = next_obj_base - obj_base - s_evictNvStart; - - ch->container_type_copy = ch->container_type = NN_OBJ_TPM_EVICTABLE; - ch->encrypted = 1; - ch->size = obj_size; - ch->generation = 0; - memcpy(ch + 1, obj_addr, obj_size); - - return save_container(ch); -} - -static enum ec_error_list new_nvmem_save_(void) -{ - const void *fence_ph; - size_t i; - size_t num_objs; - struct nn_container *ch; - struct access_tracker at = {}; - uint16_t fence_offset; - /* We don't foresee ever storing this many objects. */ - uint16_t tpm_object_offsets[MAX_STORED_EVICTABLE_OBJECTS]; - uint8_t pcr_bitmap[(NUM_STATIC_PCR * ARRAY_SIZE(pcr_arrays) + 7) / 8]; - - /* See if compaction is needed. */ - if (master_at.list_index >= (ARRAY_SIZE(page_list) - 3)) { - enum ec_error_list rv; - - rv = compact_nvmem(); - if (rv != EC_SUCCESS) - return rv; - } - - fence_ph = master_at.mt.ph; - fence_offset = master_at.mt.data_offset; - - num_objs = init_object_offsets(tpm_object_offsets, - ARRAY_SIZE(tpm_object_offsets)); - - memset(pcr_bitmap, 0, sizeof(pcr_bitmap)); - del_candidates = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE + - sizeof(struct delete_candidates)); - ch = (void *)(del_candidates + 1); - del_candidates->num_candidates = 0; - - while ((fence_ph != at.mt.ph) || (fence_offset != at.mt.data_offset)) { - int rv; - - rv = get_next_object(&at, ch, 0); - - if (rv == EC_ERROR_MEMORY_ALLOCATION) - break; - - if (rv != EC_SUCCESS) { - ccprintf("%s: failed to read flash when saving (%d)!\n", - __func__, rv); - shared_mem_release(ch); - return rv; - } - - if (ch->container_type == NN_OBJ_TPM_RESERVED) { - process_reserved(&at, ch, pcr_bitmap); - continue; - } - - if (ch->container_type == NN_OBJ_TPM_EVICTABLE) { - process_object(&at, ch, tpm_object_offsets, &num_objs); - continue; - } - } - - /* Now save new objects, if any. */ - for (i = 0; i < num_objs; i++) - save_new_object(tpm_object_offsets[i], ch); - - /* And new pcrs, if any. */ - for (i = 0; i < NUM_OF_PCRS; i++) { - if (bitmap_bit_check(pcr_bitmap, i)) - continue; - maybe_save_pcr(ch, i); - } - -#if defined(NVMEM_TEST_BUILD) - if (failure_mode == TEST_FAIL_WHEN_SAVING) { - shared_mem_release(del_candidates); - del_candidates = NULL; - return EC_SUCCESS; - } -#endif - /* - * Add a delimiter if there have been new containers added to the - * flash. - */ - if (del_candidates->num_candidates || - (fence_offset != master_at.mt.data_offset) || - (fence_ph != master_at.mt.ph)) { - const void *del = page_cursor(&master_at.mt); - - add_delimiter(); - - if (del_candidates->num_candidates) { - /* Now delete objects which need to be deleted. */ - for (i = 0; i < del_candidates->num_candidates; i++) - invalidate_object( - del_candidates->candidates[i]); - } - -#if defined(NVMEM_TEST_BUILD) - if (failure_mode == TEST_FAIL_WHEN_INVALIDATING) { - shared_mem_release(del_candidates); - del_candidates = NULL; - return EC_SUCCESS; - } -#endif - finalize_delimiter(del); - } - - shared_mem_release(del_candidates); - del_candidates = NULL; - - return EC_SUCCESS; -} - -enum ec_error_list new_nvmem_save(void) -{ - enum ec_error_list rv; - - if (!crypto_enabled()) - return EC_ERROR_INVAL; - - lock_mutex(__LINE__); - rv = new_nvmem_save_(); - unlock_mutex(__LINE__); - - return rv; -} - -/* Caller must free memory allocated by this function! */ -static struct max_var_container *find_var(const uint8_t *key, size_t key_len, - struct access_tracker *at) -{ - int rv; - struct max_var_container *vc; - - vc = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - - /* - * Let's iterate over all objects there are and look for matching - * tuples. - */ - while ((rv = get_next_object(at, &vc->c_header, 0)) == EC_SUCCESS) { - - if (vc->c_header.container_type != NN_OBJ_TUPLE) - continue; - - /* Verify consistency, first that the sizes match */ - if ((vc->t_header.key_len + vc->t_header.val_len + - sizeof(vc->t_header)) != vc->c_header.size) { - ccprintf("%s: - inconsistent sizes!\n", __func__); - /* report error here. */ - continue; - } - - /* Ok, found a tuple, does the key match? */ - if ((key_len == vc->t_header.key_len) && - !memcmp(key, vc->body, key_len)) - /* Yes, it does! */ - return vc; - } - - shared_mem_release(vc); - return NULL; -} - -const struct tuple *getvar(const uint8_t *key, uint8_t key_len) -{ - const struct max_var_container *vc; - struct access_tracker at = {}; - - if (!crypto_enabled()) - return NULL; - - if (!key || !key_len) - return NULL; - - lock_mutex(__LINE__); - vc = find_var(key, key_len, &at); - unlock_mutex(__LINE__); - - if (vc) - return &vc->t_header; - - return NULL; -} - -void freevar(const struct tuple *var) -{ - void *vc; - - if (!var) - return; - - vc = (uint8_t *)var - offsetof(struct max_var_container, t_header); - shared_mem_release(vc); -} - -static enum ec_error_list save_container(struct nn_container *nc) -{ - uint32_t hash; - uint32_t salt[4]; - - nc->container_hash = 0; - app_compute_hash_wrapper(nc, sizeof(*nc) + nc->size, &hash, - sizeof(hash)); - nc->container_hash = hash; /* This will truncate it. */ - - /* Skip transactions delimiters. */ - if (nc->size) { - salt[0] = master_at.mt.ph->page_number; - salt[1] = master_at.mt.data_offset; - salt[2] = nc->container_hash; - salt[3] = 0; - - if (!app_cipher(salt, nc + 1, nc + 1, nc->size)) - report_no_payload_failure(NVMEMF_CIPHER_ERROR); - } - - return save_object(nc); -} - -static int setvar_(const uint8_t *key, uint8_t key_len, const uint8_t *val, - uint8_t val_len) -{ - enum ec_error_list rv; - int erase_request; - size_t new_var_space; - size_t old_var_space; - struct max_var_container *vc; - struct access_tracker at = {}; - const struct nn_container *del; - - if (!key || !key_len) - return EC_ERROR_INVAL; - - new_var_space = key_len + val_len; - - if (new_var_space > MAX_VAR_BODY_SPACE) - /* Too much space would be needed. */ - return EC_ERROR_INVAL; - - erase_request = !val || !val_len; - - /* See if compaction is needed. */ - if (!erase_request && - (master_at.list_index >= (ARRAY_SIZE(page_list) - 3))) { - rv = compact_nvmem(); - if (rv != EC_SUCCESS) - return rv; - } - - vc = find_var(key, key_len, &at); - - if (erase_request) { - if (!vc) - /* Nothing to erase. */ - return EC_SUCCESS; - - rv = invalidate_object( - (struct nn_container *)((uintptr_t)at.ct.ph + - at.ct.data_offset)); - - if (rv == EC_SUCCESS) - total_var_space -= - vc->t_header.key_len + vc->t_header.val_len; - - shared_mem_release(vc); - return rv; - } - - /* Is this variable already there? */ - if (!vc) { - /* No, it is not. Will it fit? */ - if ((new_var_space + total_var_space) > MAX_VAR_TOTAL_SPACE) - /* No, it will not. */ - return EC_ERROR_OVERFLOW; - - rv = save_var(key, key_len, val, val_len, vc); - if (rv == EC_SUCCESS) - add_final_delimiter(); - - return rv; - } - - /* The variable was found, let's see if the value is being changed. */ - if (vc->t_header.val_len == val_len && - !memcmp(val, vc->body + key_len, val_len)) { - shared_mem_release(vc); - return EC_SUCCESS; - } - - /* Ok, the variable was found, and is of a different value. */ - old_var_space = vc->t_header.val_len + vc->t_header.key_len; - - if ((old_var_space < new_var_space) && - ((total_var_space + new_var_space - old_var_space) > - MAX_VAR_TOTAL_SPACE)) { - shared_mem_release(vc); - return EC_ERROR_OVERFLOW; - } - - /* Save the new instance first with the larger generation number. */ - vc->c_header.generation++; - rv = save_var(key, key_len, val, val_len, vc); - shared_mem_release(vc); - del = page_cursor(&master_at.mt); -#if defined(NVMEM_TEST_BUILD) - if (failure_mode == TEST_FAIL_SAVING_VAR) - return EC_SUCCESS; -#endif - add_delimiter(); - if (rv == EC_SUCCESS) { - rv = invalidate_object( - (struct nn_container *)((uintptr_t)at.ct.ph + - at.ct.data_offset)); - if (rv == EC_SUCCESS) { - total_var_space -= old_var_space; -#if defined(NVMEM_TEST_BUILD) - if (failure_mode != TEST_FAIL_FINALIZING_VAR) -#endif - finalize_delimiter(del); - } - } - return rv; -} - -int setvar(const uint8_t *key, uint8_t key_len, const uint8_t *val, - uint8_t val_len) -{ - int rv; - - if (!crypto_enabled()) - return EC_ERROR_INVAL; - - lock_mutex(__LINE__); - rv = setvar_(key, key_len, val, val_len); - unlock_mutex(__LINE__); - - return rv; -} - -static void dump_contents(const struct nn_container *ch) -{ - const uint8_t *buf = (const void *)ch; - size_t i; - size_t total_size = sizeof(*ch) + ch->size; - - for (i = 0; i < total_size; i++) { - if (!(i % 16)) { - ccprintf("\n"); - cflush(); - } - ccprintf(" %02x", buf[i]); - } - ccprintf("\n"); -} - -/* - * Clear tpm data from nvmem. First fill up the current top page with erased - * objects, then compact the flash storage, removing all TPM related objects. - * This would guarantee that all pages where TPM objecs were stored would be - * erased. - */ -int nvmem_erase_tpm_data(void) -{ - const uint8_t *key; - const uint8_t *val; - int rv; - struct nn_container *ch; - struct access_tracker at = {}; - uint8_t saved_list_index; - uint8_t key_len; - - if (!crypto_enabled()) - return EC_ERROR_INVAL; - - ch = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - - lock_mutex(__LINE__); - - while (get_next_object(&at, ch, 0) == EC_SUCCESS) { - - if ((ch->container_type != NN_OBJ_TPM_RESERVED) && - (ch->container_type != NN_OBJ_TPM_EVICTABLE)) - continue; - - delete_object(&at, ch); - } - - unlock_mutex(__LINE__); - - shared_mem_release(ch); - - /* - * Now fill up the current flash page with erased objects to make sure - * that it would be erased during next compaction. Use dummy key, - * value pairs as the erase objects. - */ - saved_list_index = master_at.list_index; - key = (const uint8_t *)nvmem_erase_tpm_data; - val = (const uint8_t *)nvmem_erase_tpm_data; - key_len = MAX_VAR_BODY_SPACE - 255; - do { - size_t to_go_in_page; - uint8_t val_len; - - to_go_in_page = - CONFIG_FLASH_BANK_SIZE - master_at.mt.data_offset; - if (to_go_in_page > - (MAX_VAR_BODY_SPACE + - offsetof(struct max_var_container, body) - 1)) { - val_len = MAX_VAR_BODY_SPACE - key_len; - } else { - /* - * Let's not write more than we have to get over the - * page limit. The minimum size we need is: - * - * <container header size> + <tuple header size> + 2 - * - * (where key and value are of one byte each). - */ - if (to_go_in_page < - (offsetof(struct max_var_container, body) + 2)) { - /* - * There is very little room left, even key - * and value of size of one each is enough to - * go over. - */ - key_len = 1; - val_len = 1; - } else { - size_t need_to_cover; - - /* How much space key and value should cover? */ - need_to_cover = - to_go_in_page - - offsetof(struct max_var_container, - body) + 1; - key_len = need_to_cover / 2; - val_len = need_to_cover - key_len; - } - } - if (setvar(key, key_len, val, val_len) != EC_SUCCESS) - ccprintf("%s: adding var failed!\n", __func__); - if (setvar(key, key_len, NULL, 0) != EC_SUCCESS) - ccprintf("%s: deleting var failed!\n", __func__); - - } while (master_at.list_index != (saved_list_index + 1)); - - lock_mutex(__LINE__); - rv = compact_nvmem(); - unlock_mutex(__LINE__); - - if (rv == EC_SUCCESS) - rv = new_nvmem_init(); - - return rv; -} - -/* - * Function which verifes flash contents integrity (and printing objects it - * finds, if requested by the caller). All objects' active and deleted alike - * integrity is verified by get_next_object(). - */ -test_export_static enum ec_error_list browse_flash_contents(int print) -{ - int active = 0; - int count = 0; - int rv = EC_SUCCESS; - size_t line_len = 0; - struct nn_container *ch; - struct access_tracker at = {}; - - if (!crypto_enabled()) { - ccprintf("Crypto services not available\n"); - return EC_ERROR_INVAL; - } - - ch = get_scratch_buffer(CONFIG_FLASH_BANK_SIZE); - lock_mutex(__LINE__); - - while ((rv = get_next_object(&at, ch, 1)) == EC_SUCCESS) { - uint8_t ctype = ch->container_type; - - count++; - - if ((ctype != NN_OBJ_OLD_COPY) && - (ctype != NN_OBJ_TRANSACTION_DEL)) - active++; - - if (print) { - char erased; - - if (ctype == NN_OBJ_OLD_COPY) - erased = 'x'; - else - erased = ' '; - - if (ch->container_type_copy == NN_OBJ_TPM_RESERVED) { - ccprintf("%cR:%02x.%d ", erased, - *((uint8_t *)(ch + 1)), - ch->generation); - } else { - uint32_t index; - char tag; - - switch (ch->container_type_copy) { - case NN_OBJ_TPM_EVICTABLE: - tag = 'E'; - break; - - case NN_OBJ_TUPLE: - tag = 'T'; - break; - - case NN_OBJ_TRANSACTION_DEL: - tag = 's'; /* 's' for separator. */ - break; - - default: - tag = '?'; - break; - } - - if (ch->container_type_copy != - NN_OBJ_TRANSACTION_DEL) - memcpy(&index, ch + 1, sizeof(index)); - else - index = 0; - ccprintf("%c%c:%08x.%d ", erased, tag, index, - ch->generation); - } - if (print > 1) { - dump_contents(ch); - continue; - } - - if (line_len > 70) { - ccprintf("\n"); - cflush(); - line_len = 0; - } else { - line_len += 11; - } - } - } - - unlock_mutex(__LINE__); - - shared_mem_release(ch); - - if (rv == EC_ERROR_MEMORY_ALLOCATION) { - ccprintf("%schecked %d objects, %d active\n", print ? "\n" : "", - count, active); - rv = EC_SUCCESS; - } - - return rv; -} - -static int command_dump_nvmem(int argc, char **argv) -{ - int print = 1; - - nvmem_disable_commits(); - -#ifdef CR50_DEV - /* Allow dumping ecnrypted NVMEM contents only to DEV builds. */ - print += (argc > 1); -#endif - browse_flash_contents(print); - - nvmem_enable_commits(); - - return 0; -} -DECLARE_SAFE_CONSOLE_COMMAND(dump_nvmem, command_dump_nvmem, "", ""); diff --git a/common/nvmem.c b/common/nvmem.c deleted file mode 100644 index 4b4d8fc590..0000000000 --- a/common/nvmem.c +++ /dev/null @@ -1,508 +0,0 @@ -/* Copyright 2016 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 "dcrypto.h" -#include "flash.h" -#include "nvmem.h" -#include "new_nvmem.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ##args) -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ##args) - -/* - * The NVMEM contents are stored in flash memory. At run time there is an SRAM - * cache and two instances of the contents in the flash in two partitions. - * - * Each instance is protected by a 16 bytes hash and has a 'generation' value - * associated with it. When NVMEM module is initialized it checks the flash - * stored instances. If both of them are valid, it considers the newer one - * (younger generation) to be the proper NVMEM contents and copies it to the - * SRAM cache. If only one instance is valid, it is used, and if no instances - * are valid - a new valid partition is created and copied into the SRAM - * cache. - * - * When stored in flash, the contents are encrypted, the hash value is used as - * the IV for the encryption routine. - * - * There is a mutex controlling access to the NVMEM. There are two levels - * of protection - for read only accesses and for write accesses. When the - * module is initialized the mutex is opened. - * - * If there are no pending writes, each read access locks the mutex, reads out - * the data and unlocks the mutex, thus multiple tasks could be reading NVMEM, - * blocking access momentarily. - * - * If a write access ever occurs things get more complicated. The write access - * leaves the mutex locked and stores the flag, indicating that the - * contents have changed and need to be saved, and stores the task id of the - * task performing the write access. - * - * The mutex remains locked in this case. Next time a read access happens, - * if it comes from the same task, the unlock in the end of the read is - * bypassed because the 'write in progress' flag is set. If a read or write - * request comes from another task, they will be blocked until the first - * task to write commits. - * - * nvmem_commit() calls the nvmem_save() function which checks if the cache - * contents indeed changed (by calculating the hash again). If there is no - * change - the mutex is released and the function exits. If there is a - * change, the new generation value is set, the new hash is calculated - * and the copy is saved in the least recently used flash partition, and - * then the lock is released. - */ - -/* Table of start addresses for each partition */ -static const uintptr_t nvmem_base_addr[NVMEM_NUM_PARTITIONS] = { - CONFIG_FLASH_NVMEM_BASE_A, - CONFIG_FLASH_NVMEM_BASE_B - }; - -/* NvMem user buffer start offset table */ -static uint32_t nvmem_user_start_offset[NVMEM_NUM_USERS]; - -/* A/B partion that is most up to date */ -static int nvmem_act_partition; - -/* NvMem cache memory structure */ -struct nvmem_mutex_ { - task_id_t task; - int write_in_progress; - struct mutex mtx; -}; - -static struct nvmem_mutex_ nvmem_mutex = { .task = TASK_ID_COUNT }; -static uint8_t nvmem_cache[NVMEM_PARTITION_SIZE] __aligned(4); - -static uint8_t commits_enabled; - -/* NvMem error state */ -static int nvmem_error_state; -/* Flag to track if an Nv write/move is not completed */ -static int nvmem_write_error; - -static void nvmem_release_cache(void); - -/* - * Given the nvmem tag address calculate the sha value of the nvmem buffer and - * save it in the provided space. The caller is expected to provide enough - * space to store CIPHER_SALT_SIZE bytes. - */ -static void nvmem_compute_sha(struct nvmem_tag *tag, void *sha_buf) -{ - app_compute_hash(tag->padding, NVMEM_PARTITION_SIZE - NVMEM_SHA_SIZE, - sha_buf, sizeof(tag->sha)); -} - -static int nvmem_save(void) -{ - enum ec_error_list rv; - - rv = new_nvmem_save(); - - if (rv == EC_SUCCESS) - nvmem_act_partition = NVMEM_NOT_INITIALIZED; - - nvmem_mutex.write_in_progress = 0; - nvmem_release_cache(); - return rv; -} - -/* - * Read from flash and verify partition. - * - * @param index - index of the partition to verify - * - * Returns EC_SUCCESS on verification success - * EC_ERROR_BUSY in case of malloc failure - * EC_ERROR_UNKNOWN on failure to decrypt of verify. - */ -static int nvmem_partition_read_verify(int index) -{ - uint8_t sha_comp[NVMEM_SHA_SIZE]; - struct nvmem_partition *p_part; - struct nvmem_partition *p_copy; - int ret; - - p_part = (struct nvmem_partition *)nvmem_base_addr[index]; - p_copy = (struct nvmem_partition *)nvmem_cache; - memcpy(p_copy, p_part, NVMEM_PARTITION_SIZE); - - /* Then decrypt it. */ - if (!app_cipher(p_copy->tag.sha, &p_copy->tag + 1, - &p_copy->tag + 1, - NVMEM_PARTITION_SIZE - sizeof(struct nvmem_tag))) { - CPRINTF("%s: decryption failure\n", __func__); - return EC_ERROR_UNKNOWN; - } - - /* - * Check if computed value matches stored value. Nonzero 'ret' value - * means there was a match. - */ - nvmem_compute_sha(&p_copy->tag, sha_comp); - ret = !memcmp(p_copy->tag.sha, sha_comp, NVMEM_SHA_SIZE); - - return ret ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static void nvmem_lock_cache(void) -{ - /* - * Need to protect the cache contents value from other tasks - * attempting to do nvmem write operations. However, since this - * function may be called mutliple times prior to the mutex lock being - * released, there is a check first to see if the current task holds - * the lock. If it does then the task number will equal the value in - * cache.task, no need to wait. - * - * If the lock is held by a different task then mutex_lock function - * will operate as normal. - */ - if (nvmem_mutex.task == task_get_current()) - return; - - mutex_lock(&nvmem_mutex.mtx); - nvmem_mutex.task = task_get_current(); -} - -static void nvmem_release_cache(void) -{ - if (nvmem_mutex.write_in_progress || !commits_enabled) - return; /* It will have to be saved first. */ - - /* Reset task number to max value */ - nvmem_mutex.task = TASK_ID_COUNT; - /* Release mutex lock here */ - mutex_unlock(&nvmem_mutex.mtx); -} - -static int nvmem_compare_generation(void) -{ - struct nvmem_partition *p_part; - uint16_t ver0, ver1; - uint32_t delta; - - p_part = (struct nvmem_partition *)nvmem_base_addr[0]; - ver0 = p_part->tag.generation; - p_part = (struct nvmem_partition *)nvmem_base_addr[1]; - ver1 = p_part->tag.generation; - - /* Compute generation difference accounting for wrap condition */ - delta = (ver0 - ver1 + (1<<NVMEM_GENERATION_BITS)) & - NVMEM_GENERATION_MASK; - /* - * If generation number delta is positive in a circular sense then - * partition 0 has the newest generation number. Otherwise, it's - * partition 1. - */ - return delta < (1<<(NVMEM_GENERATION_BITS-1)) ? 0 : 1; -} - -static int nvmem_find_partition(void) -{ - int n; - int newest; - - /* Don't know which partition to use yet */ - nvmem_act_partition = NVMEM_NOT_INITIALIZED; - - /* Find the newest partition available in flash. */ - newest = nvmem_compare_generation(); - - /* - * Find a partition with a valid sha, starting with the newest one. - */ - for (n = 0; n < NVMEM_NUM_PARTITIONS; n++) { - int check_part = (n + newest) % NVMEM_NUM_PARTITIONS; - - if (nvmem_partition_read_verify(check_part) == EC_SUCCESS) { - nvmem_act_partition = check_part; - ccprintf("%s:%d found legacy partition %d\n", __func__, - __LINE__, check_part); - return EC_SUCCESS; - } - } - - /* - * If active_partition is still not selected, then neither partition - * is valid. Let's reinitialize the NVMEM - there is nothing else we - * can do. - */ - CPRINTS("%s: No Legacy Partitions found.", __func__); - return EC_ERROR_INVALID_CONFIG; -} - -static int nvmem_generate_offset_table(void) -{ - int n; - uint32_t start_offset; - - /* - * Create table of starting offsets within partition for each user - * buffer that's been defined. - */ - start_offset = sizeof(struct nvmem_tag); - for (n = 0; n < NVMEM_NUM_USERS; n++) { - nvmem_user_start_offset[n] = start_offset; - start_offset += nvmem_user_sizes[n]; - } - /* Verify that all defined user buffers fit within the partition */ - if (start_offset > NVMEM_PARTITION_SIZE) - return EC_ERROR_OVERFLOW; - - return EC_SUCCESS; -} - -void *nvmem_cache_base(enum nvmem_users user) -{ - if ((user < 0) || (user >= NVMEM_NUM_USERS)) - return NULL; - - return nvmem_cache + nvmem_user_start_offset[user]; -} - -static int nvmem_get_partition_off(int user, uint32_t offset, uint32_t len, - uint32_t *p_buf_offset) -{ - uint32_t start_offset; - - /* Sanity check for user */ - if (user >= NVMEM_NUM_USERS) - return EC_ERROR_OVERFLOW; - - /* Get offset within the partition for the start of user buffer */ - start_offset = nvmem_user_start_offset[user]; - /* - * Ensure that read/write operation that is calling this function - * doesn't exceed the end of its buffer. - */ - if (offset + len > nvmem_user_sizes[user]) - return EC_ERROR_OVERFLOW; - /* Compute offset within the partition for the rd/wr operation */ - *p_buf_offset = start_offset + offset; - - return EC_SUCCESS; -} - -int nvmem_init(void) -{ - int ret; - - /* Generate start offsets within partiion for user buffers */ - ret = nvmem_generate_offset_table(); - if (ret) { - CPRINTF("%s:%d\n", __func__, __LINE__); - return ret; - } - nvmem_write_error = 0; - - /* - * Default policy is to allow all commits. This ensures reinitialization - * succeeds to bootstrap the nvmem area. - */ - commits_enabled = 1; - - /* - * Try discovering legacy partition(s). If even one is present, need - * to migrate to the new nvmem storage scheme. - */ - if (nvmem_find_partition() == EC_SUCCESS) - ret = new_nvmem_migrate(nvmem_act_partition); - else - ret = new_nvmem_init(); - - nvmem_error_state = ret; - - if (ret != EC_SUCCESS) { - CPRINTF("%s:%d error %d!\n", __func__, __LINE__, ret); - return ret; - } - - return EC_SUCCESS; -} - -int nvmem_get_error_state(void) { return nvmem_error_state; } - -int nvmem_is_different(uint32_t offset, uint32_t size, void *data, - enum nvmem_users user) -{ - int ret; - uint32_t src_offset; - - nvmem_lock_cache(); - - /* Get partition offset for this read operation */ - ret = nvmem_get_partition_off(user, offset, size, &src_offset); - if (ret != EC_SUCCESS) - return ret; - - /* Advance to the correct byte within the data buffer */ - - /* Compare NvMem with data */ - ret = memcmp(nvmem_cache + src_offset, data, size); - - nvmem_release_cache(); - - return ret; -} - -int nvmem_read(uint32_t offset, uint32_t size, - void *data, enum nvmem_users user) -{ - int ret; - uint32_t src_offset; - - nvmem_lock_cache(); - - /* Get partition offset for this read operation */ - ret = nvmem_get_partition_off(user, offset, size, &src_offset); - - if (ret == EC_SUCCESS) - /* Copy from src into the caller's destination buffer */ - memcpy(data, nvmem_cache + src_offset, size); - - nvmem_release_cache(); - - return ret; -} - -int nvmem_write(uint32_t offset, uint32_t size, - void *data, enum nvmem_users user) -{ - int ret; - uint8_t *p_dest; - uint32_t dest_offset; - - /* Make sure that the cache buffer is active */ - nvmem_lock_cache(); - nvmem_mutex.write_in_progress = 1; - - /* Compute partition offset for this write operation */ - ret = nvmem_get_partition_off(user, offset, size, &dest_offset); - if (ret != EC_SUCCESS) { - nvmem_write_error = 1; - return ret; - } - - /* Advance to correct offset within data buffer */ - p_dest = nvmem_cache + dest_offset; - - /* Copy data from caller into destination buffer */ - memcpy(p_dest, data, size); - - return EC_SUCCESS; -} - -int nvmem_move(uint32_t src_offset, uint32_t dest_offset, uint32_t size, - enum nvmem_users user) -{ - int ret; - uint8_t *p_src, *p_dest; - uintptr_t base_addr; - uint32_t s_buff_offset, d_buff_offset; - - /* Make sure that the cache buffer is active */ - nvmem_lock_cache(); - nvmem_mutex.write_in_progress = 1; - - /* Compute partition offset for source */ - ret = nvmem_get_partition_off(user, src_offset, size, &s_buff_offset); - if (ret != EC_SUCCESS) { - nvmem_write_error = 1; - return ret; - } - - /* Compute partition offset for destination */ - ret = nvmem_get_partition_off(user, dest_offset, size, &d_buff_offset); - if (ret != EC_SUCCESS) { - nvmem_write_error = 1; - return ret; - } - - base_addr = (uintptr_t)nvmem_cache; - /* Create pointer to src location within partition */ - p_src = (uint8_t *)(base_addr + s_buff_offset); - /* Create pointer to dest location within partition */ - p_dest = (uint8_t *)(base_addr + d_buff_offset); - /* Move the data block in NvMem */ - memmove(p_dest, p_src, size); - - return EC_SUCCESS; -} - -int nvmem_enable_commits(void) -{ - if (commits_enabled) - return EC_SUCCESS; - - if (nvmem_mutex.task != task_get_current()) { - CPRINTF("%s: locked by task %d, attempt to unlock by task %d\n", - __func__, nvmem_mutex.task, task_get_current()); - return EC_ERROR_INVAL; - } - - commits_enabled = 1; - CPRINTS("Committing NVMEM changes."); - return nvmem_commit(); -} - -void nvmem_disable_commits(void) -{ - /* Will be unlocked when nvmem_enable_commits() is called. */ - nvmem_lock_cache(); - - commits_enabled = 0; -} - -int nvmem_commit(void) -{ - if (nvmem_mutex.task == TASK_ID_COUNT) { - CPRINTF("%s: attempt to commit in unlocked state %d\n", - __func__, nvmem_mutex.task); - return EC_ERROR_OVERFLOW; /* Noting to commit. */ - } - - if (nvmem_mutex.task != task_get_current()) { - CPRINTF("%s: locked by task %d, attempt to unlock by task %d\n", - __func__, nvmem_mutex.task, task_get_current()); - return EC_ERROR_INVAL; - } - - /* Ensure that all writes/moves prior to commit call succeeded */ - if (nvmem_write_error) { - CPRINTS("%s: Write Error, commit abandoned", __func__); - /* Clear error state */ - nvmem_write_error = 0; - commits_enabled = 1; - nvmem_release_cache(); - return EC_ERROR_UNKNOWN; - } - - if (!commits_enabled) { - CPRINTS("Skipping commit"); - return EC_SUCCESS; - } - - /* Write active partition to NvMem */ - return nvmem_save(); -} - -void nvmem_clear_cache(void) -{ - /* This will work only if key ladder is disabled. */ - if (DCRYPTO_ladder_is_enabled()) - return; - - nvmem_lock_cache(); - - nvmem_wipe_cache(); - - nvmem_save(); -} diff --git a/common/nvmem_vars.c b/common/nvmem_vars.c deleted file mode 100644 index 2b60dbed0c..0000000000 --- a/common/nvmem_vars.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2016 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 "nvmem.h" -#include "new_nvmem.h" -#include "printf.h" -#include "shared_mem.h" -#include "util.h" - -/****************************************************************************/ -/* Pointer to the RAM copy of the persistent variable store */ - -test_mockable_static uint8_t *rbuf; - -int set_local_copy(void) -{ - if (rbuf) - return EC_ERROR_UNKNOWN; - - rbuf = nvmem_cache_base(NVMEM_CR50); - - return EC_SUCCESS; -} - -/****************************************************************************/ -/* Implementation notes - * - * The data_ member of struct tuple is simply the key and val blobs - * concatenated together. - * - * We store the variable entries in flash (and RAM) using the struct tuple - * defined in nvmem_vars.h. The entries are written sequentially with no - * padding, starting at offset 0 of the CONFIG_FLASH_NVMEM_VARS_USER_NUM user - * region. A single uint8_t zero byte will ALWAYS follow the valid entries. - * Since valid entries have nonzero key_len, we can always detect the presence - * of valid entries. - * - * A valid entry has both key_len and val_len between 1 and 255. The following - * bytes represent these tuples: <"A","ab">, <"B","cde">: - * - * Offset Content Meaning - * 0 0x01 length of key - * 1 0x02 length of val - * 2 0x00 variable flags (unused at present) - * 3 0x41 'A' (key) - * 4 0x61 'a' (val byte 1) - * 5 0x62 'b' (val byte 2) - * 6 0x01 length of key - * 7 0x03 length of val - * 8 0x00 variable flags (unused at present) - * 9 0x42 'B' (key) - * 10 0x63 'c' (val byte 1) - * 11 0x64 'd' (val byte 2) - * 12 0x65 'e' (val byte 3) - * 13 0x00 End of variables - * - * Note that the keys and values are not null-terminated since they're not - * strings, just binary blobs. The length of each entry is the size of the - * struct tuple header, plus the length of its key and value blobs. - * - * The .flags field is not currently used (and so is set to zero). It could be - * used in the future to for per-variable attributes, such as read-only, - * clear-on-reset, extended-length value, etc. - */ - -/****************************************************************************/ -/* API functions */ - -const struct tuple *legacy_getnextvar(const struct tuple *prev_var) -{ - const struct tuple *var; - uintptr_t idx; - - if (!prev_var) { - /* - * The caller is just starting, let's get the first var, if - * any. - */ - if (!rbuf[0]) - return NULL; - return (const struct tuple *)rbuf; - } - - /* Let's try to get the next one. */ - idx = (uintptr_t)prev_var; - idx += prev_var->key_len + prev_var->val_len + sizeof(struct tuple); - - var = (const struct tuple *)idx; - - if (var->key_len) - return var; - - return NULL; -} - -const uint8_t *tuple_key(const struct tuple *t) { return t->data_; } - -const uint8_t *tuple_val(const struct tuple *t) -{ - return t->data_ + t->key_len; -} - -/****************************************************************************/ -#if defined(TEST_BUILD) && !defined(TEST_FUZZ) -#include "console.h" - -static void print_blob(const uint8_t *blob, int blob_len) -{ - int i; - - for (i = 0; i < blob_len; i++) - ccprintf("%c", isprint(blob[i]) ? blob[i] : '.'); -} - -static int command_get(int argc, char **argv) -{ - const struct tuple *tuple; - - if (argc != 2) - return EC_ERROR_PARAM_COUNT; - - tuple = getvar(argv[1], strlen(argv[1])); - if (!tuple) - return EC_SUCCESS; - - print_blob(tuple_val(tuple), tuple->val_len); - ccprintf("\n"); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(get, command_get, - "VARIABLE", - "Show the value of the specified variable"); - -static int command_set(int argc, char **argv) -{ - int rc; - - if (argc != 2 && argc != 3) - return EC_ERROR_PARAM_COUNT; - - if (argc == 2) - rc = setvar(argv[1], strlen(argv[1]), 0, 0); - else - rc = setvar(argv[1], strlen(argv[1]), argv[2], strlen(argv[2])); - - return rc; -} -DECLARE_CONSOLE_COMMAND(set, command_set, "VARIABLE [VALUE]", - "Set/clear the value of the specified variable"); - -static int command_print(int argc, char **argv) -{ - ccprintf("Print all vars is not yet implemented\n"); - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(print, command_print, "", - "Print all defined variables"); - -static int command_clear_nvmem_vars(int argc, char **argv) -{ - ccprintf("Nvmem clear vars has not yet been implemented\n"); - return EC_ERROR_INVAL; -} -DECLARE_CONSOLE_COMMAND(clr_nvmem_vars, command_clear_nvmem_vars, "", - "Clear the NvMem variables."); -#endif diff --git a/common/physical_presence.c b/common/physical_presence.c deleted file mode 100644 index 5fa97e1218..0000000000 --- a/common/physical_presence.c +++ /dev/null @@ -1,326 +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. - * - * Physical presence detect state machine - */ - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "physical_presence.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_CCD, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_CCD, format, ## args) - -#ifdef CONFIG_PHYSICAL_PRESENCE_DEBUG_UNSAFE -/* More lenient physical presence for dev builds */ -#define PP_SHORT_PRESS_COUNT 3 -#define PP_SHORT_PRESS_MIN_INTERVAL_US (100 * MSEC) -#define PP_SHORT_PRESS_MAX_INTERVAL_US (15 * SECOND) -#define PP_LONG_PRESS_COUNT (PP_SHORT_PRESS_COUNT + 2) -#define PP_LONG_PRESS_MIN_INTERVAL_US (2 * SECOND) -#define PP_LONG_PRESS_MAX_INTERVAL_US (300 * SECOND) -#else -/* Stricter physical presence for non-dev builds */ -#define PP_SHORT_PRESS_COUNT 5 -#define PP_SHORT_PRESS_MIN_INTERVAL_US (100 * MSEC) -#define PP_SHORT_PRESS_MAX_INTERVAL_US (5 * SECOND) -#define PP_LONG_PRESS_COUNT (PP_SHORT_PRESS_COUNT + 4) -#define PP_LONG_PRESS_MIN_INTERVAL_US (60 * SECOND) -#define PP_LONG_PRESS_MAX_INTERVAL_US (300 * SECOND) -#endif - -enum pp_detect_state { - PP_DETECT_IDLE = 0, - PP_DETECT_AWAITING_PRESS, - PP_DETECT_BETWEEN_PRESSES, - PP_DETECT_FINISHING, - PP_DETECT_ABORT -}; - -/* Physical presence state machine data */ -static enum pp_detect_state pp_detect_state; -static void (*pp_detect_callback)(void); -static uint8_t pp_press_count; -static uint8_t pp_press_count_needed; -static uint64_t pp_last_press; /* Time of last press */ - -/* - * We need a mutex because physical_detect_start() and physical_detect_abort() - * could be called from multiple threads (TPM or console). And either of those - * could preempt the deferred functions for the state machine which run in the - * hook task. - */ -static struct mutex pp_mutex; - -static int pp_detect_in_progress(void) -{ - return ((pp_detect_state == PP_DETECT_AWAITING_PRESS) || - (pp_detect_state == PP_DETECT_BETWEEN_PRESSES)); -} - -/******************************************************************************/ -/* - * Deferred functions - * - * These are called by the hook task, so can't preempt each other. But they - * could be preempted by calls to physical_presence_start() or - * physical_presence_abort(). - */ - -/** - * Clean up at end of physical detect sequence. - */ -static void physical_detect_done(void) -{ - /* - * Note that calling physical_detect_abort() from another thread after - * the start of physical_detect_done() but before mutex_lock() will - * result in another call to physical_detect_done() being queued up. - * That's harmless, because we go back to PP_DETECT_IDLE at the end of - * this call, so the second call will simply drop through without - * calling pp_detect_callback(). - */ - mutex_lock(&pp_mutex); - - if (!pp_detect_in_progress()) { - CPRINTF("\nPhysical presence check aborted.\n"); - pp_detect_callback = NULL; - } else if (pp_press_count < pp_press_count_needed) { - CPRINTF("\nPhysical presence check timeout.\n"); - pp_detect_callback = NULL; - } - - pp_detect_state = PP_DETECT_FINISHING; - mutex_unlock(&pp_mutex); - - /* No longer care about button presses */ - board_physical_presence_enable(0); - - /* - * Call the callback function. Do this outside the mutex, because the - * callback may take a while. If we kept holding the mutex, then calls - * to physical_detect_abort() or physical_detect_start() during the - * callback would block instead of simply failing. - */ - if (pp_detect_callback) { - CPRINTS("PP callback"); - pp_detect_callback(); - pp_detect_callback = NULL; - } - - /* Now go to idle */ - mutex_lock(&pp_mutex); - pp_detect_state = PP_DETECT_IDLE; - mutex_unlock(&pp_mutex); -} -DECLARE_DEFERRED(physical_detect_done); - -/** - * Print a prompt when we've hit the minimum wait time - */ -static void physical_detect_prompt(void) -{ - pp_detect_state = PP_DETECT_AWAITING_PRESS; - CPRINTF("\n\nPress the physical button now!\n\n"); -} -DECLARE_DEFERRED(physical_detect_prompt); - -/** - * Handle a physical present button press - * - * This is implemented as a deferred function so it can use the mutex. - */ -static void physical_detect_check_press(void) -{ - uint64_t now = get_time().val; - uint64_t dt = now - pp_last_press; - - mutex_lock(&pp_mutex); - - CPRINTS("PP press dt=%.6lld", dt); - - /* If we no longer care about presses, ignore them */ - if (!pp_detect_in_progress()) - goto pdpress_exit; - - /* Ignore extra presses we don't need */ - if (pp_press_count >= pp_press_count_needed) - goto pdpress_exit; - - /* Ignore presses outside the expected interval */ - if (pp_press_count < PP_SHORT_PRESS_COUNT) { - if (dt < PP_SHORT_PRESS_MIN_INTERVAL_US) { - CPRINTS("PP S too soon"); - goto pdpress_exit; - } - if (dt > PP_SHORT_PRESS_MAX_INTERVAL_US) { - CPRINTS("PP S too late"); - goto pdpress_exit; - } - } else { - if (dt < PP_LONG_PRESS_MIN_INTERVAL_US) { - CPRINTS("PP L too soon"); - goto pdpress_exit; - } - if (dt > PP_LONG_PRESS_MAX_INTERVAL_US) { - CPRINTS("PP L too late"); - goto pdpress_exit; - } - } - - /* Ok, we need this press */ - CPRINTS("PP press counted!"); - pp_detect_state = PP_DETECT_BETWEEN_PRESSES; - pp_last_press = now; - pp_press_count++; - - /* Set up call to done handler for timeout or actually done */ - if (pp_press_count == pp_press_count_needed) { - /* Done, so call right away */ - hook_call_deferred(&physical_detect_done_data, 0); - } else if (pp_press_count < PP_SHORT_PRESS_COUNT) { - hook_call_deferred(&physical_detect_prompt_data, - PP_SHORT_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_SHORT_PRESS_MAX_INTERVAL_US); - } else { - CPRINTF("Another press will be required soon.\n"); - dt = PP_LONG_PRESS_MAX_INTERVAL_US; - hook_call_deferred(&physical_detect_prompt_data, - PP_LONG_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_LONG_PRESS_MAX_INTERVAL_US); - } - -pdpress_exit: - mutex_unlock(&pp_mutex); -} -DECLARE_DEFERRED(physical_detect_check_press); - -/******************************************************************************/ -/* Interface */ - -int physical_detect_start(int is_long, void (*callback)(void)) -{ - mutex_lock(&pp_mutex); - - /* Fail if detection is already in progress */ - if (pp_detect_state != PP_DETECT_IDLE) { - mutex_unlock(&pp_mutex); - return EC_ERROR_BUSY; - } - - pp_press_count_needed = is_long ? PP_LONG_PRESS_COUNT : - PP_SHORT_PRESS_COUNT; - pp_press_count = 0; - pp_last_press = get_time().val; - pp_detect_callback = callback; - pp_detect_state = PP_DETECT_BETWEEN_PRESSES; - mutex_unlock(&pp_mutex); - - /* Start capturing button presses */ - hook_call_deferred(&physical_detect_check_press_data, -1); - board_physical_presence_enable(1); - - CPRINTS("PP start %s", is_long ? "long" : "short"); - - /* Initial timeout is for a short press */ - hook_call_deferred(&physical_detect_prompt_data, - PP_SHORT_PRESS_MIN_INTERVAL_US); - hook_call_deferred(&physical_detect_done_data, - PP_SHORT_PRESS_MAX_INTERVAL_US); - - return EC_SUCCESS; -} - -int physical_detect_busy(void) -{ - return pp_detect_state != PP_DETECT_IDLE; -} - -void physical_detect_abort(void) -{ - mutex_lock(&pp_mutex); - if (pp_detect_in_progress()) { - CPRINTS("PP abort"); - pp_detect_state = PP_DETECT_ABORT; - /* Speed up call to done */ - hook_call_deferred(&physical_detect_prompt_data, -1); - hook_call_deferred(&physical_detect_check_press_data, -1); - hook_call_deferred(&physical_detect_done_data, 0); - } - mutex_unlock(&pp_mutex); -} - -int physical_detect_press(void) -{ - /* Ignore presses if we're idle */ - if (pp_detect_state == PP_DETECT_IDLE) - return EC_ERROR_NOT_HANDLED; - - /* Call the deferred function to do the work */ - hook_call_deferred(&physical_detect_check_press_data, 0); - return EC_SUCCESS; -} - -enum pp_fsm_state physical_presense_fsm_state(void) -{ - switch (pp_detect_state) { - case PP_DETECT_AWAITING_PRESS: - return PP_AWAITING_PRESS; - case PP_DETECT_BETWEEN_PRESSES: - return PP_BETWEEN_PRESSES; - default: - break; - } - - return PP_OTHER; -} - -#ifdef CONFIG_PHYSICAL_PRESENCE_DEBUG_UNSAFE - -/** - * Test callback function - */ -static void pp_test_callback(void) -{ - ccprintf("\nPhysical presence good\n"); -} - -/** - * Test physical presence. - */ -static int command_ppresence(int argc, char **argv) -{ - /* Print current status */ - ccprintf("PP state: %d, %d/%d, dt=%.6lld\n", - pp_detect_state, pp_press_count, pp_press_count_needed, - get_time().val - pp_last_press); - - /* With no args, simulate a button press */ - if (argc < 2) { - physical_detect_press(); - return EC_SUCCESS; - } - - if (!strcasecmp(argv[1], "short")) { - return physical_detect_start(0, pp_test_callback); - } else if (!strcasecmp(argv[1], "long")) { - return physical_detect_start(1, pp_test_callback); - } else if (!strcasecmp(argv[1], "abort")) { - physical_detect_abort(); - return EC_SUCCESS; - } else { - return EC_ERROR_PARAM1; - } -} -DECLARE_SAFE_CONSOLE_COMMAND(ppresence, command_ppresence, - "[short | long | abort]", - "Test physical presence press or sequence"); - -#endif diff --git a/common/pinweaver.c b/common/pinweaver.c deleted file mode 100644 index 2cc4118c7d..0000000000 --- a/common/pinweaver.c +++ /dev/null @@ -1,1543 +0,0 @@ -/* Copyright 2018 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 <compile_time_macros.h> -#include <console.h> -#include <dcrypto.h> -#include <extension.h> -#include <hooks.h> -#include <nvmem_vars.h> -#include <pinweaver.h> -#include <pinweaver_tpm_imports.h> -#include <pinweaver_types.h> -#include <timer.h> -#include <tpm_vendor_cmds.h> -#include <trng.h> -#include <tpm_registers.h> -#include <util.h> - -/* Compile time sanity checks. */ -/* Make sure the hash size is consistent with dcrypto. */ -BUILD_ASSERT(PW_HASH_SIZE >= SHA256_DIGEST_SIZE); - -/* sizeof(struct leaf_data_t) % 16 should be zero */ -BUILD_ASSERT(sizeof(struct leaf_sensitive_data_t) % PW_WRAP_BLOCK_SIZE == 0); - -BUILD_ASSERT(sizeof(((struct merkle_tree_t *)0)->wrap_key) == - AES256_BLOCK_CIPHER_KEY_SIZE); - -/* Verify that the nvmem_vars log entries have the correct sizes. */ -BUILD_ASSERT(sizeof(struct pw_long_term_storage_t) + - sizeof(struct pw_log_storage_t) <= PW_MAX_VAR_USAGE); - -/* Verify that the request structs will fit into the message. */ -BUILD_ASSERT(PW_MAX_MESSAGE_SIZE >= - sizeof(struct pw_request_header_t) + - sizeof(union {struct pw_request_insert_leaf_t insert_leaf; - struct pw_request_remove_leaf_t remove_leaf; - struct pw_request_try_auth_t try_auth; - struct pw_request_reset_auth_t reset_auth; - struct pw_request_get_log_t get_log; - struct pw_request_log_replay_t log_replay; }) + - sizeof(struct leaf_public_data_t) + - sizeof(struct leaf_sensitive_data_t) + - PW_MAX_PATH_SIZE); - -#define PW_MAX_RESPONSE_SIZE (sizeof(struct pw_response_header_t) + \ - sizeof(union {struct pw_response_insert_leaf_t insert_leaf; \ - struct pw_response_try_auth_t try_auth; \ - struct pw_response_reset_auth_t reset_auth; \ - struct pw_response_log_replay_t log_replay; }) + \ - PW_LEAF_PAYLOAD_SIZE) -#define PW_VALID_PCR_CRITERIA_SIZE \ - (sizeof(struct valid_pcr_value_t) * PW_MAX_PCR_CRITERIA_COUNT) -/* Verify that the request structs will fit into the message. */ -BUILD_ASSERT(PW_MAX_MESSAGE_SIZE >= PW_MAX_RESPONSE_SIZE); -/* Make sure the largest possible message would fit in - * (struct tpm_register_file).data_fifo. - */ -BUILD_ASSERT(PW_MAX_MESSAGE_SIZE + sizeof(struct tpm_cmd_header) <= 2048); - -/* PW_MAX_PATH_SIZE should not change unless PW_LEAF_MAJOR_VERSION changes too. - * Update these statements whenever these constants are changed to remind future - * maintainers about this requirement. - * - * This requirement helps guarantee that forward compatibility across the same - * PW_LEAF_MAJOR_VERSION doesn't break because of a path length becoming too - * long after new fields are added to struct wrapped_leaf_data_t or its sub - * fields. - */ -BUILD_ASSERT(PW_LEAF_MAJOR_VERSION == 0); -BUILD_ASSERT(PW_MAX_PATH_SIZE == 1024); - -/* If fields are appended to struct leaf_sensitive_data_t, an encryption - * operation should be performed on them reusing the same IV since the prefix - * won't change. - * - * If any data in the original struct leaf_sensitive_data_t changes, a new IV - * should be generated and stored as part of the log for a replay to be - * possible. - */ -BUILD_ASSERT(sizeof(struct leaf_sensitive_data_t) == 3 * PW_SECRET_SIZE); - -#define RESTART_TIMER_THRESHOLD (10 * SECOND) - -/* This var caches the restart count so the nvram log structure doesn't need to - * be walked every time try_auth request is made. - */ -uint32_t pw_restart_count; - -/******************************************************************************/ -/* Struct helper functions. - */ - -void import_leaf(const struct unimported_leaf_data_t *unimported, - struct imported_leaf_data_t *imported) -{ - imported->head = &unimported->head; - imported->hmac = unimported->hmac; - imported->iv = unimported->iv; - imported->pub = (const struct leaf_public_data_t *)unimported->payload; - imported->cipher_text = unimported->payload + unimported->head.pub_len; - imported->hashes = (const uint8_t (*)[PW_HASH_SIZE])( - imported->cipher_text + unimported->head.sec_len); -} - -/******************************************************************************/ -/* Basic operations required by the Merkle tree. - */ - -static int derive_keys(struct merkle_tree_t *merkle_tree) -{ - struct APPKEY_CTX ctx; - int ret = EC_SUCCESS; - const uint32_t KEY_TYPE_AES = 0x0; - const uint32_t KEY_TYPE_HMAC = 0xffffffff; - union { - uint32_t v[8]; - uint8_t bytes[sizeof(uint32_t) * 8]; - } input; - uint32_t type_field; - size_t seed_size = sizeof(input); - size_t x; - - get_storage_seed(input.v, &seed_size); - for (x = 0; x < ARRAY_SIZE(input.bytes) && - x < ARRAY_SIZE(merkle_tree->key_derivation_nonce); ++x) - input.bytes[x] ^= merkle_tree->key_derivation_nonce[x]; - type_field = input.v[6]; - - if (!DCRYPTO_appkey_init(PINWEAVER, &ctx)) - return PW_ERR_CRYPTO_FAILURE; - - input.v[6] = type_field ^ KEY_TYPE_AES; - if (!DCRYPTO_appkey_derive(PINWEAVER, input.v, - (uint32_t *)merkle_tree->wrap_key)) { - ret = PW_ERR_CRYPTO_FAILURE; - goto cleanup; - } - - input.v[6] = type_field ^ KEY_TYPE_HMAC; - if (!DCRYPTO_appkey_derive(PINWEAVER, input.v, - (uint32_t *)merkle_tree->hmac_key)) { - ret = PW_ERR_CRYPTO_FAILURE; - } -cleanup: - DCRYPTO_appkey_finish(&ctx); - return ret; -} - -/* Creates an empty merkle_tree with the given parameters. */ -static int create_merkle_tree(struct bits_per_level_t bits_per_level, - struct height_t height, - struct merkle_tree_t *merkle_tree) -{ - uint16_t fan_out = 1 << bits_per_level.v; - uint8_t temp_hash[PW_HASH_SIZE] = {}; - uint8_t hx; - uint16_t kx; - LITE_SHA256_CTX ctx; - - merkle_tree->bits_per_level = bits_per_level; - merkle_tree->height = height; - - /* Initialize the root hash. */ - for (hx = 0; hx < height.v; ++hx) { - DCRYPTO_SHA256_init(&ctx, 0); - for (kx = 0; kx < fan_out; ++kx) - HASH_update(&ctx, temp_hash, PW_HASH_SIZE); - memcpy(temp_hash, HASH_final(&ctx), PW_HASH_SIZE); - } - memcpy(merkle_tree->root, temp_hash, PW_HASH_SIZE); - - rand_bytes(merkle_tree->key_derivation_nonce, - sizeof(merkle_tree->key_derivation_nonce)); - return derive_keys(merkle_tree); -} - -/* Computes the HMAC for an encrypted leaf using the key in the merkle_tree. */ -static void compute_hmac( - const struct merkle_tree_t *merkle_tree, - const struct imported_leaf_data_t *imported_leaf_data, - uint8_t result[PW_HASH_SIZE]) -{ - LITE_HMAC_CTX hmac; - - DCRYPTO_HMAC_SHA256_init(&hmac, merkle_tree->hmac_key, - sizeof(merkle_tree->hmac_key)); - HASH_update(&hmac.hash, imported_leaf_data->head, - sizeof(*imported_leaf_data->head)); - HASH_update(&hmac.hash, imported_leaf_data->iv, - sizeof(PW_WRAP_BLOCK_SIZE)); - HASH_update(&hmac.hash, imported_leaf_data->pub, - imported_leaf_data->head->pub_len); - HASH_update(&hmac.hash, imported_leaf_data->cipher_text, - imported_leaf_data->head->sec_len); - memcpy(result, DCRYPTO_HMAC_final(&hmac), PW_HASH_SIZE); -} - -/* Computes the root hash for the specified path and child hash. */ -static void compute_root_hash(const struct merkle_tree_t *merkle_tree, - struct label_t path, - const uint8_t hashes[][PW_HASH_SIZE], - const uint8_t child_hash[PW_HASH_SIZE], - uint8_t new_root[PW_HASH_SIZE]) -{ - /* This is one less than the fan out, the number of sibling hashes. */ - const uint16_t num_aux = (1 << merkle_tree->bits_per_level.v) - 1; - const uint16_t path_suffix_mask = num_aux; - uint8_t temp_hash[PW_HASH_SIZE]; - uint8_t hx = 0; - uint64_t index = path.v; - - compute_hash(hashes, num_aux, - (struct index_t){index & path_suffix_mask}, - child_hash, temp_hash); - for (hx = 1; hx < merkle_tree->height.v; ++hx) { - hashes += num_aux; - index = index >> merkle_tree->bits_per_level.v; - compute_hash(hashes, num_aux, - (struct index_t){index & path_suffix_mask}, - temp_hash, temp_hash); - } - memcpy(new_root, temp_hash, sizeof(temp_hash)); -} - -/* Checks to see the specified path is valid. The length of the path should be - * validated prior to calling this function. - * - * Returns 0 on success or an error code otherwise. - */ -static int authenticate_path(const struct merkle_tree_t *merkle_tree, - struct label_t path, - const uint8_t hashes[][PW_HASH_SIZE], - const uint8_t child_hash[PW_HASH_SIZE]) -{ - uint8_t parent[PW_HASH_SIZE]; - - compute_root_hash(merkle_tree, path, hashes, child_hash, parent); - if (memcmp(parent, merkle_tree->root, sizeof(parent)) != 0) - return PW_ERR_PATH_AUTH_FAILED; - return EC_SUCCESS; -} - -static void init_wrapped_leaf_data( - struct wrapped_leaf_data_t *wrapped_leaf_data) -{ - wrapped_leaf_data->head.leaf_version.major = PW_LEAF_MAJOR_VERSION; - wrapped_leaf_data->head.leaf_version.minor = PW_LEAF_MINOR_VERSION; - wrapped_leaf_data->head.pub_len = sizeof(wrapped_leaf_data->pub); - wrapped_leaf_data->head.sec_len = - sizeof(wrapped_leaf_data->cipher_text); -} - -/* Encrypts the leaf meta data. */ -static int encrypt_leaf_data(const struct merkle_tree_t *merkle_tree, - const struct leaf_data_t *leaf_data, - struct wrapped_leaf_data_t *wrapped_leaf_data) -{ - /* Generate a random IV. - * - * If fields are appended to struct leaf_sensitive_data_t, an encryption - * operation should be performed on them reusing the same IV since the - * prefix won't change. - * - * If any data of in the original struct leaf_sensitive_data_t changes, - * a new IV should be generated and stored as part of the log for a - * replay to be possible. - */ - rand_bytes(wrapped_leaf_data->iv, sizeof(wrapped_leaf_data->iv)); - memcpy(&wrapped_leaf_data->pub, &leaf_data->pub, - sizeof(leaf_data->pub)); - if (!DCRYPTO_aes_ctr(wrapped_leaf_data->cipher_text, - merkle_tree->wrap_key, - sizeof(merkle_tree->wrap_key) << 3, - wrapped_leaf_data->iv, (uint8_t *)&leaf_data->sec, - sizeof(leaf_data->sec))) { - return PW_ERR_CRYPTO_FAILURE; - } - return EC_SUCCESS; -} - -/* Decrypts the leaf meta data. */ -static int decrypt_leaf_data( - const struct merkle_tree_t *merkle_tree, - const struct imported_leaf_data_t *imported_leaf_data, - struct leaf_data_t *leaf_data) -{ - memcpy(&leaf_data->pub, imported_leaf_data->pub, - MIN(imported_leaf_data->head->pub_len, - sizeof(struct leaf_public_data_t))); - if (!DCRYPTO_aes_ctr((uint8_t *)&leaf_data->sec, merkle_tree->wrap_key, - sizeof(merkle_tree->wrap_key) << 3, - imported_leaf_data->iv, - imported_leaf_data->cipher_text, - sizeof(leaf_data->sec))) { - return PW_ERR_CRYPTO_FAILURE; - } - return EC_SUCCESS; -} - -static int handle_leaf_update( - const struct merkle_tree_t *merkle_tree, - const struct leaf_data_t *leaf_data, - const uint8_t hashes[][PW_HASH_SIZE], - struct wrapped_leaf_data_t *wrapped_leaf_data, - uint8_t new_root[PW_HASH_SIZE], - const struct imported_leaf_data_t *optional_old_wrapped_data) -{ - int ret; - struct imported_leaf_data_t ptrs; - - init_wrapped_leaf_data(wrapped_leaf_data); - if (optional_old_wrapped_data == NULL) { - ret = encrypt_leaf_data(merkle_tree, leaf_data, - wrapped_leaf_data); - if (ret != EC_SUCCESS) - return ret; - } else { - memcpy(wrapped_leaf_data->iv, optional_old_wrapped_data->iv, - sizeof(wrapped_leaf_data->iv)); - memcpy(&wrapped_leaf_data->pub, &leaf_data->pub, - sizeof(leaf_data->pub)); - memcpy(wrapped_leaf_data->cipher_text, - optional_old_wrapped_data->cipher_text, - sizeof(wrapped_leaf_data->cipher_text)); - } - - import_leaf((const struct unimported_leaf_data_t *)wrapped_leaf_data, - &ptrs); - compute_hmac(merkle_tree, &ptrs, wrapped_leaf_data->hmac); - - compute_root_hash(merkle_tree, leaf_data->pub.label, - hashes, wrapped_leaf_data->hmac, - new_root); - - return EC_SUCCESS; -} - -/******************************************************************************/ -/* Parameter and state validation functions. - */ - -static int validate_tree_parameters(struct bits_per_level_t bits_per_level, - struct height_t height) -{ - uint8_t fan_out = 1 << bits_per_level.v; - - if (bits_per_level.v < BITS_PER_LEVEL_MIN || - bits_per_level.v > BITS_PER_LEVEL_MAX) - return PW_ERR_BITS_PER_LEVEL_INVALID; - - if (height.v < HEIGHT_MIN || - height.v > HEIGHT_MAX(bits_per_level.v) || - ((fan_out - 1) * height.v) * PW_HASH_SIZE > PW_MAX_PATH_SIZE) - return PW_ERR_HEIGHT_INVALID; - - return EC_SUCCESS; -} - -/* Verifies that merkle_tree has been initialized. */ -static int validate_tree(const struct merkle_tree_t *merkle_tree) -{ - if (validate_tree_parameters(merkle_tree->bits_per_level, - merkle_tree->height) != EC_SUCCESS) - return PW_ERR_TREE_INVALID; - return EC_SUCCESS; -} - -/* Checks the following conditions: - * Extra index fields should be all zero. - */ -static int validate_label(const struct merkle_tree_t *merkle_tree, - struct label_t path) -{ - uint8_t shift_by = merkle_tree->bits_per_level.v * - merkle_tree->height.v; - - if ((path.v >> shift_by) == 0) - return EC_SUCCESS; - return PW_ERR_LABEL_INVALID; -} - -/* Checks the following conditions: - * Columns should be strictly increasing. - * Zeroes for filler at the end of the delay_schedule are permitted. - */ -static int validate_delay_schedule(const struct delay_schedule_entry_t - delay_schedule[PW_SCHED_COUNT]) -{ - size_t x; - - /* The first entry should not be useless. */ - if (delay_schedule[0].time_diff.v == 0) - return PW_ERR_DELAY_SCHEDULE_INVALID; - - for (x = PW_SCHED_COUNT - 1; x > 0; --x) { - if (delay_schedule[x].attempt_count.v == 0) { - if (delay_schedule[x].time_diff.v != 0) - return PW_ERR_DELAY_SCHEDULE_INVALID; - } else if (delay_schedule[x].attempt_count.v <= - delay_schedule[x - 1].attempt_count.v || - delay_schedule[x].time_diff.v <= - delay_schedule[x - 1].time_diff.v) { - return PW_ERR_DELAY_SCHEDULE_INVALID; - } - } - return EC_SUCCESS; -} - -static int validate_pcr_value(const struct valid_pcr_value_t - valid_pcr_criteria[PW_MAX_PCR_CRITERIA_COUNT]) -{ - size_t index; - uint8_t sha256_of_selected_pcr[SHA256_DIGEST_SIZE]; - - for (index = 0; index < PW_MAX_PCR_CRITERIA_COUNT; ++index) { - /* The criteria with bitmask[0] = bitmask[1] = 0 is considered - * the end of list criteria. If it happens that the first - * bitmask is zero, we consider that no criteria has to be - * satisfied and return success in that case. - */ - if (valid_pcr_criteria[index].bitmask[0] == 0 && - valid_pcr_criteria[index].bitmask[1] == 0) { - if (index == 0) - return EC_SUCCESS; - - return PW_ERR_PCR_NOT_MATCH; - } - - if (get_current_pcr_digest(valid_pcr_criteria[index].bitmask, - sha256_of_selected_pcr)) { - cprints(CC_TASK, - "PinWeaver: Read PCR error, bitmask: %d, %d", - valid_pcr_criteria[index].bitmask[0], - valid_pcr_criteria[index].bitmask[1]); - return PW_ERR_PCR_NOT_MATCH; - } - - /* Check if the curent PCR digest is the same as expected by - * criteria. - */ - if (memcmp(sha256_of_selected_pcr, - valid_pcr_criteria[index].digest, - SHA256_DIGEST_SIZE) == 0) { - return EC_SUCCESS; - } - } - - cprints(CC_TASK, "PinWeaver: No criteria matches PCR values"); - return PW_ERR_PCR_NOT_MATCH; -} - -static int expected_payload_len(int minor_version) -{ - switch (minor_version) { - case 0: - return PW_LEAF_PAYLOAD_SIZE - PW_VALID_PCR_CRITERIA_SIZE; - case PW_LEAF_MINOR_VERSION: - return PW_LEAF_PAYLOAD_SIZE; - default: - return 0; - } -} - -static int validate_leaf_header(const struct leaf_header_t *head, - uint16_t payload_len, uint16_t aux_hash_len) -{ - uint32_t leaf_payload_len = head->pub_len + head->sec_len; - - if (head->leaf_version.major != PW_LEAF_MAJOR_VERSION) - return PW_ERR_LEAF_VERSION_MISMATCH; - - if (head->leaf_version.minor <= PW_LEAF_MINOR_VERSION && - leaf_payload_len != - expected_payload_len(head->leaf_version.minor)) { - return PW_ERR_LENGTH_INVALID; - } - - if (payload_len != leaf_payload_len + aux_hash_len * PW_HASH_SIZE) - return PW_ERR_LENGTH_INVALID; - - return EC_SUCCESS; -} - -/* Common validation for requests that include a path to authenticate. */ -static int validate_request_with_path(const struct merkle_tree_t *merkle_tree, - struct label_t path, - const uint8_t hashes[][PW_HASH_SIZE], - const uint8_t hmac[PW_HASH_SIZE]) -{ - int ret; - - ret = validate_tree(merkle_tree); - if (ret != EC_SUCCESS) - return ret; - - ret = validate_label(merkle_tree, path); - if (ret != EC_SUCCESS) - return ret; - - return authenticate_path(merkle_tree, path, hashes, hmac); -} - -/* Common validation for requests that import a leaf. */ -static int validate_request_with_wrapped_leaf( - const struct merkle_tree_t *merkle_tree, - uint16_t payload_len, - const struct unimported_leaf_data_t *unimported_leaf_data, - struct imported_leaf_data_t *imported_leaf_data, - struct leaf_data_t *leaf_data) -{ - int ret; - uint8_t hmac[PW_HASH_SIZE]; - - ret = validate_leaf_header(&unimported_leaf_data->head, payload_len, - get_path_auxiliary_hash_count(merkle_tree)); - if (ret != EC_SUCCESS) - return ret; - - import_leaf(unimported_leaf_data, imported_leaf_data); - ret = validate_request_with_path(merkle_tree, - imported_leaf_data->pub->label, - imported_leaf_data->hashes, - imported_leaf_data->hmac); - if (ret != EC_SUCCESS) - return ret; - - compute_hmac(merkle_tree, imported_leaf_data, hmac); - /* Safe memcmp is used here to prevent an attacker from being able to - * brute force a valid HMAC for a crafted wrapped_leaf_data. - * memcmp provides an attacker a timing side-channel they can use to - * determine how much of a prefix is correct. - */ - if (safe_memcmp(hmac, unimported_leaf_data->hmac, sizeof(hmac))) - return PW_ERR_HMAC_AUTH_FAILED; - - ret = decrypt_leaf_data(merkle_tree, imported_leaf_data, leaf_data); - if (ret != EC_SUCCESS) - return ret; - - /* The code below handles version upgrades. */ - if (unimported_leaf_data->head.leaf_version.minor == 0 && - unimported_leaf_data->head.leaf_version.major == 0) { - /* Populate the leaf_data with default pcr value */ - memset(&leaf_data->pub.valid_pcr_criteria, 0, - PW_VALID_PCR_CRITERIA_SIZE); - } - - return EC_SUCCESS; -} - -/* Sets the value of ts to the current notion of time. */ -static void update_timestamp(struct pw_timestamp_t *ts) -{ - ts->timer_value = get_time().val / SECOND; - ts->boot_count = pw_restart_count; -} - -/* Checks if an auth attempt can be made or not based on the delay schedule. - * EC_SUCCESS is returned when a new attempt can be made otherwise - * seconds_to_wait will be updated with the remaining wait time required. - */ -static int test_rate_limit(struct leaf_data_t *leaf_data, - struct time_diff_t *seconds_to_wait) -{ - uint64_t ready_time; - uint8_t x; - struct pw_timestamp_t current_time; - struct time_diff_t delay = {0}; - - /* This loop ends when x is one greater than the index that applies. */ - for (x = 0; x < ARRAY_SIZE(leaf_data->pub.delay_schedule); ++x) { - /* Stop if a null entry is reached. The first part of the delay - * schedule has a list of increasing (attempt_count, time_diff) - * pairs with any unused entries zeroed out at the end. - */ - if (leaf_data->pub.delay_schedule[x].attempt_count.v == 0) - break; - - /* Stop once a delay schedule entry is reached whose - * threshold is greater than the current number of - * attempts. - */ - if (leaf_data->pub.attempt_count.v < - leaf_data->pub.delay_schedule[x].attempt_count.v) - break; - } - - /* If the first threshold was greater than the current number of - * attempts, there is no delay. Otherwise, grab the delay from the - * entry prior to the one that was too big. - */ - if (x > 0) - delay = leaf_data->pub.delay_schedule[x - 1].time_diff; - - if (delay.v == 0) - return EC_SUCCESS; - - if (delay.v == PW_BLOCK_ATTEMPTS) { - seconds_to_wait->v = PW_BLOCK_ATTEMPTS; - return PW_ERR_RATE_LIMIT_REACHED; - } - - update_timestamp(¤t_time); - - if (leaf_data->pub.timestamp.boot_count == current_time.boot_count) - ready_time = delay.v + leaf_data->pub.timestamp.timer_value; - else - ready_time = delay.v; - - if (current_time.timer_value >= ready_time) - return EC_SUCCESS; - - seconds_to_wait->v = ready_time - current_time.timer_value; - return PW_ERR_RATE_LIMIT_REACHED; -} - -/******************************************************************************/ -/* Logging implementation. - */ - -/* Once the storage version is incremented, the update code needs to be written - * to handle differences in the structs. - * - * See the two comments "Add storage format updates here." below. - */ -BUILD_ASSERT(PW_STORAGE_VERSION == 0); - -void force_restart_count(uint32_t mock_value) -{ - pw_restart_count = mock_value; -} - -/* Returns EC_SUCCESS if the root hash was found. Sets *index to the first index - * of the log entry with a matching root hash, or the index of the last valid - * entry. - */ -static int find_relevant_entry(const struct pw_log_storage_t *log, - const uint8_t root[PW_HASH_SIZE], int *index) -{ - /* Find the relevant log entry. */ - for (*index = 0; *index < PW_LOG_ENTRY_COUNT; ++*index) { - if (log->entries[*index].type.v == PW_MT_INVALID) - break; - if (memcmp(root, log->entries[*index].root, PW_HASH_SIZE) == 0) - return EC_SUCCESS; - } - --*index; - return PW_ERR_ROOT_NOT_FOUND; -} - -static int load_log_data(struct pw_log_storage_t *log) -{ - const struct tuple *ptr; - const struct pw_log_storage_t *view; - int rv = EC_SUCCESS; - - ptr = getvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1); - if (ptr == NULL) - return PW_ERR_NV_EMPTY; - - view = (void *)tuple_val(ptr); - if (ptr->val_len != sizeof(struct pw_log_storage_t)) - rv = PW_ERR_NV_LENGTH_MISMATCH; - else if (view->storage_version != PW_STORAGE_VERSION) - rv = PW_ERR_NV_VERSION_MISMATCH; - else - memcpy(log, view, ptr->val_len); - - freevar(ptr); - - return rv; -} - -int store_log_data(const struct pw_log_storage_t *log) -{ - return setvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1, (uint8_t *)log, - sizeof(struct pw_log_storage_t)); -} - -static int load_merkle_tree(struct merkle_tree_t *merkle_tree) -{ - int ret; - const struct tuple *ptr; - - cprints(CC_TASK, "PinWeaver: Loading Tree!"); - - /* Handle the immutable data. */ - { - const struct pw_long_term_storage_t *tree; - - ptr = getvar(PW_TREE_VAR, sizeof(PW_TREE_VAR) - 1); - if (!ptr) - return PW_ERR_NV_EMPTY; - - tree = (void *)tuple_val(ptr); - /* Add storage format updates here. */ - if (ptr->val_len != sizeof(*tree)) { - freevar(ptr); - return PW_ERR_NV_LENGTH_MISMATCH; - } - if (tree->storage_version != PW_STORAGE_VERSION) { - freevar(ptr); - return PW_ERR_NV_VERSION_MISMATCH; - } - - merkle_tree->bits_per_level = tree->bits_per_level; - merkle_tree->height = tree->height; - memcpy(merkle_tree->key_derivation_nonce, - tree->key_derivation_nonce, - sizeof(tree->key_derivation_nonce)); - ret = derive_keys(merkle_tree); - freevar(ptr); - if (ret != EC_SUCCESS) - return ret; - } - - /* Handle the root hash. */ - { - struct pw_log_storage_t *log; - - ptr = getvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1); - if (!ptr) - return PW_ERR_NV_EMPTY; - - log = (void *)tuple_val(ptr); - /* Add storage format updates here. */ - if (ptr->val_len != sizeof(struct pw_log_storage_t)) { - freevar(ptr); - return PW_ERR_NV_LENGTH_MISMATCH; - } - if (log->storage_version != PW_STORAGE_VERSION) { - freevar(ptr); - return PW_ERR_NV_VERSION_MISMATCH; - } - - memcpy(merkle_tree->root, log->entries[0].root, - sizeof(merkle_tree->root)); - - /* This forces an NVRAM write for hard reboots for which the - * timer value gets reset. The TPM restart and reset counters - * were not used because they do not track the state of the - * counter. - * - * Pinweaver uses the restart_count to know when the time since - * boot can be used as the elapsed time for the delay schedule, - * versus when the elapsed time starts from a timestamp. - */ - if (get_time().val < RESTART_TIMER_THRESHOLD) { - ++log->restart_count; - ret = setvar(PW_LOG_VAR0, sizeof(PW_LOG_VAR0) - 1, - (uint8_t *)log, - sizeof(struct pw_log_storage_t)); - if (ret != EC_SUCCESS) { - freevar(ptr); - return ret; - } - } - pw_restart_count = log->restart_count; - freevar(ptr); - } - - cprints(CC_TASK, "PinWeaver: Loaded Tree. restart_count = %d", - pw_restart_count); - - return EC_SUCCESS; -} - -/* This should only be called when a new tree is created. */ -int store_merkle_tree(const struct merkle_tree_t *merkle_tree) -{ - int ret; - - /* Handle the immutable data. */ - { - struct pw_long_term_storage_t data; - - data.storage_version = PW_STORAGE_VERSION; - data.bits_per_level = merkle_tree->bits_per_level; - data.height = merkle_tree->height; - memcpy(data.key_derivation_nonce, - merkle_tree->key_derivation_nonce, - sizeof(data.key_derivation_nonce)); - - ret = setvar(PW_TREE_VAR, sizeof(PW_TREE_VAR) - 1, - (uint8_t *)&data, sizeof(data)); - if (ret != EC_SUCCESS) - return ret; - } - - /* Handle the root hash. */ - { - struct pw_log_storage_t log = {}; - struct pw_get_log_entry_t *entry = log.entries; - - log.storage_version = PW_STORAGE_VERSION; - entry->type.v = PW_RESET_TREE; - memcpy(entry->root, merkle_tree->root, - sizeof(merkle_tree->root)); - - ret = store_log_data(&log); - if (ret == EC_SUCCESS) - pw_restart_count = 0; - return ret; - } - -} - -static int log_roll_for_append(struct pw_log_storage_t *log) -{ - int ret; - - ret = load_log_data(log); - if (ret != EC_SUCCESS) - return ret; - - memmove(&log->entries[1], &log->entries[0], - sizeof(log->entries[0]) * (PW_LOG_ENTRY_COUNT - 1)); - memset(&log->entries[0], 0, sizeof(log->entries[0])); - return EC_SUCCESS; -} - -int log_insert_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE], - const uint8_t hmac[PW_HASH_SIZE]) -{ - int ret; - struct pw_log_storage_t log; - struct pw_get_log_entry_t *entry = log.entries; - - ret = log_roll_for_append(&log); - if (ret != EC_SUCCESS) - return ret; - - entry->type.v = PW_INSERT_LEAF; - entry->label.v = label.v; - memcpy(entry->root, root, sizeof(entry->root)); - memcpy(entry->leaf_hmac, hmac, sizeof(entry->leaf_hmac)); - - return store_log_data(&log); -} - -int log_remove_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE]) -{ - int ret; - struct pw_log_storage_t log; - struct pw_get_log_entry_t *entry = log.entries; - - ret = log_roll_for_append(&log); - if (ret != EC_SUCCESS) - return ret; - - entry->type.v = PW_REMOVE_LEAF; - entry->label.v = label.v; - memcpy(entry->root, root, sizeof(entry->root)); - - return store_log_data(&log); -} - -int log_auth(struct label_t label, const uint8_t root[PW_HASH_SIZE], int code, - struct pw_timestamp_t timestamp) -{ - int ret; - struct pw_log_storage_t log; - struct pw_get_log_entry_t *entry = log.entries; - - ret = log_roll_for_append(&log); - if (ret != EC_SUCCESS) - return ret; - - entry->type.v = PW_TRY_AUTH; - entry->label.v = label.v; - memcpy(entry->root, root, sizeof(entry->root)); - entry->return_code = code; - memcpy(&entry->timestamp, ×tamp, sizeof(entry->timestamp)); - - return store_log_data(&log); -} - -/******************************************************************************/ -/* Per-request-type handler implementations. - */ - -static int pw_handle_reset_tree(struct merkle_tree_t *merkle_tree, - const struct pw_request_reset_tree_t *request, - uint16_t req_size) -{ - struct merkle_tree_t new_tree = {}; - int ret; - - if (req_size != sizeof(*request)) - return PW_ERR_LENGTH_INVALID; - - ret = validate_tree_parameters(request->bits_per_level, - request->height); - if (ret != EC_SUCCESS) - return ret; - - ret = create_merkle_tree(request->bits_per_level, request->height, - &new_tree); - if (ret != EC_SUCCESS) - return ret; - - ret = store_merkle_tree(&new_tree); - if (ret != EC_SUCCESS) - return ret; - - memcpy(merkle_tree, &new_tree, sizeof(new_tree)); - return EC_SUCCESS; -} - -static int pw_handle_insert_leaf(struct merkle_tree_t *merkle_tree, - const struct pw_request_insert_leaf_t *request, - uint16_t req_size, - struct pw_response_insert_leaf_t *response, - uint16_t *response_size) -{ - int ret = EC_SUCCESS; - struct leaf_data_t leaf_data = {}; - struct wrapped_leaf_data_t wrapped_leaf_data; - const uint8_t empty_hash[PW_HASH_SIZE] = {}; - uint8_t new_root[PW_HASH_SIZE]; - - if (req_size != sizeof(*request) + - get_path_auxiliary_hash_count(merkle_tree) * - PW_HASH_SIZE) - return PW_ERR_LENGTH_INVALID; - - ret = validate_request_with_path(merkle_tree, request->label, - request->path_hashes, empty_hash); - if (ret != EC_SUCCESS) - return ret; - - ret = validate_delay_schedule(request->delay_schedule); - if (ret != EC_SUCCESS) - return ret; - - memset(&leaf_data, 0, sizeof(leaf_data)); - leaf_data.pub.label.v = request->label.v; - memcpy(&leaf_data.pub.valid_pcr_criteria, request->valid_pcr_criteria, - sizeof(request->valid_pcr_criteria)); - memcpy(&leaf_data.pub.delay_schedule, &request->delay_schedule, - sizeof(request->delay_schedule)); - memcpy(&leaf_data.sec.low_entropy_secret, &request->low_entropy_secret, - sizeof(request->low_entropy_secret)); - memcpy(&leaf_data.sec.high_entropy_secret, - &request->high_entropy_secret, - sizeof(request->high_entropy_secret)); - memcpy(&leaf_data.sec.reset_secret, &request->reset_secret, - sizeof(request->reset_secret)); - - ret = handle_leaf_update(merkle_tree, &leaf_data, request->path_hashes, - &wrapped_leaf_data, new_root, NULL); - if (ret != EC_SUCCESS) - return ret; - - ret = log_insert_leaf(request->label, new_root, - wrapped_leaf_data.hmac); - if (ret != EC_SUCCESS) - return ret; - - memcpy(merkle_tree->root, new_root, sizeof(new_root)); - - memcpy(&response->unimported_leaf_data, &wrapped_leaf_data, - sizeof(wrapped_leaf_data)); - - *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE; - - return ret; -} - -static int pw_handle_remove_leaf(struct merkle_tree_t *merkle_tree, - const struct pw_request_remove_leaf_t *request, - uint16_t req_size) -{ - int ret = EC_SUCCESS; - const uint8_t empty_hash[PW_HASH_SIZE] = {}; - uint8_t new_root[PW_HASH_SIZE]; - - if (req_size != sizeof(*request) + - get_path_auxiliary_hash_count(merkle_tree) * - PW_HASH_SIZE) - return PW_ERR_LENGTH_INVALID; - - ret = validate_request_with_path(merkle_tree, request->leaf_location, - request->path_hashes, - request->leaf_hmac); - if (ret != EC_SUCCESS) - return ret; - - compute_root_hash(merkle_tree, request->leaf_location, - request->path_hashes, empty_hash, new_root); - - ret = log_remove_leaf(request->leaf_location, new_root); - if (ret != EC_SUCCESS) - return ret; - - memcpy(merkle_tree->root, new_root, sizeof(new_root)); - return ret; -} - -/* Processes a try_auth request. - * - * The valid fields in response based on return code are: - * EC_SUCCESS -> unimported_leaf_data and high_entropy_secret - * PW_ERR_RATE_LIMIT_REACHED -> seconds_to_wait - * PW_ERR_LOWENT_AUTH_FAILED -> unimported_leaf_data - */ -static int pw_handle_try_auth(struct merkle_tree_t *merkle_tree, - const struct pw_request_try_auth_t *request, - uint16_t req_size, - struct pw_response_try_auth_t *response, - uint16_t *data_length) -{ - int ret = EC_SUCCESS; - struct leaf_data_t leaf_data = {}; - struct imported_leaf_data_t imported_leaf_data; - struct wrapped_leaf_data_t wrapped_leaf_data; - struct time_diff_t seconds_to_wait; - uint8_t zeros[PW_SECRET_SIZE] = {}; - uint8_t new_root[PW_HASH_SIZE]; - - /* These variables help eliminate the possibility of a timing side - * channel that would allow an attacker to prevent the log write. - */ - volatile int auth_result; - - volatile struct { - uint32_t attempts; - int ret; - uint8_t *secret; - uint8_t *reset_secret; - } results_table[2] = { - { 0, PW_ERR_LOWENT_AUTH_FAILED, zeros, zeros }, - { 0, EC_SUCCESS, leaf_data.sec.high_entropy_secret, - leaf_data.sec.reset_secret }, - }; - - if (req_size < sizeof(*request)) - return PW_ERR_LENGTH_INVALID; - - ret = validate_request_with_wrapped_leaf( - merkle_tree, req_size - sizeof(*request), - &request->unimported_leaf_data, &imported_leaf_data, - &leaf_data); - if (ret != EC_SUCCESS) - return ret; - - /* Check if at least one PCR criteria is satisfied if the leaf is - * bound to PCR. - */ - ret = validate_pcr_value(leaf_data.pub.valid_pcr_criteria); - if (ret != EC_SUCCESS) - return ret; - - ret = test_rate_limit(&leaf_data, &seconds_to_wait); - if (ret != EC_SUCCESS) { - *data_length = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE; - memset(response, 0, *data_length); - memcpy(&response->seconds_to_wait, &seconds_to_wait, - sizeof(seconds_to_wait)); - return ret; - } - - update_timestamp(&leaf_data.pub.timestamp); - - /* Precompute the failed attempts. */ - results_table[0].attempts = leaf_data.pub.attempt_count.v; - if (results_table[0].attempts != UINT32_MAX) - ++results_table[0].attempts; - - /**********************************************************************/ - /* After this: - * 1) results_table should not be changed; - * 2) the runtime of the code paths for failed and successful - * authentication attempts should not diverge. - */ - auth_result = safe_memcmp(request->low_entropy_secret, - leaf_data.sec.low_entropy_secret, - sizeof(request->low_entropy_secret)) == 0; - leaf_data.pub.attempt_count.v = results_table[auth_result].attempts; - - /* This has a non-constant time path, but it doesn't convey information - * about whether a PW_ERR_LOWENT_AUTH_FAILED happened or not. - */ - ret = handle_leaf_update(merkle_tree, &leaf_data, - imported_leaf_data.hashes, &wrapped_leaf_data, - new_root, &imported_leaf_data); - if (ret != EC_SUCCESS) - return ret; - - ret = log_auth(wrapped_leaf_data.pub.label, new_root, - results_table[auth_result].ret, leaf_data.pub.timestamp); - if (ret != EC_SUCCESS) { - memcpy(new_root, merkle_tree->root, sizeof(merkle_tree->root)); - return ret; - } - /**********************************************************************/ - /* At this point the log should be written so it should be safe for the - * runtime of the code paths to diverge. - */ - - memcpy(merkle_tree->root, new_root, sizeof(new_root)); - - *data_length = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE; - memset(response, 0, *data_length); - - memcpy(&response->unimported_leaf_data, &wrapped_leaf_data, - sizeof(wrapped_leaf_data)); - - memcpy(&response->high_entropy_secret, - results_table[auth_result].secret, - sizeof(response->high_entropy_secret)); - - memcpy(&response->reset_secret, - results_table[auth_result].reset_secret, - sizeof(response->reset_secret)); - - return results_table[auth_result].ret; -} - -static int pw_handle_reset_auth(struct merkle_tree_t *merkle_tree, - const struct pw_request_reset_auth_t *request, - uint16_t req_size, - struct pw_response_reset_auth_t *response, - uint16_t *response_size) -{ - int ret = EC_SUCCESS; - struct leaf_data_t leaf_data = {}; - struct imported_leaf_data_t imported_leaf_data; - struct wrapped_leaf_data_t wrapped_leaf_data; - uint8_t new_root[PW_HASH_SIZE]; - - if (req_size < sizeof(*request)) - return PW_ERR_LENGTH_INVALID; - - ret = validate_request_with_wrapped_leaf( - merkle_tree, req_size - sizeof(*request), - &request->unimported_leaf_data, &imported_leaf_data, - &leaf_data); - if (ret != EC_SUCCESS) - return ret; - - /* Safe memcmp is used here to prevent an attacker from being able to - * brute force the reset secret and use it to unlock the leaf. - * memcmp provides an attacker a timing side-channel they can use to - * determine how much of a prefix is correct. - */ - if (safe_memcmp(request->reset_secret, - leaf_data.sec.reset_secret, - sizeof(request->reset_secret)) != 0) - return PW_ERR_RESET_AUTH_FAILED; - - leaf_data.pub.attempt_count.v = 0; - - ret = handle_leaf_update(merkle_tree, &leaf_data, - imported_leaf_data.hashes, &wrapped_leaf_data, - new_root, &imported_leaf_data); - if (ret != EC_SUCCESS) - return ret; - - ret = log_auth(leaf_data.pub.label, new_root, ret, - leaf_data.pub.timestamp); - if (ret != EC_SUCCESS) - return ret; - - memcpy(merkle_tree->root, new_root, sizeof(new_root)); - - memcpy(&response->unimported_leaf_data, &wrapped_leaf_data, - sizeof(wrapped_leaf_data)); - - memcpy(response->high_entropy_secret, - leaf_data.sec.high_entropy_secret, - sizeof(response->high_entropy_secret)); - - *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE; - - return ret; -} - -static int pw_handle_get_log(const struct merkle_tree_t *merkle_tree, - const struct pw_request_get_log_t *request, - uint16_t req_size, - struct pw_get_log_entry_t response[], - uint16_t *response_size) -{ - int ret; - int x; - struct pw_log_storage_t log; - - if (req_size != sizeof(*request)) - return PW_ERR_LENGTH_INVALID; - - ret = validate_tree(merkle_tree); - if (ret != EC_SUCCESS) - return ret; - - ret = load_log_data(&log); - if (ret != EC_SUCCESS) - return ret; - - /* Find the relevant log entry. The return value isn't used because if - * the entry isn't found the entire log is returned. This makes it - * easier to recover when the log is too short. - * - * Here is an example: - * 50 attempts have been made against a leaf that becomes out of sync - * because of a disk flush failing. The copy of the leaf on disk is - * behind by 50 and the log contains less than 50 entries. The CrOS - * implementation can check the public parameters of the local copy with - * the log entry to determine that leaf is out of sync. It can then send - * any valid copy of that leaf with a log replay request that will only - * succeed if the HMAC of the resulting leaf matches the log entry. - */ - find_relevant_entry(&log, request->root, &x); - /* If there are no valid entries, return. */ - if (x < 0) - return EC_SUCCESS; - - /* Copy the entries in reverse order. */ - while (1) { - memcpy(&response[x], &log.entries[x], sizeof(log.entries[x])); - *response_size += sizeof(log.entries[x]); - if (x == 0) - break; - --x; - } - - return EC_SUCCESS; -} - -static int pw_handle_log_replay(const struct merkle_tree_t *merkle_tree, - const struct pw_request_log_replay_t *request, - uint16_t req_size, - struct pw_response_log_replay_t *response, - uint16_t *response_size) -{ - int ret; - int x; - struct pw_log_storage_t log; - struct leaf_data_t leaf_data = {}; - struct imported_leaf_data_t imported_leaf_data; - struct wrapped_leaf_data_t wrapped_leaf_data; - uint8_t hmac[PW_HASH_SIZE]; - uint8_t root[PW_HASH_SIZE]; - - if (req_size < sizeof(*request)) - return PW_ERR_LENGTH_INVALID; - - ret = validate_tree(merkle_tree); - if (ret != EC_SUCCESS) - return ret; - - /* validate_request_with_wrapped_leaf() isn't used here because the - * path validation is delayed to allow any valid copy of the same leaf - * to be used in the replay operation as long as the result passes path - * validation. - */ - ret = validate_leaf_header(&request->unimported_leaf_data.head, - req_size - sizeof(*request), - get_path_auxiliary_hash_count(merkle_tree)); - if (ret != EC_SUCCESS) - return ret; - - import_leaf(&request->unimported_leaf_data, &imported_leaf_data); - - ret = load_log_data(&log); - if (ret != EC_SUCCESS) - return ret; - - /* Find the relevant log entry. */ - ret = find_relevant_entry(&log, request->log_root, &x); - if (ret != EC_SUCCESS) - return ret; - - /* The other message types don't need to be handled by Cr50. */ - if (log.entries[x].type.v != PW_TRY_AUTH) - return PW_ERR_TYPE_INVALID; - - compute_hmac(merkle_tree, &imported_leaf_data, hmac); - if (safe_memcmp(hmac, request->unimported_leaf_data.hmac, sizeof(hmac))) - return PW_ERR_HMAC_AUTH_FAILED; - - ret = decrypt_leaf_data(merkle_tree, &imported_leaf_data, &leaf_data); - if (ret != EC_SUCCESS) - return ret; - - if (leaf_data.pub.label.v != log.entries[x].label.v) - return PW_ERR_LABEL_INVALID; - - /* Update the metadata to match the log. */ - if (log.entries[x].return_code == EC_SUCCESS) - leaf_data.pub.attempt_count.v = 0; - else - ++leaf_data.pub.attempt_count.v; - memcpy(&leaf_data.pub.timestamp, &log.entries[x].timestamp, - sizeof(leaf_data.pub.timestamp)); - - ret = handle_leaf_update(merkle_tree, &leaf_data, - imported_leaf_data.hashes, &wrapped_leaf_data, - root, &imported_leaf_data); - if (ret != EC_SUCCESS) - return ret; - - if (memcmp(root, log.entries[x].root, PW_HASH_SIZE)) - return PW_ERR_PATH_AUTH_FAILED; - - memcpy(&response->unimported_leaf_data, &wrapped_leaf_data, - sizeof(wrapped_leaf_data)); - - *response_size = sizeof(*response) + PW_LEAF_PAYLOAD_SIZE; - - return EC_SUCCESS; -} - -struct merkle_tree_t pw_merkle_tree; - -/* - * Handle the VENDOR_CC_PINWEAVER command. - */ -static enum vendor_cmd_rc pw_vendor_specific_command(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) -{ - struct pw_request_t *request = buf; - struct pw_response_t *response = buf; - - if (input_size < sizeof(request->header)) { - ccprintf("PinWeaver: message smaller than a header (%zd).\n", - input_size); - return VENDOR_RC_INTERNAL_ERROR; - } - - if (input_size != request->header.data_length + - sizeof(request->header)) { - ccprintf("PinWeaver: header size mismatch %zd != %zd.\n", - input_size, request->header.data_length + - sizeof(request->header)); - return VENDOR_RC_REQUEST_TOO_BIG; - } - - /* The response_size is validated by compile time checks. */ - - /* The return value of this function call is intentionally unused. */ - pw_handle_request(&pw_merkle_tree, request, response); - - *response_size = response->header.data_length + - sizeof(response->header); - - /* The response is only sent for EC_SUCCESS so it is used even for - * errors which are reported through header.return_code. - */ - return VENDOR_RC_SUCCESS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_PINWEAVER, - pw_vendor_specific_command); - -/******************************************************************************/ -/* Non-static functions. - */ - -void pinweaver_init(void) -{ - load_merkle_tree(&pw_merkle_tree); -} - -int get_path_auxiliary_hash_count(const struct merkle_tree_t *merkle_tree) -{ - return ((1 << merkle_tree->bits_per_level.v) - 1) * - merkle_tree->height.v; -} - -/* Computes the SHA256 parent hash of a set of child hashes given num_hashes - * sibling hashes in hashes[] and the index of child_hash. - * - * Assumptions: - * num_hashes == fan_out - 1 - * ARRAY_SIZE(hashes) == num_hashes - * 0 <= location <= num_hashes - */ -void compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes, - struct index_t location, - const uint8_t child_hash[PW_HASH_SIZE], - uint8_t result[PW_HASH_SIZE]) -{ - LITE_SHA256_CTX ctx; - - DCRYPTO_SHA256_init(&ctx, 0); - if (location.v > 0) - HASH_update(&ctx, hashes[0], PW_HASH_SIZE * location.v); - HASH_update(&ctx, child_hash, PW_HASH_SIZE); - if (location.v < num_hashes) - HASH_update(&ctx, hashes[location.v], - PW_HASH_SIZE * (num_hashes - location.v)); - memcpy(result, HASH_final(&ctx), PW_HASH_SIZE); -} - -/* If a request from older protocol comes, this method should make it - * compatible with the current request structure. - */ -int make_compatible_request(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - switch (request->header.version) { - case 0: - /* The switch from protocol version 0 to 1 means all the - * requests have the same format, except insert_leaf. - * Update the request in that case. - */ - if (request->header.type.v == PW_INSERT_LEAF) { - unsigned char *src = (unsigned char *) - (&request->data.insert_leaf00.path_hashes); - unsigned char *dest = (unsigned char *) - (&request->data.insert_leaf.path_hashes); - const int hash_count = - get_path_auxiliary_hash_count(merkle_tree); - const uint16_t hashes_size = hash_count * PW_HASH_SIZE; - - memmove(dest, src, hashes_size); - memset(&request->data.insert_leaf.valid_pcr_criteria, - 0, PW_VALID_PCR_CRITERIA_SIZE); - request->header.data_length += - PW_VALID_PCR_CRITERIA_SIZE; - } - /* Fallthrough to make compatible from next version */ - case PW_PROTOCOL_VERSION: - return 1; - } - /* Unsupported version. */ - return 0; -} - -/* Converts the response to be understandable by an older protocol. - */ -void make_compatible_response(int version, int req_type, - struct pw_response_t *response) -{ - if (version >= PW_PROTOCOL_VERSION) - return; - - response->header.version = version; - if (version == 0) { - if (req_type == PW_TRY_AUTH) { - unsigned char *src = (unsigned char *) - (&response->data.try_auth.unimported_leaf_data); - unsigned char *dest = (unsigned char *) - (&response->data.try_auth00.unimported_leaf_data); - memmove(dest, src, - PW_LEAF_PAYLOAD_SIZE + - sizeof(struct unimported_leaf_data_t)); - response->header.data_length -= PW_SECRET_SIZE; - } - } -} - -/* Handles the message in request using the context in merkle_tree and writes - * the results to response. The return value captures any error conditions that - * occurred or EC_SUCCESS if there were no errors. - * - * This implementation is written to handle the case where request and response - * exist at the same memory location---are backed by the same buffer. This means - * the implementation requires that no reads are made to request after response - * has been written to. - */ -int pw_handle_request(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request, - struct pw_response_t *response) -{ - int32_t ret; - uint16_t resp_length; - /* Store the message type of the request since it may be overwritten - * inside the switch whenever response and request overlap in memory. - */ - struct pw_message_type_t type = request->header.type; - int version = request->header.version; - - resp_length = 0; - - if (!make_compatible_request(merkle_tree, request)) { - ret = PW_ERR_VERSION_MISMATCH; - goto cleanup; - } - switch (type.v) { - case PW_RESET_TREE: - ret = pw_handle_reset_tree(merkle_tree, - &request->data.reset_tree, - request->header.data_length); - break; - case PW_INSERT_LEAF: - ret = pw_handle_insert_leaf(merkle_tree, - &request->data.insert_leaf, - request->header.data_length, - &response->data.insert_leaf, - &resp_length); - break; - case PW_REMOVE_LEAF: - ret = pw_handle_remove_leaf(merkle_tree, - &request->data.remove_leaf, - request->header.data_length); - break; - case PW_TRY_AUTH: - ret = pw_handle_try_auth(merkle_tree, &request->data.try_auth, - request->header.data_length, - &response->data.try_auth, - &resp_length); - break; - case PW_RESET_AUTH: - ret = pw_handle_reset_auth(merkle_tree, - &request->data.reset_auth, - request->header.data_length, - &response->data.reset_auth, - &resp_length); - break; - case PW_GET_LOG: - ret = pw_handle_get_log(merkle_tree, &request->data.get_log, - request->header.data_length, - (void *)&response->data, &resp_length); - break; - case PW_LOG_REPLAY: - ret = pw_handle_log_replay(merkle_tree, - &request->data.log_replay, - request->header.data_length, - &response->data.log_replay, - &resp_length); - break; - default: - ret = PW_ERR_TYPE_INVALID; - break; - } -cleanup: - response->header.version = PW_PROTOCOL_VERSION; - response->header.data_length = resp_length; - response->header.result_code = ret; - memcpy(&response->header.root, merkle_tree->root, - sizeof(merkle_tree->root)); - - make_compatible_response(version, type.v, response); - - return ret; -}; diff --git a/common/tpm_registers.c b/common/tpm_registers.c deleted file mode 100644 index cd1afcd244..0000000000 --- a/common/tpm_registers.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* Copyright 2015 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. - */ - -/* - * This implements the register interface for the TPM SPI Hardware Protocol. - * The master puts or gets between 1 and 64 bytes to a register designated by a - * 24-bit address. There is no provision for error reporting at this level. - */ - -#include "byteorder.h" -#include "console.h" -#include "extension.h" -#include "link_defs.h" -#include "new_nvmem.h" -#include "printf.h" -#include "signed_header.h" -#include "sps.h" -#include "system.h" -#include "system_chip.h" -#include "task.h" -#include "tpm_manufacture.h" -#include "tpm_registers.h" -#include "util.h" -#include "watchdog.h" -#include "wp.h" - -/* - * Do not enable TPM if crypto test is enabled - there is no room in the flash - * for both. - */ -#ifndef CRYPTO_TEST_SETUP -#define ENABLE_TPM - -/* TPM2 library includes. */ -#include "ExecCommand_fp.h" -#include "Platform.h" -#include "_TPM_Init_fp.h" -#include "Manufacture_fp.h" - -#endif - -/****************************************************************************/ -/* - * CAUTION: Variables defined in this in this file are treated specially. - * - * As always, initialized variables are placed in the .data section, and - * uninitialized variables in the .bss section. This saves space in the - * executable, because the loader can just zero .bss prior to running the - * program. - * - * In addition to that, the tpm_reset_request() function will zero the .bss of - * all modules of the TPM library and variables of this file explicitly added - * to the .bss.Tpm2_common section, which will allow restarting TPM without - * rebooting the device. - * - * On the other hand, initialized variables (in the .data section) are NOT - * affected by tpm_reset_request(), so any variables that should be - * reinitialized must be dealt with manually in the tpm_reset_request() - * function. To prevent initialized variables from being added to the TPM - * library without notice, the linker will reject any that aren't explicitly - * flagged. - */ - -/* This marks uninitialized variables that tpm_reset_request() should ignore */ -#define __preserved __attribute__((section(".bss.noreinit"))) - -/* - * This marks initialized variables that tpm_reset_request() may need to reset - */ -#define __initialized __attribute__((section(".data.noreinit"))) - -/****************************************************************************/ - -#define CPRINTS(format, args...) cprints(CC_TPM, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_TPM, format, ## args) - -/* Register addresses for FIFO mode. */ -#define TPM_ACCESS (0) -#define TPM_INTF_CAPABILITY (0x14) -#define TPM_STS (0x18) -#define TPM_DATA_FIFO (0x24) -#define TPM_INTERFACE_ID (0x30) -#define TPM_DID_VID (0xf00) -#define TPM_RID (0xf04) -#define TPM_FW_VER (0xf90) - -#define GOOGLE_VID 0x1ae0 -#define GOOGLE_DID 0x0028 -#define CR50_RID 0 /* No revision ID yet */ - -static __preserved uint8_t reset_in_progress; - -/* Tpm state machine states. */ -enum tpm_states { - tpm_state_idle, - tpm_state_ready, - tpm_state_receiving_cmd, - tpm_state_executing_cmd, - tpm_state_completing_cmd, -}; - -/* A preliminary interface capability register value, will be fine tuned. */ -#define IF_CAPABILITY_REG ((3 << 28) | /* TPM2.0 (interface 1.3) */ \ - (3 << 9) | /* up to 64 bytes transfers. */ \ - 0x15) /* Mandatory set to one. */ - -/* Volatile registers for FIFO mode */ -struct tpm_register_file { - uint8_t access; - uint32_t sts; - uint8_t data_fifo[2048]; /* this might have to be even deeper. */ -}; - -/* - * Tpm representation. This is a file scope variable, only one locality is - * supported. - */ -static struct { - enum tpm_states state; - uint32_t fifo_read_index; /* for read commands */ - uint32_t fifo_write_index; /* for write commands */ - struct tpm_register_file regs; -} tpm_ __attribute__((section(".bss.Tpm2_common"))); - -/* Bit definitions for some TPM registers. */ -enum tpm_access_bits { - tpm_reg_valid_sts = BIT(7), - active_locality = BIT(5), - request_use = BIT(1), - tpm_establishment = BIT(0), -}; - -enum tpm_sts_bits { - tpm_family_shift = 26, - tpm_family_mask = (BIT(2) - 1), /* 2 bits wide */ - tpm_family_tpm2 = 1, - reset_establishment_bit = BIT(25), - command_cancel = BIT(24), - burst_count_shift = 8, - burst_count_mask = (BIT(16) - 1), /* 16 bits wide */ - sts_valid = BIT(7), - command_ready = BIT(6), - tpm_go = BIT(5), - data_avail = BIT(4), - expect = BIT(3), - self_test_done = BIT(2), - response_retry = BIT(1), -}; - -/* Used to count bytes read in version string */ -static int tpm_fw_ver_index __attribute__((section(".bss.Tpm2_common"))); -/* - * Used to store the full version string, which includes version of the two RO - * and two RW regions in the flash as well as the version string of the four - * cr50 image components. The number is somewhat arbitrary, calculated for the - * worst case scenario when all compontent trees are 'dirty'. - */ -static uint8_t tpm_fw_ver[80] __attribute__((section(".bss.Tpm2_common"))); - -/* - * We need to be able to report firmware version to the host, both RO and RW - * sections. This copies the information into a static string so that it can be - * passed to the host a little bit at a time. - */ -static void set_version_string(void) -{ - enum ec_image active_ro, active_rw; - size_t offset; - - active_ro = system_get_ro_image_copy(); - active_rw = system_get_image_copy(); - - snprintf(tpm_fw_ver, sizeof(tpm_fw_ver), "%s:%d RO_%c:%s", - system_get_chip_revision(), - system_get_board_version(), - (active_ro == EC_IMAGE_RO ? 'A' : 'B'), - system_get_version(active_ro)); - offset = strlen(tpm_fw_ver); - if (offset == sizeof(tpm_fw_ver) - 1) - return; - - snprintf(tpm_fw_ver + offset, - sizeof(tpm_fw_ver) - offset, " RW_%c:%s", - (active_rw == EC_IMAGE_RW ? 'A' : 'B'), - system_get_version(active_rw)); -} - -static void set_tpm_state(enum tpm_states state) -{ - CPRINTF("state transition from %d to %d\n", tpm_.state, state); - tpm_.state = state; - - if (state == tpm_state_idle) { - /* Make sure FIFO is empty. */ - tpm_.fifo_read_index = 0; - tpm_.fifo_write_index = 0; - /* - * Set proper fields of the status register: FIFO depth 63, - * not ready, no data available. - */ - tpm_.regs.sts &= ~((burst_count_mask << burst_count_shift) | - command_ready | data_avail); - tpm_.regs.sts |= 63 << burst_count_shift; - } -} - -/* - * Some TPM registers allow writing of only exactly one bit. This helper - * function allows to verify that a value is compliant with this - * requirement - */ -static int single_bit_set(uint32_t value) -{ - return value && !(value & (value - 1)); -} - -/* - * NOTE: The put/get functions are called in interrupt context! Don't waste a - * lot of time here - just copy the data and wake up a task to deal with it - * later. Although if the implementation mandates a "busy" bit somewhere, you - * might want to set it now to avoid race conditions with back-to-back - * interrupts. - */ - -static void copy_bytes(uint8_t *dest, uint32_t data_size, uint32_t value) -{ - unsigned i; - - data_size = MIN(data_size, 4); - - for (i = 0; i < data_size; i++) - dest[i] = (value >> (i * 8)) & 0xff; -} - -static void access_reg_write(uint8_t data) -{ - if (!single_bit_set(data)) { - CPRINTF("%s: attempt to set acces reg to %02x\n", - __func__, data); - return; - } - - switch (data) { - case request_use: - /* - * No multiple localities supported, let's just always honor - * this request. - */ - tpm_.regs.access |= active_locality; - break; - - case active_locality: - switch (tpm_.state) { - case tpm_state_ready: - case tpm_state_idle: - break; - default: - /* - * TODO: need to decide what to do if there is a - * command in progress. - */ - CPRINTF("%s: locality release request in state %d\n", - __func__, tpm_.state); - break; - } - tpm_.regs.access &= ~active_locality; - /* No matter what we do, fall into idle state. */ - set_tpm_state(tpm_state_idle); - break; - - default: - CPRINTF("%s: attempt to set access reg to an unsupported value" - " of 0x%02x\n", __func__, data); - break; - } -} - -/* - * Process writes into the 'important' sts register bits. Actions on all - * depends on the current state of the device. - */ -static void sts_reg_write_cr(void) -{ - switch (tpm_.state) { - case tpm_state_idle: - set_tpm_state(tpm_state_ready); - tpm_.regs.sts |= command_ready; - break; - case tpm_state_ready: - tpm_.regs.sts |= command_ready; - break; - case tpm_state_completing_cmd: - case tpm_state_executing_cmd: - case tpm_state_receiving_cmd: - set_tpm_state(tpm_state_idle); - break; - } -} - -static void sts_reg_write_tg(void) -{ - switch (tpm_.state) { - case tpm_state_completing_cmd: - case tpm_state_executing_cmd: - case tpm_state_idle: - case tpm_state_ready: - break; /* Ignore setting this bit in these states. */ - case tpm_state_receiving_cmd: - if (!(tpm_.state & expect)) { - /* This should trigger actual command execution. */ - set_tpm_state(tpm_state_executing_cmd); - task_set_event(TASK_ID_TPM, TASK_EVENT_WAKE, 0); - } - break; - } -} - -static void sts_reg_write_rr(void) -{ - switch (tpm_.state) { - case tpm_state_idle: - case tpm_state_ready: - case tpm_state_receiving_cmd: - case tpm_state_executing_cmd: - break; - case tpm_state_completing_cmd: - tpm_.fifo_read_index = 0; - break; - } -} - -/* - * TPM_STS register both reports current state machine state and controls some - * of state machine transitions. - */ -static void sts_reg_write(const uint8_t *data, uint32_t data_size) -{ - uint32_t value = 0; - - data_size = MIN(data_size, 4); - memcpy(&value, data, data_size); - - /* By definition only one bit can be set at a time. */ - if (!single_bit_set(value)) { - CPRINTF("%s: attempt to set status reg to %02x\n", - __func__, value); - return; - } - - switch (value) { - case command_ready: - sts_reg_write_cr(); - break; - case tpm_go: - sts_reg_write_tg(); - break; - case response_retry: - sts_reg_write_rr(); - break; - case command_cancel: - /* TODO: this also needs to be handled, fall through for now. */ - default: - CPRINTF("requested to write %08x to sts\n", value); - break; - } -} - -/* Collect received data in the local buffer and change state accordingly. */ -static void fifo_reg_write(const uint8_t *data, uint32_t data_size) -{ - uint32_t packet_size; - struct tpm_cmd_header *tpmh; - - /* - * Make sure we are in the appropriate state, otherwise ignore this - * access. - */ - if ((tpm_.state == tpm_state_ready) && (tpm_.fifo_write_index == 0)) - set_tpm_state(tpm_state_receiving_cmd); - - if (tpm_.state != tpm_state_receiving_cmd) { - CPRINTF("%s: ignoring data in state %d\n", - __func__, tpm_.state); - return; - } - - if ((tpm_.fifo_write_index + data_size) > sizeof(tpm_.regs.data_fifo)) { - CPRINTF("%s: receive buffer overflow: %d in addition to %d\n", - __func__, data_size, tpm_.fifo_write_index); - tpm_.fifo_write_index = 0; - set_tpm_state(tpm_state_ready); - return; - } - - /* Copy data into the local buffer. */ - memcpy(tpm_.regs.data_fifo + tpm_.fifo_write_index, - data, data_size); - - tpm_.fifo_write_index += data_size; - - /* Verify that size in the header matches the block size */ - if (tpm_.fifo_write_index < 6) { - tpm_.regs.sts |= expect; /* More data is needed. */ - return; - } - - tpmh = (struct tpm_cmd_header *)tpm_.regs.data_fifo; - packet_size = be32toh(tpmh->size); - if (tpm_.fifo_write_index < packet_size) { - tpm_.regs.sts |= expect; /* More data is needed. */ - return; - } - - /* All data has been received, Ready for the 'go' command. */ - tpm_.regs.sts &= ~expect; -} - -/* TODO: data_size is between 1 and 64, but is not trustworthy! Don't write - * past the end of any actual registers if data_size is larger than the spec - * allows. */ -void tpm_register_put(uint32_t regaddr, const uint8_t *data, uint32_t data_size) -{ - uint32_t i; - - CPRINTF("%s(0x%03x, %d,", __func__, regaddr, data_size); - for (i = 0; i < data_size && i < 4; i++) - CPRINTF(" %02x", data[i]); - if (data_size > 4) - CPRINTF(" ..."); - CPRINTF(")\n"); - - switch (regaddr) { - case TPM_ACCESS: - /* This is a one byte register, ignore extra data, if any */ - access_reg_write(data[0]); - break; - case TPM_STS: - sts_reg_write(data, data_size); - break; - case TPM_DATA_FIFO: - fifo_reg_write(data, data_size); - break; - case TPM_FW_VER: - /* Reset read byte count */ - tpm_fw_ver_index = 0; - break; - default: - CPRINTF("%s(0x%06x, %d bytes:", __func__, regaddr, data_size); - for (i = 0; i < data_size; i++) - CPRINTF(", %02x", data[i]); - CPRINTF("\n"); - return; - } - -} - -static void fifo_reg_read(uint8_t *dest, uint32_t data_size) -{ - uint32_t still_in_fifo = tpm_.fifo_write_index - - tpm_.fifo_read_index; - uint32_t tpm_sts; - - data_size = MIN(data_size, still_in_fifo); - memcpy(dest, - tpm_.regs.data_fifo + tpm_.fifo_read_index, - data_size); - - tpm_.fifo_read_index += data_size; - - tpm_sts = tpm_.regs.sts; - tpm_sts &= ~(burst_count_mask << burst_count_shift); - if (tpm_.fifo_write_index == tpm_.fifo_read_index) { - tpm_sts &= ~(data_avail | command_ready); - /* Burst size for the following write requests. */ - tpm_sts |= 63 << burst_count_shift; - } else { - /* - * Tell the master how much there is to read in the next - * burst. - */ - tpm_sts |= MIN(tpm_.fifo_write_index - - tpm_.fifo_read_index, 63) << burst_count_shift; - } - - tpm_.regs.sts = tpm_sts; -} - - -/* TODO: data_size is between 1 and 64, but is not trustworthy! We must return - * that many bytes, but not leak any secrets if data_size is larger than - * it should be. Return 0x00 or 0xff or whatever the spec says instead. */ -void tpm_register_get(uint32_t regaddr, uint8_t *dest, uint32_t data_size) -{ - int i; - - reset_in_progress = 0; - - CPRINTF("%s(0x%06x, %d)", __func__, regaddr, data_size); - switch (regaddr) { - case TPM_DID_VID: - copy_bytes(dest, data_size, (GOOGLE_DID << 16) | GOOGLE_VID); - break; - case TPM_RID: - copy_bytes(dest, data_size, CR50_RID); - break; - case TPM_INTF_CAPABILITY: - copy_bytes(dest, data_size, IF_CAPABILITY_REG); - break; - case TPM_ACCESS: - copy_bytes(dest, data_size, tpm_.regs.access); - break; - case TPM_STS: - CPRINTF(" %x", tpm_.regs.sts); - copy_bytes(dest, data_size, tpm_.regs.sts); - break; - case TPM_DATA_FIFO: - fifo_reg_read(dest, data_size); - break; - case TPM_FW_VER: - for (i = 0; i < data_size; i++) { - /* - * Only read while the index remains less than the - * maximum allowed version string size. - */ - if (tpm_fw_ver_index < sizeof(tpm_fw_ver)) { - *dest++ = tpm_fw_ver[tpm_fw_ver_index]; - /* - * If reached end of string, then don't update - * the index so that it will keep pointing at - * the end of string character and continue to - * fill *dest with 0s. - */ - if (tpm_fw_ver[tpm_fw_ver_index] != '\0') - tpm_fw_ver_index++; - } else - /* Not in a valid state, just stuff 0s */ - *dest++ = 0; - } - break; - default: - CPRINTS("%s(0x%06x, %d) => ??", __func__, regaddr, data_size); - return; - } - CPRINTF("\n"); -} - -static __preserved interface_control_func if_start; -static __preserved interface_control_func if_stop; -void tpm_register_interface(interface_control_func interface_start, - interface_control_func interface_stop) -{ - if_start = interface_start; - if_stop = interface_stop; -} - -static void tpm_init(void) -{ -#ifdef ENABLE_TPM - /* - * 0xc0 Means successful endorsement. Actual endorsement reasult code - * is added in lower bits to indicate endorsement failure, if any. - */ - uint8_t underrun_char = 0xc0; -#endif - /* This is more related to TPM task activity than TPM transactions */ - cprints(CC_TASK, "%s", __func__); - - if (system_rolling_reboot_suspected()) { - cprints(CC_TASK, "%s interrupted", __func__); - return; - } - - set_tpm_state(tpm_state_idle); - tpm_.regs.access = tpm_reg_valid_sts; - /* - * I2CS writes must limit the burstsize to 63 for fifo writes to work - * properly. For I2CS fifo writes the first byte is the I2C TPM address - * and the next up to 62 bytes are the data to write to that register. - */ - tpm_.regs.sts = (tpm_family_tpm2 << tpm_family_shift) | - (63 << burst_count_shift) | sts_valid; - - /* Create version string to be read by host */ - set_version_string(); - -#ifdef ENABLE_TPM - /* TPM2 library functions. */ - _plat__Signal_PowerOn(); - - watchdog_reload(); - - /* - * Make sure NV RAM metadata is initialized, needed to check - * manufactured status. This is a speculative call which will have to - * be repeated in case the TPM has not been through the manufacturing - * sequence yet. - * - * No harm in calling it twice in that case. - */ - _TPM_Init(); - - if (!tpm_manufactured()) { - enum manufacturing_status endorse_result; - - /* - * If tpm has not been manufactured yet - this needs to run on - * every startup. It will wipe out NV RAM, among other things. - */ - TPM_Manufacture(1); - _TPM_Init(); - _plat__SetNvAvail(); - endorse_result = tpm_endorse(); - - ccprints("Endorsement %s", - (endorse_result == mnf_success) ? - "succeeded" : "failed"); - - if (chip_factory_mode()) { - underrun_char |= endorse_result; - - ccprints("Setting underrun character to 0x%x", - underrun_char); - sps_tx_status(underrun_char); - } - } else { - if (chip_factory_mode()) - sps_tx_status(underrun_char | mnf_manufactured); - - _plat__SetNvAvail(); - } -#endif -} - -size_t tpm_get_burst_size(void) -{ - return (tpm_.regs.sts >> burst_count_shift) & burst_count_mask; -} - -#ifdef CONFIG_EXTENSION_COMMAND - -/* Recognize both original extension and new vendor-specific command codes */ -#define IS_CUSTOM_CODE(code) \ - ((code == CONFIG_EXTENSION_COMMAND) || \ - (code == TPM_CC_VENDOR_BIT_MASK)) - -static void call_extension_command(struct tpm_cmd_header *tpmh, - size_t *total_size, - uint32_t flags) -{ - size_t command_size = be32toh(tpmh->size); - uint32_t rc; - - /* - * Note that we don't look for TPM_CC_VENDOR_CR50 anywhere. All - * vendor-specific commands are handled the same way for now. - */ - - /* Verify there is room for at least the extension command header. */ - if (command_size >= sizeof(struct tpm_cmd_header)) { - struct vendor_cmd_params p = { - .code = be16toh(tpmh->subcommand_code), - /* The header takes room in the buffer. */ - .buffer = tpmh + 1, - .in_size = command_size - sizeof(struct tpm_cmd_header), - .out_size = *total_size - sizeof(struct tpm_cmd_header), - .flags = flags - }; - - rc = extension_route_command(&p); - - /* Add the header size back. */ - *total_size = p.out_size + sizeof(struct tpm_cmd_header); - tpmh->size = htobe32(*total_size); - - /* Flag errors from commands as vendor-specific */ - if (rc) - rc |= VENDOR_RC_ERR; - tpmh->command_code = htobe32(rc); - } else { - *total_size = command_size; - } -} -#endif - -/* - * Events used on the TPM task context. Make sure there is no collision with - * event(s) defined in chip/g/dcrypto/dcrypto_runtime.c - */ -#define TPM_EVENT_RESET TASK_EVENT_CUSTOM_BIT(1) -#define TPM_EVENT_COMMIT TASK_EVENT_CUSTOM_BIT(2) -#define TPM_EVENT_ALT_EXTENSION TASK_EVENT_CUSTOM_BIT(3) - -/* - * Result of executing of the TPM command on the alternative path, could have - * been interrupted by a reset. - */ -enum alt_process_result { - ALT_PROCESS_WAITING, - ALT_PROCESS_DONE, - ALT_PROCESS_INTERRUPTED -}; - -/* - * This structure stores the context of the alternative TPM command execution - * path. - * - * The command and response share the buffer, when TPM task finishes - * processing the command it sets the 'process_result' field to a non-zero - * value. - * - * The mutex ensures that only one alternative TPM command execution is active - * at a time. - */ -static __preserved struct alt_tpm_interface { - struct tpm_cmd_header *alt_hdr; - size_t alt_buffer_size; - uint32_t process_result; - struct mutex if_mutex; -} alt_if; - -void tpm_alt_extension(struct tpm_cmd_header *command, size_t buffer_size) -{ - mutex_lock(&alt_if.if_mutex); - memset(&alt_if, 0, sizeof(alt_if)); - - alt_if.alt_hdr = command; - alt_if.alt_buffer_size = buffer_size; - - do { - alt_if.process_result = ALT_PROCESS_WAITING; - - task_set_event(TASK_ID_TPM, TPM_EVENT_ALT_EXTENSION, 0); - - /* - * This is not very elegant, but simple and acceptable for - * this TPM command execution path, as in most cases it would - * be drven by a human operator. - * - * Use REG32 to make sure that the field is treated as - * volatile. - */ - while (REG32(&alt_if.process_result) == ALT_PROCESS_WAITING) - msleep(10); - - /* - * Repeat the request if command execution was interrupted by - * a TPM reset. - */ - } while (REG32(&alt_if.process_result) != ALT_PROCESS_DONE); - - mutex_unlock(&alt_if.if_mutex); -} - -/* Calling task (singular) to notify when the TPM reset has completed */ -static __initialized task_id_t waiting_for_reset = TASK_ID_INVALID; - -/* Return value from blocking tpm_reset_request() call */ -static __preserved int wipe_result; - -/* - * Did tpm_reset_request() request nvmem wipe? (intentionally cleared on reset) - */ -static int wipe_requested __attribute__((section(".bss.Tpm2_common"))); - -int tpm_reset_request(int wait_until_done, int wipe_nvmem_first) -{ - uint32_t evt; - - cprints(CC_TASK, "%s(%d, %d)", __func__, - wait_until_done, wipe_nvmem_first); - - if (reset_in_progress) { - cprints(CC_TASK, "%s: already scheduled", __func__); - return EC_ERROR_BUSY; - } - - reset_in_progress = 1; - wipe_result = EC_SUCCESS; - - /* We can't change our minds about wiping. */ - wipe_requested |= wipe_nvmem_first; - - if (wait_until_done) - /* - * Completion could take a while, if other things have - * higher priority. - */ - waiting_for_reset = task_get_current(); - - /* Ask the TPM task to reset itself */ - task_set_event(TASK_ID_TPM, TPM_EVENT_RESET, 0); - - if (!wait_until_done) - return EC_SUCCESS; - - if (in_interrupt_context() || - task_get_current() == TASK_ID_TPM) { - waiting_for_reset = TASK_ID_INVALID; - return EC_ERROR_BUSY; /* Can't sleep. Clown'll eat me. */ - } - - evt = task_wait_event_mask(TPM_EVENT_RESET, 5 * SECOND); - - /* We were notified of completion */ - if (evt & TPM_EVENT_RESET) - return wipe_result; - - /* Timeout is bad */ - return EC_ERROR_TIMEOUT; -} - -/* - * A timeout hook to reinstate NVMEM commits soon after reset. - * - * The TPM task disables nvmem commits during TPM reset, they need to be - * reinstated on the same task context. This is why an event is raised here to - * wake up the TPM task and force it to reinstate nvmem commits instead of - * doing it here directly. - */ -static void reinstate_nvmem_commits(void) -{ - tpm_reinstate_nvmem_commits(); -} -DECLARE_DEFERRED(reinstate_nvmem_commits); - -void tpm_reinstate_nvmem_commits(void) -{ - task_set_event(TASK_ID_TPM, TPM_EVENT_COMMIT, 0); -} - -static void tpm_reset_now(int wipe_first) -{ - /* TPM is not running in factory mode. */ - if (!chip_factory_mode()) - if_stop(); - - /* This is more related to TPM task activity than TPM transactions */ - cprints(CC_TASK, "%s(%d)", __func__, wipe_first); - - if (wipe_first) - /* Now wipe the TPM's nvmem */ - wipe_result = nvmem_erase_tpm_data(); - else - wipe_result = EC_SUCCESS; - - /* - * NOTE: If any __initialized variables need reinitializing after - * reset, this is the place to do it. - */ - - /* - * If TPM was reset while commits were disabled, save whatever changes - * might have accumulated. - */ - nvmem_enable_commits(); - - /* - * Clear the TPM library's zero-init data. Note that the linker script - * includes this file's .bss in the same section, so it will be cleared - * at the same time. - */ - memset(&__bss_libtpm2_start, 0, - (uintptr_t)(&__bss_libtpm2_end) - - (uintptr_t)(&__bss_libtpm2_start)); - - /* - * Prevent NVRAM commits until further notice, unless running in - * factory mode. - */ - if (!chip_factory_mode()) - nvmem_disable_commits(); - - /* Re-initialize our registers */ - tpm_init(); - - if (waiting_for_reset != TASK_ID_INVALID) { - /* Wake the waiting task, if any */ - task_set_event(waiting_for_reset, TPM_EVENT_RESET, 0); - waiting_for_reset = TASK_ID_INVALID; - } - - cprints(CC_TASK, "%s: done", __func__); - - /* - * The host might decide to do it sooner, but let's make sure commits - * do not stay disabled for more than 3 seconds. - */ - hook_call_deferred(&reinstate_nvmem_commits_data, 3 * SECOND); - - /* - * In chip factory mode SPI idle byte sent on MISO is used for - * progress reporting. TPM flow control messes it up, do not start TPM - * in factory mode. - */ - if (!chip_factory_mode()) - if_start(); -} - -int tpm_sync_reset(int wipe_first) -{ - tpm_reset_now(wipe_first); - - return wipe_result; -} - -void tpm_stop(void) -{ - /* Stop the TPM interface if it has been initialized. */ - if (if_stop) - if_stop(); -} - -void tpm_task(void *u) -{ - uint32_t evt = 0; - - if (!chip_factory_mode()) { - /* - * Just in case there is a resume from deep sleep where AP is - * not out of reset, let's not proceed until AP is actually - * up. No need to worry about the AP state in chip factory - * mode of course. - */ - while (!ap_is_on()) { - /* - * The only events we should expect at this point - * would be the reset request or a command routed - * through TPM task context to make use of the large - * stack. - */ - evt = task_wait_event(-1); - if (evt & (TPM_EVENT_RESET | TPM_EVENT_ALT_EXTENSION)) { - /* - * No need to remember the reset request: tpm - * reset will happen as soon as we break out - * from this while loop, - */ - evt &= TPM_EVENT_ALT_EXTENSION; - break; - } - - cprints(CC_TASK, "%s:%d unexpected event %x", - __func__, __LINE__, evt); - } - } - - tpm_reset_now(0); - while (1) { - uint8_t *response = NULL; - unsigned response_size; - uint32_t command_code; - struct tpm_cmd_header *tpmh; - size_t buffer_size; - uint8_t alt_if_command; - - /* Process unprocessed events or wait for the next event */ - if (!evt) - evt = task_wait_event(-1); - - if (evt & TPM_EVENT_RESET) { - tpm_reset_now(wipe_requested); - if (evt & TPM_EVENT_ALT_EXTENSION) { - /* - * Need to tell the waiting task that - * processing was interrupted. - */ - alt_if.process_result = ALT_PROCESS_INTERRUPTED; - } - /* - * There is no point in looking at other events in - * this situation: the nvram will be committed by TPM - * reset; other tpm commands would be ignored. - * - * Let's just continue. This could change if there are - * other events added to the set. - */ - evt = 0; - continue; - } - - if (evt & TPM_EVENT_COMMIT) { - evt &= ~TPM_EVENT_COMMIT; - nvmem_enable_commits(); - } - - if (evt & TASK_EVENT_WAKE) { - evt &= ~TASK_EVENT_WAKE; - tpmh = (struct tpm_cmd_header *)tpm_.regs.data_fifo; - buffer_size = sizeof(tpm_.regs.data_fifo); - alt_if_command = 0; - } else if (evt & TPM_EVENT_ALT_EXTENSION) { - evt &= ~TPM_EVENT_ALT_EXTENSION; - tpmh = alt_if.alt_hdr; - buffer_size = alt_if.alt_buffer_size; - alt_if_command = 1; - } else { - if (evt) { - cprints(CC_TASK, "%s:%d unexpected event %x", - __func__, __LINE__, evt); - evt = 0; - } - continue; - } - - command_code = be32toh(tpmh->command_code); - CPRINTF("%s: received fifo command 0x%04x\n", - __func__, command_code); - - watchdog_reload(); - -#ifdef CONFIG_EXTENSION_COMMAND - if (IS_CUSTOM_CODE(command_code)) { - response_size = buffer_size; - call_extension_command(tpmh, &response_size, - alt_if_command ? - VENDOR_CMD_FROM_USB : 0); - } else -#endif - { - if (board_id_is_mismatched()) { - static const char tpm_broken_response[] = { - 0x80, 0x01, /* TPM_ST_NO_SESSIONS */ - 0, 0, 0, 10, /* Response size. */ - 0, 0, 9, 0x21 /* TPM_RC_LOCKOUT */ - }; - CPRINTF("%s: Ignoring TPM commands\n", - __func__); - response = (uint8_t *)tpmh; - response_size = sizeof(tpm_broken_response); - memcpy(response, tpm_broken_response, - response_size); - } else { -#ifdef ENABLE_TPM - ExecuteCommand(tpm_.fifo_write_index, - (uint8_t *)tpmh, - &response_size, - &response); -#else - { - /* - * This response is sent by actual - * TPM2 when replying to gibberish - * input. Copy it here to avoid the - * need to add conditional compilation - * cases below. - */ - const uint8_t bad_cmd_resp[] = { - 0x00, 0xc4, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x1e - }; - response = (uint8_t *)tpmh; - response_size = sizeof(bad_cmd_resp); - memcpy(response, bad_cmd_resp, - response_size); - } -#endif - } - } - CPRINTF("got %d bytes in response\n", response_size); - if (response_size && - (response_size <= buffer_size)) { - uint32_t tpm_sts; - /* - * TODO(vbendeb): revisit this when - * crosbug.com/p/55667 has been addressed. - */ - if (command_code == TPM2_PCR_Read) - system_process_retry_counter(); -#ifdef CONFIG_EXTENSION_COMMAND - if (!IS_CUSTOM_CODE(command_code)) -#endif - { - /* - * Extension commands reuse FIFO buffer, the - * rest need to copy. - */ - memcpy(tpmh, response, response_size); - } - if (alt_if_command) { - alt_if.process_result = ALT_PROCESS_DONE; - /* No need to manage TPM registers. */ - continue; - } - tpm_.fifo_read_index = 0; - tpm_.fifo_write_index = response_size; - set_tpm_state(tpm_state_completing_cmd); - tpm_sts = tpm_.regs.sts; - tpm_sts &= ~(burst_count_mask << burst_count_shift); - tpm_sts |= (MIN(response_size, 63) << burst_count_shift) - | data_avail; - tpm_.regs.sts = tpm_sts; - } - } -} diff --git a/common/u2f.c b/common/u2f.c deleted file mode 100644 index 8cef638d3a..0000000000 --- a/common/u2f.c +++ /dev/null @@ -1,445 +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. - */ - -/* APDU dispatcher and U2F command handlers. */ - -#include "console.h" -#include "cryptoc/p256.h" -#include "cryptoc/sha256.h" -#include "dcrypto.h" -#include "extension.h" -#include "system.h" -#include "u2f_impl.h" -#include "u2f.h" -#include "util.h" - -#define G2F_CERT_NAME "CrOS" - -#define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ##args) - -/* Crypto parameters */ -#define AES_BLOCK_LEN 16 -#define KH_LEN 64 - -/* De-interleave 64 bytes into two 32 arrays. */ -static void deinterleave64(const uint8_t *in, uint8_t *a, uint8_t *b) -{ - size_t i; - - for (i = 0; i < 32; ++i) { - a[i] = in[2 * i + 0]; - b[i] = in[2 * i + 1]; - } -} - -/* (un)wrap w/ the origin dependent KEK. */ -static int wrap_kh(const uint8_t *origin, const uint8_t *in, - uint8_t *out, enum encrypt_mode mode) -{ - uint8_t kek[SHA256_DIGEST_SIZE]; - uint8_t iv[AES_BLOCK_LEN] = {0}; - int i; - - /* KEK derivation */ - if (u2f_gen_kek(origin, kek, sizeof(kek))) - return EC_ERROR_UNKNOWN; - - DCRYPTO_aes_init(kek, 256, iv, CIPHER_MODE_CBC, mode); - - for (i = 0; i < 4; i++) - DCRYPTO_aes_block(in + i * AES_BLOCK_LEN, - out + i * AES_BLOCK_LEN); - - return EC_SUCCESS; -} - -static int individual_cert(const p256_int *d, const p256_int *pk_x, - const p256_int *pk_y, uint8_t *cert, const int n) -{ - p256_int *serial; - - if (system_get_chip_unique_id((uint8_t **)&serial) != P256_NBYTES) - return 0; - - return DCRYPTO_x509_gen_u2f_cert_name(d, pk_x, pk_y, serial, - G2F_CERT_NAME, cert, n); -} - -int g2f_attestation_cert(uint8_t *buf) -{ - p256_int d, pk_x, pk_y; - - if (g2f_individual_keypair(&d, &pk_x, &pk_y)) - return 0; - - /* Note that max length is not currently respected here. */ - return individual_cert(&d, &pk_x, &pk_y, - buf, G2F_ATTESTATION_CERT_MAX_LEN); -} - -/* U2F GENERATE command */ -static enum vendor_cmd_rc u2f_generate(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) -{ - U2F_GENERATE_REQ *req = buf; - U2F_GENERATE_RESP *resp; - - /* Origin keypair */ - uint8_t od_seed[P256_NBYTES]; - p256_int od, opk_x, opk_y; - - /* Key handle */ - uint8_t kh[U2F_FIXED_KH_SIZE]; - - /* Whether keypair generation succeeded */ - int generate_keypair_rc; - - size_t response_buf_size = *response_size; - - *response_size = 0; - - if (input_size != sizeof(U2F_GENERATE_REQ) || - response_buf_size < sizeof(U2F_GENERATE_RESP)) - return VENDOR_RC_BOGUS_ARGS; - - /* Maybe enforce user presence, w/ optional consume */ - if (pop_check_presence(req->flags & G2F_CONSUME) != POP_TOUCH_YES && - (req->flags & U2F_AUTH_FLAG_TUP) != 0) - return VENDOR_RC_NOT_ALLOWED; - - /* Generate origin-specific keypair */ - do { - if (!DCRYPTO_ladder_random(&od_seed)) - return VENDOR_RC_INTERNAL_ERROR; - - if (u2f_origin_user_keyhandle(req->appId, req->userSecret, - od_seed, kh) != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - - generate_keypair_rc = - u2f_origin_user_keypair(kh, &od, &opk_x, &opk_y); - } while (generate_keypair_rc == EC_ERROR_TRY_AGAIN); - - if (generate_keypair_rc != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - - /* - * From this point: the request 'req' content is invalid as it is - * overridden by the response we are building in the same buffer. - */ - resp = buf; - - *response_size = sizeof(*resp); - - /* Insert origin-specific public keys into the response */ - p256_to_bin(&opk_x, resp->pubKey.x); /* endianness */ - p256_to_bin(&opk_y, resp->pubKey.y); /* endianness */ - - resp->pubKey.pointFormat = U2F_POINT_UNCOMPRESSED; - - /* Copy key handle to response. */ - memcpy(resp->keyHandle, kh, sizeof(kh)); - - return VENDOR_RC_SUCCESS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_GENERATE, u2f_generate); - -static int verify_kh_pubkey(const uint8_t *key_handle, - const U2F_EC_POINT *public_key, int *matches) { - int rc; - U2F_EC_POINT kh_pubkey; - p256_int od, opk_x, opk_y; - - rc = u2f_origin_user_keypair(key_handle, &od, &opk_x, &opk_y); - if (rc != EC_SUCCESS) - return rc; - - /* Reconstruct the public key. */ - p256_to_bin(&opk_x, kh_pubkey.x); - p256_to_bin(&opk_y, kh_pubkey.y); - kh_pubkey.pointFormat = U2F_POINT_UNCOMPRESSED; - - *matches = - safe_memcmp(&kh_pubkey, public_key, sizeof(U2F_EC_POINT)) == 0; - - return EC_SUCCESS; -} - -static int verify_kh_owned(const uint8_t *user_secret, const uint8_t *app_id, - const uint8_t *key_handle, int *owned) -{ - int rc; - /* Re-created key handle. */ - uint8_t recreated_kh[KH_LEN]; - - /* - * Re-create the key handle and compare against that which - * was provided. This allows us to verify that the key handle - * is owned by this combination of device, current user and app_id. - */ - - rc = u2f_origin_user_keyhandle(app_id, user_secret, key_handle, - recreated_kh); - - if (rc == EC_SUCCESS) - *owned = safe_memcmp(recreated_kh, key_handle, KH_LEN) == 0; - - return rc; -} - -static int verify_legacy_kh_owned(const uint8_t *app_id, - const uint8_t *key_handle, - uint8_t *origin_seed) -{ - uint8_t unwrapped_kh[KH_LEN]; - uint8_t kh_app_id[U2F_APPID_SIZE]; - - p256_int app_id_p256; - p256_int kh_app_id_p256; - - /* Unwrap key handle */ - if (wrap_kh(app_id, key_handle, unwrapped_kh, DECRYPT_MODE)) - return 0; - deinterleave64(unwrapped_kh, kh_app_id, origin_seed); - - /* Return whether appId (i.e. origin) matches. */ - p256_from_bin(app_id, &app_id_p256); - p256_from_bin(kh_app_id, &kh_app_id_p256); - return p256_cmp(&app_id_p256, &kh_app_id_p256) == 0; -} - -/* Below, we depend on the response not being larger than than the request. */ -BUILD_ASSERT(sizeof(U2F_SIGN_RESP) <= sizeof(U2F_SIGN_REQ)); - -/* U2F SIGN command */ -static enum vendor_cmd_rc u2f_sign(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) -{ - const U2F_SIGN_REQ *req = buf; - U2F_SIGN_RESP *resp; - - struct drbg_ctx ctx; - - /* Whether the key handle is owned by this device. */ - int kh_owned; - - /* Origin private key. */ - uint8_t legacy_origin_seed[SHA256_DIGEST_SIZE]; - p256_int origin_d; - - /* Hash, and corresponding signature. */ - p256_int h, r, s; - - /* Whether the key handle uses the legacy key derivation scheme. */ - int legacy_kh = 0; - - /* Response is smaller than request, so no need to check this. */ - *response_size = 0; - - if (input_size != sizeof(U2F_SIGN_REQ)) - return VENDOR_RC_BOGUS_ARGS; - - if (verify_kh_owned(req->userSecret, req->appId, req->keyHandle, - &kh_owned) != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - - if (!kh_owned) { - if ((req->flags & SIGN_LEGACY_KH) == 0) - return VENDOR_RC_PASSWORD_REQUIRED; - - /* - * We have a key handle which is not valid for the new scheme, - * but may be a valid legacy key handle, and we have been asked - * to sign legacy key handles. - */ - if (verify_legacy_kh_owned(req->appId, req->keyHandle, - legacy_origin_seed)) - legacy_kh = 1; - else - return VENDOR_RC_PASSWORD_REQUIRED; - } - - /* We might not actually need to sign anything. */ - if (req->flags == U2F_AUTH_CHECK_ONLY) - return VENDOR_RC_SUCCESS; - - /* Always enforce user presence, with optional consume. */ - if (pop_check_presence(req->flags & G2F_CONSUME) != POP_TOUCH_YES) - return VENDOR_RC_NOT_ALLOWED; - - /* Re-create origin-specific key. */ - if (legacy_kh) { - if (u2f_origin_key(legacy_origin_seed, &origin_d) != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - } else { - if (u2f_origin_user_keypair(req->keyHandle, &origin_d, NULL, - NULL) != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - } - - /* Prepare hash to sign. */ - p256_from_bin(req->hash, &h); - - /* Sign. */ - hmac_drbg_init_rfc6979(&ctx, &origin_d, &h); - if (!dcrypto_p256_ecdsa_sign(&ctx, &origin_d, &h, &r, &s)) { - p256_clear(&origin_d); - return VENDOR_RC_INTERNAL_ERROR; - } - p256_clear(&origin_d); - - /* - * From this point: the request 'req' content is invalid as it is - * overridden by the response we are building in the same buffer. - * The response is smaller than the request, so we have the space. - */ - resp = buf; - - *response_size = sizeof(*resp); - - p256_to_bin(&r, resp->sig_r); - p256_to_bin(&s, resp->sig_s); - - return VENDOR_RC_SUCCESS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_SIGN, u2f_sign); - -struct G2F_REGISTER_MSG { - uint8_t reserved; - uint8_t app_id[U2F_APPID_SIZE]; - uint8_t challenge[U2F_CHAL_SIZE]; - uint8_t key_handle[U2F_APPID_SIZE + sizeof(p256_int)]; - U2F_EC_POINT public_key; -}; - -static inline int u2f_attest_verify_reg_resp(const uint8_t *user_secret, - uint8_t data_size, - const uint8_t *data) -{ - struct G2F_REGISTER_MSG *msg = (void *) data; - int verified; - - if (data_size != sizeof(struct G2F_REGISTER_MSG)) - return VENDOR_RC_NOT_ALLOWED; - - if (msg->reserved != 0) - return VENDOR_RC_NOT_ALLOWED; - - if (verify_kh_owned(user_secret, msg->app_id, msg->key_handle, - &verified) != EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - - if (!verified) - return VENDOR_RC_NOT_ALLOWED; - - if (verify_kh_pubkey(msg->key_handle, &msg->public_key, &verified) != - EC_SUCCESS) - return VENDOR_RC_INTERNAL_ERROR; - - if (!verified) - return VENDOR_RC_NOT_ALLOWED; - - return VENDOR_RC_SUCCESS; -} - -static int u2f_attest_verify(const uint8_t *user_secret, - uint8_t format, - uint8_t data_size, - const uint8_t *data) -{ - switch (format) { - case U2F_ATTEST_FORMAT_REG_RESP: - return u2f_attest_verify_reg_resp(user_secret, data_size, data); - default: - return VENDOR_RC_NOT_ALLOWED; - } -} - -static inline size_t u2f_attest_format_size(uint8_t format) -{ - switch (format) { - case U2F_ATTEST_FORMAT_REG_RESP: - return sizeof(struct G2F_REGISTER_MSG); - default: - return 0; - } -} - -/* U2F ATTEST command */ -static enum vendor_cmd_rc u2f_attest(enum vendor_cmd_cc code, - void *buf, - size_t input_size, - size_t *response_size) -{ - const U2F_ATTEST_REQ *req = buf; - U2F_ATTEST_RESP *resp; - - int verify_ret; - - HASH_CTX h_ctx; - struct drbg_ctx dr_ctx; - - /* Data hash, and corresponding signature. */ - p256_int h, r, s; - - /* Attestation key */ - p256_int d, pk_x, pk_y; - - size_t response_buf_size = *response_size; - - *response_size = 0; - - if (input_size < offsetof(U2F_ATTEST_REQ, data) || - input_size < (offsetof(U2F_ATTEST_REQ, data) + req->dataLen) || - input_size > sizeof(U2F_ATTEST_REQ) || - response_buf_size < sizeof(*resp)) - return VENDOR_RC_BOGUS_ARGS; - - verify_ret = u2f_attest_verify(req->userSecret, - req->format, - req->dataLen, - req->data); - - if (verify_ret != VENDOR_RC_SUCCESS) - return verify_ret; - - /* Message signature */ - DCRYPTO_SHA256_init(&h_ctx, 0); - HASH_update(&h_ctx, req->data, u2f_attest_format_size(req->format)); - p256_from_bin(HASH_final(&h_ctx), &h); - - /* Derive G2F Attestation Key */ - if (g2f_individual_keypair(&d, &pk_x, &pk_y)) { - CPRINTF("G2F Attestation key generation failed"); - return VENDOR_RC_INTERNAL_ERROR; - } - - /* Sign over the response w/ the attestation key */ - hmac_drbg_init_rfc6979(&dr_ctx, &d, &h); - if (!dcrypto_p256_ecdsa_sign(&dr_ctx, &d, &h, &r, &s)) { - CPRINTF("Signing error"); - return VENDOR_RC_INTERNAL_ERROR; - } - p256_clear(&d); - - /* - * From this point: the request 'req' content is invalid as it is - * overridden by the response we are building in the same buffer. - * The response is smaller than the request, so we have the space. - */ - resp = buf; - - *response_size = sizeof(*resp); - - p256_to_bin(&r, resp->sig_r); - p256_to_bin(&s, resp->sig_s); - - return VENDOR_RC_SUCCESS; -} -DECLARE_VENDOR_COMMAND(VENDOR_CC_U2F_ATTEST, u2f_attest); diff --git a/common/update_fw.c b/common/update_fw.c index d0cb35e697..bdb432acd6 100644 --- a/common/update_fw.c +++ b/common/update_fw.c @@ -5,7 +5,6 @@ #include "byteorder.h" #include "console.h" -#include "extension.h" #include "flash.h" #include "hooks.h" #include "include/compile_time_macros.h" @@ -106,7 +105,6 @@ static uint8_t check_update_chunk(uint32_t block_offset, size_t body_size) } -/* TODO(b/36375666): These need to be overridden for chip/g. */ int update_pdu_valid(struct update_command *cmd_body, size_t cmd_size) { return 1; @@ -283,11 +281,6 @@ void fw_update_command_handler(void *body, return; } - /* - * TODO(b/36375666): chip/g code has some cr50-specific stuff right - * here, which should probably be merged into contents_allowed... - */ - #ifdef CONFIG_TOUCHPAD_VIRTUAL_OFF if (is_touchpad_block(block_offset, body_size)) { if (touchpad_update_write( @@ -329,7 +322,6 @@ void fw_update_command_handler(void *body, *error_code = UPDATE_SUCCESS; } -/* TODO(b/36375666): This need to be overridden for chip/g. */ void fw_update_complete(void) { } diff --git a/common/usb_update.c b/common/usb_update.c index 23b3ed4512..cc443163ba 100644 --- a/common/usb_update.c +++ b/common/usb_update.c @@ -8,7 +8,6 @@ #include "console.h" #include "consumer.h" #include "curve25519.h" -#include "extension.h" #include "flash.h" #include "queue_policies.h" #include "host_command.h" diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S index 3697a72516..9aa1c987ba 100644 --- a/core/cortex-m/ec.lds.S +++ b/core/cortex-m/ec.lds.S @@ -220,12 +220,6 @@ SECTIONS KEEP(*(.rodata.HOOK_BATTERY_SOC_CHANGE)) __hooks_battery_soc_change_end = .; -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1 - __hooks_ccd_change = .; - KEEP(*(.rodata.HOOK_CCD_CHANGE)) - __hooks_ccd_change_end = .; -#endif - #ifdef CONFIG_USB_SUSPEND __hooks_usb_change = .; KEEP(*(.rodata.HOOK_USB_PM_CHANGE)) diff --git a/extra/usb_updater/Makefile b/extra/usb_updater/Makefile index 2f8f70a6d3..1dfbc55645 100644 --- a/extra/usb_updater/Makefile +++ b/extra/usb_updater/Makefile @@ -4,7 +4,7 @@ CC ?= gcc PKG_CONFIG ?= pkg-config -PROGRAMS := gsctool usb_updater2 +PROGRAMS := usb_updater2 LIBS := LFLAGS := CFLAGS := -std=gnu99 \ @@ -34,27 +34,12 @@ CFLAGS += -I../../include -I../../util -I../../fuzz -I../../test VPATH = ../../util -BOARD := cr50 -LIBS_g = $(shell $(PKG_CONFIG) --libs libcrypto) -CFLAGS_g = $(shell $(PKG_CONFIG) --cflags libcrypto) -CFLAGS_g += -I../../board/cr50 -I ../../chip/g - LIBS_common = -lfmap all: $(PROGRAMS) -GSCTOOL_SOURCES := gsctool.c desc_parser.c usb_if.c verify_ro.c -GSCTOOL_OBJS := $(patsubst %.c,%.o,$(GSCTOOL_SOURCES)) -DEPS := $(patsubst %.c,%.d,$(GSCTOOL_SOURCES)) - -# chip/g updater -gsctool: $(GSCTOOL_OBJS) Makefile - $(CC) $(GSCTOOL_OBJS) $(LFLAGS) $(LIBS) $(LIBS_g) -o $@ - %.o: %.c - $(CC) $(CFLAGS) $(CFLAGS_g) -c -MMD -MF $(basename $@).d -o $@ $< - -gsctool.o: generated_version.h + $(CC) $(CFLAGS) -c -MMD -MF $(basename $@).d -o $@ $< # common EC code USB updater usb_updater2: usb_updater2.c Makefile @@ -62,16 +47,9 @@ usb_updater2: usb_updater2.c Makefile .PHONY: clean -generated_version.h: $(GSCTOOL_SOURCES) - # Make sure ${BOARD} not set to anything when invoking getversion.sh, - # as even when building with Cr50 enabled, other directories do not - # matter for gsctool. - @(cd ../../; BOARD= util/getversion.sh) > $@ - clean: - rm -rf $(PROGRAMS) *~ *.o *.d dp generated_version.h + rm -rf $(PROGRAMS) *~ *.o *.d dp parser_debug: desc_parser.c gcc -g -O0 -DTEST_PARSER desc_parser.c -o dp --include $(DEPS) diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c deleted file mode 100644 index 4540814e56..0000000000 --- a/extra/usb_updater/gsctool.c +++ /dev/null @@ -1,3027 +0,0 @@ -/* - * Copyright 2015 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 <asm/byteorder.h> -#include <ctype.h> -#include <endian.h> -#include <errno.h> -#include <fcntl.h> -#include <getopt.h> -#include <libusb.h> -#include <openssl/sha.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <termios.h> -#include <unistd.h> - -#include "config.h" - -#include "ccd_config.h" -#include "compile_time_macros.h" -#include "flash_log.h" -#include "generated_version.h" -#include "gsctool.h" -#include "misc_util.h" -#include "signed_header.h" -#include "tpm_registers.h" -#include "tpm_vendor_cmds.h" -#include "upgrade_fw.h" -#include "usb_descriptor.h" -#include "verify_ro.h" - -/* - * This file contains the source code of a Linux application used to update - * CR50 device firmware. - * - * The CR50 firmware image consists of multiple sections, of interest to this - * app are the RO and RW code sections, two of each. When firmware update - * session is established, the CR50 device reports locations of backup RW and RO - * sections (those not used by the device at the time of transfer). - * - * Based on this information this app carves out the appropriate sections form - * the full CR50 firmware binary image and sends them to the device for - * programming into flash. Once the new sections are programmed and the device - * is restarted, the new RO and RW are used if they pass verification and are - * logically newer than the existing sections. - * - * There are two ways to communicate with the CR50 device: USB and /dev/tpm0 - * (when this app is running on a chromebook with the CR50 device). Originally - * different protocols were used to communicate over different channels, - * starting with version 3 the same protocol is used. - * - * This app provides backwards compatibility to ensure that earlier CR50 - * devices still can be updated. - * - * - * The host (either a local AP or a workstation) is the master of the firmware - * update protocol, it sends data to the cr50 device, which proceeses it and - * responds. - * - * The encapsultation format is different between the /dev/tpm0 and USB cases: - * - * 4 bytes 4 bytes 4 bytes variable size - * +-----------+--------------+---------------+----------~~--------------+ - * + total size| block digest | dest address | data | - * +-----------+--------------+---------------+----------~~--------------+ - * \ \ / - * \ \ / - * \ +----- FW update PDU sent over /dev/tpm0 -----------+ - * \ / - * +--------- USB frame, requires total size field ------------+ - * - * The update protocol data unints (PDUs) are passed over /dev/tpm0, the - * encapsulation includes integritiy verification and destination address of - * the data (more of this later). /dev/tpm0 transactions pretty much do not - * have size limits, whereas the USB data is sent in chunks of the size - * determined when the USB connestion is set up. This is why USB requires an - * additional encapsulation into frames to communicate the PDU size to the - * client side so that the PDU can be reassembled before passing to the - * programming function. - * - * In general, the protocol consists of two phases: connection establishment - * and actual image transfer. - * - * The very first PDU of the transfer session is used to establish the - * connection. The first PDU does not have any data, and the dest. address - * field is set to zero. Receiving such a PDU signals the programming function - * that the host intends to transfer a new image. - * - * The response to the first PDU varies depending on the protocol version. - * - * Note that protocol versions before 5 are described here for completeness, - * but are not supported any more by this utility. - * - * Version 1 is used over /dev/tpm0. The response is either 4 or 1 bytes in - * size. The 4 byte response is the *base address* of the backup RW section, - * no support for RO updates. The one byte response is an error indication, - * possibly reporting flash erase failure, command format error, etc. - * - * Version 2 is used over USB. The response is 8 bytes in size. The first four - * bytes are either the *base address* of the backup RW section (still no RO - * updates), or an error code, the same as in Version 1. The second 4 bytes - * are the protocol version number (set to 2). - * - * All versions above 2 behave the same over /dev/tpm0 and USB. - * - * Version 3 response is 16 bytes in size. The first 4 bytes are the error code - * the second 4 bytes are the protocol version (set to 3) and then 4 byte - * *offset* of the RO section followed by the 4 byte *offset* of the RW section. - * - * Version 4 response in addition to version 3 provides header revision fields - * for active RO and RW images running on the target. - * - * Once the connection is established, the image to be programmed into flash - * is transferred to the CR50 in 1K PDUs. In versions 1 and 2 the address in - * the header is the absolute address to place the block to, in version 3 and - * later it is the offset into the flash. - * - * Protocol version 5 includes RO and RW key ID information into the first PDU - * response. The key ID could be used to tell between prod and dev signing - * modes, among other things. - * - * Protocol version 6 does not change the format of the first PDU response, - * but it indicates the target's ablitiy to channel TPM vendor commands - * through USB connection. - * - * When channeling TPM vendor commands the USB frame looks as follows: - * - * 4 bytes 4 bytes 4 bytes 2 bytes variable size - * +-----------+--------------+---------------+-----------+------~~~-------+ - * + total size| block digest | EXT_CMD | Vend. sub.| data | - * +-----------+--------------+---------------+-----------+------~~~-------+ - * - * Where 'Vend. sub' is the vendor subcommand, and data field is subcommand - * dependent. The target tells between update PDUs and encapsulated vendor - * subcommands by looking at the EXT_CMD value - it is set to 0xbaccd00a and - * as such is guaranteed not to be a valid update PDU destination address. - * - * The vendor command response size is not fixed, it is subcommand dependent. - * - * The CR50 device responds to each update PDU with a confirmation which is 4 - * bytes in size in protocol version 2, and 1 byte in size in all other - * versions. Zero value means success, non zero value is the error code - * reported by CR50. - * - * Again, vendor command responses are subcommand specific. - */ - -/* Look for Cr50 FW update interface */ -#define VID USB_VID_GOOGLE -#define PID CONFIG_USB_PID -#define SUBCLASS USB_SUBCLASS_GOOGLE_CR50 -#define PROTOCOL USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE - -/* - * Need to create an entire TPM PDU when upgrading over /dev/tpm0 and need to - * have space to prepare the entire PDU. - */ -struct upgrade_pkt { - __be16 tag; - __be32 length; - __be32 ordinal; - __be16 subcmd; - union { - /* - * Upgrade PDUs as opposed to all other vendor and extension - * commands include two additional fields in the header. - */ - struct { - __be32 digest; - __be32 address; - char data[0]; - } upgrade; - struct { - char data[0]; - } command; - }; -} __packed; - -/* - * Structure used to simplify mapping command line options into Boolean - * variables. If an option is present, the corresponding integer value is set - * to 1. - */ -struct options_map { - char opt; - int *flag; -}; - -/* - * Structure used to combine option description used by getopt_long() and help - * text for the option. - */ -struct option_container { - struct option opt; - const char *help_text; -}; - -/* - * This by far exceeds the largest vendor command response size we ever - * expect. - */ -#define MAX_BUF_SIZE 500 - -/* - * Max. length of the board ID string representation. - * - * Board ID is either a 4-character ASCII alphanumeric string or an 8-digit - * hex. - */ -#define MAX_BOARD_ID_LENGTH 9 - -/* - * Length, in bytes, of the SN Bits serial number bits. - */ -#define SN_BITS_SIZE (96 >> 3) - -/* - * Max. length of FW version in the format of <epoch>.<major>.<minor> - * (3 uint32_t string representation + 2 separators + NULL terminator). - */ -#define MAX_FW_VER_LENGTH 33 - -static int verbose_mode; -static uint32_t protocol_version; -static char *progname; - -/* - * List of command line options, ***sorted by the short form***. - * - * The help_text field does not include the short and long option strings, - * they are retrieved from the opt structure. In case the help text needs to - * have something printed immediately after the option strings (for example, - * an optional parameter), it should be included in the beginning of help_text - * string separated by the % character. - * - * usage() function which prints out the help message will concatenate the - * short and long options and the optional parameter, if present, and then - * print the rest of the text message at a fixed indentation. - */ -static const struct option_container cmd_line_options[] = { - /* name has_arg *flag val */ - {{"any", no_argument, NULL, 'a'}, - "Try any interfaces to find Cr50" - " (-d, -s, -t are all ignored)"}, - {{"background_update_supported", no_argument, NULL, 'B'}, - "Force background update mode (relevant" - " only when interacting" - " with Cr50 versions before 0.0.19)" - }, - {{"binvers", no_argument, NULL, 'b'}, - "Report versions of Cr50 image's " - "RW and RO headers, do not update"}, - {{"corrupt", no_argument, NULL, 'c'}, - "Corrupt the inactive rw"}, - {{"device", required_argument, NULL, 'd'}, - " VID:PID%USB device (default 18d1:5014)"}, - {{"endorsement_seed", optional_argument, NULL, 'e'}, - "[state]%get/set the endorsement key seed"}, - {{"fwver", no_argument, NULL, 'f'}, - "Report running Cr50 firmware versions"}, - {{"factory", required_argument, NULL, 'F'}, - "[enable|disable]%Control factory mode"}, - {{"help", no_argument, NULL, 'h'}, - "Show this message"}, - {{"ccd_info", no_argument, NULL, 'I'}, - "Get information about CCD state"}, - {{"board_id", optional_argument, NULL, 'i'}, - "[ID[:FLAGS]]%Get or set Info1 board ID fields. ID could be 32 bit " - "hex or 4 character string."}, - {{"ccd_lock", no_argument, NULL, 'k'}, - "Lock CCD"}, - {{"flog", optional_argument, NULL, 'L'}, - "[prev entry]%Retrieve contents of the flash log" - " (newer than <prev entry> if specified)"}, - {{"machine", no_argument, NULL, 'M'}, - "Output in a machine-friendly way. " - "Effective with -b, -f, -i, and -O."}, - {{"tpm_mode", optional_argument, NULL, 'm'}, - "[enable|disable]%Change or query tpm_mode"}, - {{"serial", required_argument, NULL, 'n'}, - "Cr50 CCD serial number"}, - {{"openbox_rma", required_argument, NULL, 'O'}, - "<desc_file>%Verify other device's RO integrity using information " - "provided in <desc file>"}, - {{"ccd_open", no_argument, NULL, 'o'}, - "Start CCD open sequence"}, - {{"password", no_argument, NULL, 'P'}, - "Set or clear CCD password. Use 'clear:<cur password>' to clear it"}, - {{"post_reset", no_argument, NULL, 'p'}, - "Request post reset after transfer"}, - {{"force_ro", no_argument, NULL, 'q'}, - "Force inactive RO update"}, - {{"sn_rma_inc", required_argument, NULL, 'R'}, - "RMA_INC%Increment SN RMA count by RMA_INC. RMA_INC should be 0-7."}, - {{"rma_auth", optional_argument, NULL, 'r'}, - "[auth_code]%Request RMA challenge, process " - "RMA authentication code"}, - {{"sn_bits", required_argument, NULL, 'S'}, - "SN_BITS%Set Info1 SN bits fields. SN_BITS should be 96 bit hex."}, - {{"systemdev", no_argument, NULL, 's'}, - "Use /dev/tpm0 (-d is ignored)"}, - {{"tstamp", optional_argument, NULL, 'T'}, - "[<tstamp>]%Get or set flash log timestamp base"}, - {{"trunks_send", no_argument, NULL, 't'}, - "Use `trunks_send --raw' (-d is ignored)"}, - {{"ccd_unlock", no_argument, NULL, 'U'}, - "Start CCD unlock sequence"}, - {{"upstart", no_argument, NULL, 'u'}, - "Upstart mode (strict header checks)"}, - {{"verbose", no_argument, NULL, 'V'}, - "Enable debug messages"}, - {{"version", no_argument, NULL, 'v'}, - "Report this utility version"}, - {{"wp", no_argument, NULL, 'w'}, - "Get the current wp setting"} -}; - -/* Helper to print debug messages when verbose flag is specified. */ -static void debug(const char *fmt, ...) -{ - va_list args; - - if (verbose_mode) { - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - } -} - -/* Helpers to convert between binary and hex ascii and back. */ -static char to_hexascii(uint8_t c) -{ - if (c <= 9) - return '0' + c; - return 'a' + c - 10; -} - -static int from_hexascii(char c) -{ - /* convert to lower case. */ - c = tolower(c); - - if (c < '0' || c > 'f' || ((c > '9') && (c < 'a'))) - return -1; /* Not an ascii character. */ - - if (c <= '9') - return c - '0'; - - return c - 'a' + 10; -} - -/* Functions to communicate with the TPM over the trunks_send --raw channel. */ - -/* File handle to share between write and read sides. */ -static FILE *tpm_output; -static int ts_write(const void *out, size_t len) -{ - const char *cmd_head = "PATH=\"${PATH}:/usr/sbin\" trunks_send --raw "; - size_t head_size = strlen(cmd_head); - char full_command[head_size + 2 * len + 1]; - size_t i; - - strcpy(full_command, cmd_head); - /* - * Need to convert binary input into hex ascii output to pass to the - * trunks_send command. - */ - for (i = 0; i < len; i++) { - uint8_t c = ((const uint8_t *)out)[i]; - - full_command[head_size + 2 * i] = to_hexascii(c >> 4); - full_command[head_size + 2 * i + 1] = to_hexascii(c & 0xf); - } - - /* Make it a proper zero terminated string. */ - full_command[sizeof(full_command) - 1] = 0; - debug("cmd: %s\n", full_command); - tpm_output = popen(full_command, "r"); - if (tpm_output) - return len; - - fprintf(stderr, "Error: failed to launch trunks_send --raw\n"); - return -1; -} - -static int ts_read(void *buf, size_t max_rx_size) -{ - int i; - int pclose_rv; - int rv; - char response[max_rx_size * 2]; - - if (!tpm_output) { - fprintf(stderr, "Error: attempt to read empty output\n"); - return -1; - } - - rv = fread(response, 1, sizeof(response), tpm_output); - if (rv > 0) - rv -= 1; /* Discard the \n character added by trunks_send. */ - - debug("response of size %d, max rx size %zd: %s\n", - rv, max_rx_size, response); - - pclose_rv = pclose(tpm_output); - if (pclose_rv < 0) { - fprintf(stderr, - "Error: pclose failed: error %d (%s)\n", - errno, strerror(errno)); - return -1; - } - - tpm_output = NULL; - - if (rv & 1) { - fprintf(stderr, - "Error: trunks_send returned odd number of bytes: %s\n", - response); - return -1; - } - - for (i = 0; i < rv/2; i++) { - uint8_t byte; - char c; - int nibble; - - c = response[2 * i]; - nibble = from_hexascii(c); - if (nibble < 0) { - fprintf(stderr, "Error: " - "trunks_send returned non hex character %c\n", - c); - return -1; - } - byte = nibble << 4; - - c = response[2 * i + 1]; - nibble = from_hexascii(c); - if (nibble < 0) { - fprintf(stderr, "Error: " - "trunks_send returned non hex character %c\n", - c); - return -1; - } - byte |= nibble; - - ((uint8_t *)buf)[i] = byte; - } - - return rv/2; -} - -/* - * Prepare and transfer a block to either to /dev/tpm0 or through trunks_send - * --raw, get a reply. - */ -static int tpm_send_pkt(struct transfer_descriptor *td, unsigned int digest, - unsigned int addr, const void *data, int size, - void *response, size_t *response_size, - uint16_t subcmd) -{ - /* Used by transfer to /dev/tpm0 */ - static uint8_t outbuf[MAX_BUF_SIZE]; - struct upgrade_pkt *out = (struct upgrade_pkt *)outbuf; - int len, done; - int response_offset = offsetof(struct upgrade_pkt, command.data); - void *payload; - size_t header_size; - uint32_t rv; - const size_t rx_size = sizeof(outbuf); - - debug("%s: sending to %#x %d bytes\n", __func__, addr, size); - - out->tag = htobe16(0x8001); - out->subcmd = htobe16(subcmd); - - if (subcmd <= LAST_EXTENSION_COMMAND) - out->ordinal = htobe32(CONFIG_EXTENSION_COMMAND); - else - out->ordinal = htobe32(TPM_CC_VENDOR_BIT_MASK); - - if (subcmd == EXTENSION_FW_UPGRADE) { - /* FW Upgrade PDU header includes a couple of extra fields. */ - out->upgrade.digest = digest; - out->upgrade.address = htobe32(addr); - header_size = offsetof(struct upgrade_pkt, upgrade.data); - } else { - header_size = offsetof(struct upgrade_pkt, command.data); - } - - payload = outbuf + header_size; - len = size + header_size; - - out->length = htobe32(len); - memcpy(payload, data, size); - - if (verbose_mode) { - int i; - - debug("Writing %d bytes to TPM at %x\n", len, addr); - for (i = 0; i < MIN(len, 20); i++) - debug("%2.2x ", outbuf[i]); - debug("\n"); - } - - switch (td->ep_type) { - case dev_xfer: - done = write(td->tpm_fd, out, len); - break; - case ts_xfer: - done = ts_write(out, len); - break; - default: - fprintf(stderr, "Error: %s:%d: unknown transfer type %d\n", - __func__, __LINE__, td->ep_type); - return -1; - } - - if (done < 0) { - perror("Could not write to TPM"); - return -1; - } else if (done != len) { - fprintf(stderr, "Error: Wrote %d bytes, expected to write %d\n", - done, len); - return -1; - } - - switch (td->ep_type) { - case dev_xfer: { - int read_count; - - len = 0; - do { - uint8_t *rx_buf = outbuf + len; - size_t rx_to_go = rx_size - len; - - read_count = read(td->tpm_fd, rx_buf, rx_to_go); - - len += read_count; - } while (read_count); - break; - } - case ts_xfer: - len = ts_read(outbuf, rx_size); - break; - default: - /* - * This sure will never happen, type is verifed in the - * previous switch statement. - */ - len = -1; - break; - } - - debug("Read %d bytes from TPM\n", len); - if (len > 0) { - int i; - - for (i = 0; i < len; i++) - debug("%2.2x ", outbuf[i]); - debug("\n"); - } - len = len - response_offset; - if (len < 0) { - fprintf(stderr, "Problems reading from TPM, got %d bytes\n", - len + response_offset); - return -1; - } - - if (response && response_size) { - len = MIN(len, *response_size); - memcpy(response, outbuf + response_offset, len); - *response_size = len; - } - - /* Return the actual return code from the TPM response header. */ - memcpy(&rv, &((struct upgrade_pkt *)outbuf)->ordinal, sizeof(rv)); - rv = be32toh(rv); - - /* Clear out vendor command return value offset.*/ - if ((rv & VENDOR_RC_ERR) == VENDOR_RC_ERR) - rv &= ~VENDOR_RC_ERR; - - return rv; -} - -/* Release USB device and return error to the OS. */ -static void shut_down(struct usb_endpoint *uep) -{ - usb_shut_down(uep); - exit(update_error); -} - -static void usage(int errs) -{ - size_t i; - const int indent = 27; /* This is the size used by gsctool all along. */ - - printf("\nUsage: %s [options] [<binary image>]\n" - "\n" - "This utility allows to update Cr50 RW firmware, configure\n" - "various aspects of Cr50 operation, analyze Cr50 binary\n" - "images, etc.\n\n" - "<binary image> is the file name of a full RO+RW binary image.\n" - "\n" - "Options:\n\n", - progname); - - for (i = 0; i < ARRAY_SIZE(cmd_line_options); i++) { - const char *help_text = cmd_line_options[i].help_text; - int printed_length; - const char *separator; - - /* - * First print the short and long forms of the command line - * option. - */ - printed_length = printf(" -%c,--%s", - cmd_line_options[i].opt.val, - cmd_line_options[i].opt.name); - - /* - * If there is something to print immediately after the - * options, print it. - */ - separator = strchr(help_text, '%'); - if (separator) { - char buffer[80]; - size_t extra_size; - - extra_size = separator - help_text; - if (extra_size >= sizeof(buffer)) { - fprintf(stderr, "misformatted help text: %s\n", - help_text); - exit(-1); - } - memcpy(buffer, help_text, extra_size); - buffer[extra_size] = '\0'; - printed_length += printf(" %s", buffer); - help_text = separator + 1; - } - - /* - * If printed length exceeds or is too close to indent, print - * help text on the next line. - */ - if (printed_length >= (indent - 1)) { - printf("\n"); - printed_length = 0; - } - - while (printed_length++ < indent) - printf(" "); - printf("%s\n", help_text); - } - printf("\n"); - exit(errs ? update_error : noop); -} - -/* Read file into buffer */ -static uint8_t *get_file_or_die(const char *filename, size_t *len_ptr) -{ - FILE *fp; - struct stat st; - uint8_t *data; - size_t len; - - fp = fopen(filename, "rb"); - if (!fp) { - perror(filename); - exit(update_error); - } - if (fstat(fileno(fp), &st)) { - perror("stat"); - exit(update_error); - } - - len = st.st_size; - - data = malloc(len); - if (!data) { - perror("malloc"); - exit(update_error); - } - - if (1 != fread(data, st.st_size, 1, fp)) { - perror("fread"); - exit(update_error); - } - - fclose(fp); - - *len_ptr = len; - return data; -} - -/* Returns true if parsed. */ -static int parse_vidpid(const char *input, uint16_t *vid_ptr, uint16_t *pid_ptr) -{ - char *copy, *s, *e = 0; - - copy = strdup(input); - - s = strchr(copy, ':'); - if (!s) - return 0; - *s++ = '\0'; - - *vid_ptr = (uint16_t) strtoul(copy, &e, 16); - if (!*optarg || (e && *e)) - return 0; - - *pid_ptr = (uint16_t) strtoul(s, &e, 16); - if (!*optarg || (e && *e)) - return 0; - - return 1; -} - -struct update_pdu { - uint32_t block_size; /* Total block size, include this field's size. */ - struct upgrade_command cmd; - /* The actual payload goes here. */ -}; - -static void do_xfer(struct usb_endpoint *uep, void *outbuf, int outlen, - void *inbuf, int inlen, int allow_less, size_t *rxed_count) -{ - if (usb_trx(uep, outbuf, outlen, inbuf, inlen, allow_less, rxed_count)) - shut_down(uep); -} - -static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu, - uint8_t *transfer_data_ptr, size_t payload_size) -{ - size_t transfer_size; - uint32_t reply; - int actual; - int r; - - /* First send the header. */ - do_xfer(uep, updu, sizeof(*updu), NULL, 0, 0, NULL); - - /* Now send the block, chunk by chunk. */ - for (transfer_size = 0; transfer_size < payload_size;) { - int chunk_size; - - chunk_size = MIN(uep->chunk_len, payload_size - transfer_size); - do_xfer(uep, transfer_data_ptr, chunk_size, NULL, 0, 0, NULL); - transfer_data_ptr += chunk_size; - transfer_size += chunk_size; - } - - /* Now get the reply. */ - r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80, - (void *) &reply, sizeof(reply), - &actual, 1000); - if (r) { - if (r == -7) { - fprintf(stderr, "Timeout!\n"); - return r; - } - USB_ERROR("libusb_bulk_transfer", r); - shut_down(uep); - } - - reply = *((uint8_t *)&reply); - if (reply) { - fprintf(stderr, "Error: status %#x\n", reply); - exit(update_error); - } - - return 0; -} - -/** - * Transfer an image section (typically RW or RO). - * - * td - transfer descriptor to use to communicate with the target - * data_ptr - pointer at the section base in the image - * section_addr - address of the section in the target memory space - * data_len - section size - */ -static void transfer_section(struct transfer_descriptor *td, - uint8_t *data_ptr, - uint32_t section_addr, - size_t data_len) -{ - /* - * Actually, we can skip trailing chunks of 0xff, as the entire - * section space must be erased before the update is attempted. - */ - while (data_len && (data_ptr[data_len - 1] == 0xff)) - data_len--; - - /* - * Make sure total size is 4 bytes aligned, this is required for - * successful flashing. - */ - data_len = (data_len + 3) & ~3; - - printf("sending 0x%zx bytes to %#x\n", data_len, section_addr); - while (data_len) { - size_t payload_size; - SHA_CTX ctx; - uint8_t digest[SHA_DIGEST_LENGTH]; - int max_retries; - struct update_pdu updu; - - /* prepare the header to prepend to the block. */ - payload_size = MIN(data_len, SIGNED_TRANSFER_SIZE); - updu.block_size = htobe32(payload_size + - sizeof(struct update_pdu)); - - updu.cmd.block_base = htobe32(section_addr); - - /* Calculate the digest. */ - SHA1_Init(&ctx); - SHA1_Update(&ctx, &updu.cmd.block_base, - sizeof(updu.cmd.block_base)); - SHA1_Update(&ctx, data_ptr, payload_size); - SHA1_Final(digest, &ctx); - - /* Copy the first few bytes. */ - memcpy(&updu.cmd.block_digest, digest, - sizeof(updu.cmd.block_digest)); - if (td->ep_type == usb_xfer) { - for (max_retries = 10; max_retries; max_retries--) - if (!transfer_block(&td->uep, &updu, - data_ptr, payload_size)) - break; - - if (!max_retries) { - fprintf(stderr, - "Failed to transfer block, %zd to go\n", - data_len); - exit(update_error); - } - } else { - uint8_t error_code[4]; - size_t rxed_size = sizeof(error_code); - uint32_t block_addr; - - block_addr = section_addr; - - /* - * A single byte response is expected, but let's give - * the driver a few extra bytes to catch cases when a - * different amount of data is transferred (which - * would indicate a synchronization problem). - */ - if (tpm_send_pkt(td, - updu.cmd.block_digest, - block_addr, - data_ptr, - payload_size, error_code, - &rxed_size, - EXTENSION_FW_UPGRADE) < 0) { - fprintf(stderr, - "Failed to trasfer block, %zd to go\n", - data_len); - exit(update_error); - } - if (rxed_size != 1) { - fprintf(stderr, "Unexpected return size %zd\n", - rxed_size); - exit(update_error); - } - - if (error_code[0]) { - fprintf(stderr, "Error %d\n", error_code[0]); - exit(update_error); - } - } - data_len -= payload_size; - data_ptr += payload_size; - section_addr += payload_size; - } -} - -/* Information about the target */ -static struct first_response_pdu targ; - -/* - * Each RO or RW section of the new image can be in one of the following - * states. - */ -enum upgrade_status { - not_needed = 0, /* Version below or equal that on the target. */ - not_possible, /* - * RO is newer, but can't be transferred due to - * target RW shortcomings. - */ - needed /* - * This section needs to be transferred to the - * target. - */ -}; - -/* This array describes all four sections of the new image. */ -static struct { - const char *name; - uint32_t offset; - uint32_t size; - enum upgrade_status ustatus; - struct signed_header_version shv; - uint32_t keyid; -} sections[] = { - {"RO_A", CONFIG_RO_MEM_OFF, CONFIG_RO_SIZE}, - {"RW_A", CONFIG_RW_MEM_OFF, CONFIG_RW_SIZE}, - {"RO_B", CHIP_RO_B_MEM_OFF, CONFIG_RO_SIZE}, - {"RW_B", CONFIG_RW_B_MEM_OFF, CONFIG_RW_SIZE} -}; - -/* - * Scan the new image and retrieve versions of all four sections, two RO and - * two RW. - */ -static void fetch_header_versions(const void *image) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(sections); i++) { - const struct SignedHeader *h; - - h = (const struct SignedHeader *)((uintptr_t)image + - sections[i].offset); - sections[i].shv.epoch = h->epoch_; - sections[i].shv.major = h->major_; - sections[i].shv.minor = h->minor_; - sections[i].keyid = h->keyid; - } -} - - -/* Compare to signer headers and determine which one is newer. */ -static int a_newer_than_b(struct signed_header_version *a, - struct signed_header_version *b) -{ - uint32_t fields[][3] = { - {a->epoch, a->major, a->minor}, - {b->epoch, b->major, b->minor}, - }; - size_t i; - - for (i = 0; i < ARRAY_SIZE(fields[0]); i++) { - uint32_t a_value; - uint32_t b_value; - - a_value = fields[0][i]; - b_value = fields[1][i]; - - /* - * Let's filter out images where the section is not - * initialized and the version field value is set to all ones. - */ - if (a_value == 0xffffffff) - a_value = 0; - - if (b_value == 0xffffffff) - b_value = 0; - - if (a_value != b_value) - return a_value > b_value; - } - - return 0; /* All else being equal A is no newer than B. */ -} -/* - * Pick sections to transfer based on information retrieved from the target, - * the new image, and the protocol version the target is running. - */ -static void pick_sections(struct transfer_descriptor *td) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(sections); i++) { - uint32_t offset = sections[i].offset; - - if ((offset == CONFIG_RW_MEM_OFF) || - (offset == CONFIG_RW_B_MEM_OFF)) { - - /* Skip currently active section. */ - if (offset != td->rw_offset) - continue; - /* - * Ok, this would be the RW section to transfer to the - * device. Is it newer in the new image than the - * running RW section on the device? - * - * If not in 'upstart' mode - transfer even if - * versions are the same, timestamps could be - * different. - */ - - if (a_newer_than_b(§ions[i].shv, &targ.shv[1]) || - !td->upstart_mode) - sections[i].ustatus = needed; - continue; - } - - /* Skip currently active section. */ - if (offset != td->ro_offset) - continue; - /* - * Ok, this would be the RO section to transfer to the device. - * Is it newer in the new image than the running RO section on - * the device? - */ - if (a_newer_than_b(§ions[i].shv, &targ.shv[0]) || - td->force_ro) - sections[i].ustatus = needed; - } -} - -static void setup_connection(struct transfer_descriptor *td) -{ - size_t rxed_size; - size_t i; - uint32_t error_code; - - /* - * Need to be backwards compatible, communicate with targets running - * different protocol versions. - */ - union { - struct first_response_pdu rpdu; - uint32_t legacy_resp; - } start_resp; - - /* Send start request. */ - printf("start\n"); - - if (td->ep_type == usb_xfer) { - struct update_pdu updu; - - memset(&updu, 0, sizeof(updu)); - updu.block_size = htobe32(sizeof(updu)); - do_xfer(&td->uep, &updu, sizeof(updu), &start_resp, - sizeof(start_resp), 1, &rxed_size); - } else { - rxed_size = sizeof(start_resp); - if (tpm_send_pkt(td, 0, 0, NULL, 0, - &start_resp, &rxed_size, - EXTENSION_FW_UPGRADE) < 0) { - fprintf(stderr, "Failed to start transfer\n"); - exit(update_error); - } - } - - /* We got something. Check for errors in response */ - if (rxed_size < 8) { - fprintf(stderr, "Unexpected response size %zd: ", rxed_size); - for (i = 0; i < rxed_size; i++) - fprintf(stderr, " %02x", ((uint8_t *)&start_resp)[i]); - fprintf(stderr, "\n"); - exit(update_error); - } - - protocol_version = be32toh(start_resp.rpdu.protocol_version); - if (protocol_version < 5) { - fprintf(stderr, "Unsupported protocol version %d\n", - protocol_version); - exit(update_error); - } - - printf("target running protocol version %d\n", protocol_version); - - error_code = be32toh(start_resp.rpdu.return_value); - - if (error_code) { - fprintf(stderr, "Target reporting error %d\n", error_code); - if (td->ep_type == usb_xfer) - shut_down(&td->uep); - exit(update_error); - } - - td->rw_offset = be32toh(start_resp.rpdu.backup_rw_offset); - td->ro_offset = be32toh(start_resp.rpdu.backup_ro_offset); - - /* Running header versions. */ - for (i = 0; i < ARRAY_SIZE(targ.shv); i++) { - targ.shv[i].minor = be32toh(start_resp.rpdu.shv[i].minor); - targ.shv[i].major = be32toh(start_resp.rpdu.shv[i].major); - targ.shv[i].epoch = be32toh(start_resp.rpdu.shv[i].epoch); - } - - for (i = 0; i < ARRAY_SIZE(targ.keyid); i++) - targ.keyid[i] = be32toh(start_resp.rpdu.keyid[i]); - - printf("keyids: RO 0x%08x, RW 0x%08x\n", targ.keyid[0], targ.keyid[1]); - printf("offsets: backup RO at %#x, backup RW at %#x\n", - td->ro_offset, td->rw_offset); - - pick_sections(td); -} - -/* - * Channel TPM extension/vendor command over USB. The payload of the USB frame - * in this case consists of the 2 byte subcommand code concatenated with the - * command body. The caller needs to indicate if a response is expected, and - * if it is - of what maximum size. - */ -static int ext_cmd_over_usb(struct usb_endpoint *uep, uint16_t subcommand, - const void *cmd_body, size_t body_size, - void *resp, size_t *resp_size) -{ - struct update_frame_header *ufh; - uint16_t *frame_ptr; - size_t usb_msg_size; - SHA_CTX ctx; - uint8_t digest[SHA_DIGEST_LENGTH]; - - usb_msg_size = sizeof(struct update_frame_header) + - sizeof(subcommand) + body_size; - - ufh = malloc(usb_msg_size); - if (!ufh) { - fprintf(stderr, "%s: failed to allocate %zd bytes\n", - __func__, usb_msg_size); - return -1; - } - - ufh->block_size = htobe32(usb_msg_size); - ufh->cmd.block_base = htobe32(CONFIG_EXTENSION_COMMAND); - frame_ptr = (uint16_t *)(ufh + 1); - *frame_ptr = htobe16(subcommand); - - if (body_size) - memcpy(frame_ptr + 1, cmd_body, body_size); - - /* Calculate the digest. */ - SHA1_Init(&ctx); - SHA1_Update(&ctx, &ufh->cmd.block_base, - usb_msg_size - - offsetof(struct update_frame_header, cmd.block_base)); - SHA1_Final(digest, &ctx); - memcpy(&ufh->cmd.block_digest, digest, sizeof(ufh->cmd.block_digest)); - - do_xfer(uep, ufh, usb_msg_size, resp, - resp_size ? *resp_size : 0, 1, resp_size); - - free(ufh); - return 0; -} - -/* - * Indicate to the target that update image transfer has been completed. Upon - * receiveing of this message the target state machine transitions into the - * 'rx_idle' state. The host may send an extension command to reset the target - * after this. - */ -static void send_done(struct usb_endpoint *uep) -{ - uint32_t out; - - /* Send stop request, ignoring reply. */ - out = htobe32(UPGRADE_DONE); - do_xfer(uep, &out, sizeof(out), &out, 1, 0, NULL); -} - -/* - * Old cr50 images fail the update if sections are sent out of order. They - * require each block to have an offset greater than the block that was sent - * before. RO has a lower offset than RW, so old cr50 images reject RO if it's - * sent right after RW. - * This offset restriction expires after 60 seconds. Delay the RO update long - * enough for cr50 to not care that it has a lower offset than RW. - * - * Make the delay 65 seconds instead of 60 to cover differences in the speed of - * H1's clock and the host clock. - */ -#define NEXT_SECTION_DELAY 65 - -/* Support for flashing RO immediately after RW was added in 0.3.20/0.4.20. */ -static int supports_reordered_section_updates(struct signed_header_version *rw) -{ - return (rw->epoch || rw->major > 4 || - (rw->major >= 3 && rw->minor >= 20)); -} - -/* Returns number of successfully transmitted image sections. */ -static int transfer_image(struct transfer_descriptor *td, - uint8_t *data, size_t data_len) -{ - size_t j; - int num_txed_sections = 0; - int needs_delay = !supports_reordered_section_updates(&targ.shv[1]); - - /* - * In case both RO and RW updates are required, make sure the RW - * section is updated before the RO. The array below keeps sections - * offsets in the required order. - */ - const size_t update_order[] = {CONFIG_RW_MEM_OFF, - CONFIG_RW_B_MEM_OFF, - CONFIG_RO_MEM_OFF, - CHIP_RO_B_MEM_OFF}; - - for (j = 0; j < ARRAY_SIZE(update_order); j++) { - size_t i; - - for (i = 0; i < ARRAY_SIZE(sections); i++) { - if (sections[i].offset != update_order[j]) - continue; - - if (sections[i].ustatus != needed) - break; - if (num_txed_sections && needs_delay) { - /* - * Delays more than 5 seconds cause the update - * to timeout. End the update before the delay - * and set it up after to recover from the - * timeout. - */ - if (td->ep_type == usb_xfer) - send_done(&td->uep); - printf("Waiting %ds for %s update.\n", - NEXT_SECTION_DELAY, sections[i].name); - sleep(NEXT_SECTION_DELAY); - setup_connection(td); - } - - transfer_section(td, - data + sections[i].offset, - sections[i].offset, - sections[i].size); - num_txed_sections++; - } - } - - if (!num_txed_sections) - printf("nothing to do\n"); - else - printf("-------\nupdate complete\n"); - return num_txed_sections; -} - -uint32_t send_vendor_command(struct transfer_descriptor *td, - uint16_t subcommand, - const void *command_body, - size_t command_body_size, - void *response, - size_t *response_size) -{ - int32_t rv; - - if (td->ep_type == usb_xfer) { - /* - * When communicating over USB the response is always supposed - * to have the result code in the first byte of the response, - * to be stripped from the actual response body by this - * function. - */ - uint8_t temp_response[MAX_BUF_SIZE]; - size_t max_response_size; - - if (!response_size) { - max_response_size = 1; - } else if (*response_size < (sizeof(temp_response))) { - max_response_size = *response_size + 1; - } else { - fprintf(stderr, - "Error: Expected response too large (%zd)\n", - *response_size); - /* Should happen only when debugging. */ - exit(update_error); - } - - ext_cmd_over_usb(&td->uep, subcommand, - command_body, command_body_size, - temp_response, &max_response_size); - if (!max_response_size) { - /* - * we must be talking to an older Cr50 firmware, which - * does not return the result code in the first byte - * on success, nothing to do. - */ - if (response_size) - *response_size = 0; - rv = 0; - } else { - rv = temp_response[0]; - if (response_size) { - *response_size = max_response_size - 1; - memcpy(response, - temp_response + 1, *response_size); - } - } - } else { - - rv = tpm_send_pkt(td, 0, 0, - command_body, command_body_size, - response, response_size, subcommand); - - if (rv == -1) { - fprintf(stderr, - "Error: Failed to send vendor command %d\n", - subcommand); - exit(update_error); - } - } - - return rv; /* This will be converted into uint32_t */ -} - -/* - * Corrupt the header of the inactive rw image to make sure the system can't - * rollback - */ -static void invalidate_inactive_rw(struct transfer_descriptor *td) -{ - /* Corrupt the rw image that is not running. */ - uint32_t rv; - - rv = send_vendor_command(td, VENDOR_CC_INVALIDATE_INACTIVE_RW, - NULL, 0, NULL, NULL); - if (!rv) { - printf("Inactive header invalidated\n"); - return; - } - - fprintf(stderr, "*%s: Error %#x\n", __func__, rv); - exit(update_error); -} - -static struct signed_header_version ver19 = { - .epoch = 0, - .major = 0, - .minor = 19, -}; - -static void generate_reset_request(struct transfer_descriptor *td) -{ - size_t response_size; - uint8_t response; - uint16_t subcommand; - uint8_t command_body[2]; /* Max command body size. */ - size_t command_body_size; - uint32_t background_update_supported; - const char *reset_type; - int rv; - - if (protocol_version < 6) { - if (td->ep_type == usb_xfer) { - /* - * Send a second stop request, which should reboot - * without replying. - */ - send_done(&td->uep); - } - /* Nothing we can do over /dev/tpm0 running versions below 6. */ - return; - } - - /* RW version 0.0.19 and above has support for background updates. */ - background_update_supported = td->background_update_supported || - !a_newer_than_b(&ver19, &targ.shv[1]); - - /* - * If this is an upstart request and there is support for background - * updates, don't post a request now. The target should handle it on - * the next reboot. - */ - if (td->upstart_mode && background_update_supported) - return; - - /* - * If the user explicitly wants it or a reset is needed because h1 - * does not support background updates, request post reset instead of - * immediate reset. In this case next time the target reboots, the h1 - * will reboot as well, and will consider running the uploaded code. - * - * In case target RW version is 19 or above, to reset the target the - * host is supposed to send the command to enable the uploaded image - * disabled by default. - * - * Otherwise the immediate reset command would suffice. - */ - /* Most common case. */ - command_body_size = 0; - response_size = 1; - if (td->post_reset || td->upstart_mode) { - subcommand = EXTENSION_POST_RESET; - reset_type = "posted"; - } else if (background_update_supported) { - subcommand = VENDOR_CC_TURN_UPDATE_ON; - command_body_size = sizeof(command_body); - command_body[0] = 0; - command_body[1] = 100; /* Reset in 100 ms. */ - reset_type = "requested"; - } else { - response_size = 0; - subcommand = VENDOR_CC_IMMEDIATE_RESET; - reset_type = "triggered"; - } - - rv = send_vendor_command(td, subcommand, command_body, - command_body_size, &response, &response_size); - - if (rv) { - fprintf(stderr, "*%s: Error %#x\n", __func__, rv); - exit(update_error); - } - printf("reboot %s\n", reset_type); -} - -/* - * Machine output is formatted as "key=value", one key-value pair per line, and - * parsed by other programs (e.g., debugd). The value part should be specified - * in the printf-like way. For example: - * - * print_machine_output("date", "%d/%d/%d", 2018, 1, 1), - * - * which outputs this line in console: - * - * date=2018/1/1 - * - * The key part should not contain '=' or newline. The value part may contain - * special characters like spaces, quotes, brackets, but not newlines. The - * newline character means end of value. - * - * Any output format change in this function may require similar changes on the - * programs that are using this gsctool. - */ -__attribute__((__format__(__printf__, 2, 3))) -static void print_machine_output(const char *key, const char *format, ...) -{ - va_list args; - - if (strchr(key, '=') != NULL || strchr(key, '\n') != NULL) { - fprintf(stderr, - "Error: key %s contains '=' or a newline character.\n", - key); - return; - } - - if (strchr(format, '\n') != NULL) { - fprintf(stderr, - "Error: value format %s contains a newline character. " - "\n", - format); - return; - } - - va_start(args, format); - - printf("%s=", key); - vprintf(format, args); - printf("\n"); - - va_end(args); -} - -/* - * Prints out the header, including FW versions and board IDs, of the given - * image. Output in a machine-friendly format if show_machine_output is true. - */ -static int show_headers_versions(const void *image, bool show_machine_output) -{ - /* - * There are 2 FW slots in an image, and each slot has 2 sections, RO - * and RW. The 2 slots should have identical FW versions and board - * IDs. - */ - const struct { - const char *name; - uint32_t offset; - } sections[] = { - /* Slot A. */ - {"RO", CONFIG_RO_MEM_OFF}, - {"RW", CONFIG_RW_MEM_OFF}, - /* Slot B. */ - {"RO", CHIP_RO_B_MEM_OFF}, - {"RW", CONFIG_RW_B_MEM_OFF} - }; - const size_t kNumSlots = 2; - const size_t kNumSectionsPerSlot = 2; - - /* - * String representation of FW version (<epoch>:<major>:<minor>), one - * string for each FW section. - */ - char ro_fw_ver[kNumSlots][MAX_FW_VER_LENGTH]; - char rw_fw_ver[kNumSlots][MAX_FW_VER_LENGTH]; - - uint32_t dev_id0_[kNumSlots]; - uint32_t dev_id1_[kNumSlots]; - uint32_t print_devid = 0; - - struct board_id { - uint32_t id; - uint32_t mask; - uint32_t flags; - } bid[kNumSlots]; - - char bid_string[kNumSlots][MAX_BOARD_ID_LENGTH]; - - size_t i; - - for (i = 0; i < ARRAY_SIZE(sections); i++) { - const struct SignedHeader *h = - (const struct SignedHeader *) - ((uintptr_t)image + sections[i].offset); - const size_t slot_idx = i / kNumSectionsPerSlot; - - uint32_t cur_bid; - size_t j; - - if (sections[i].name[1] == 'O') { - /* RO. */ - snprintf(ro_fw_ver[slot_idx], MAX_FW_VER_LENGTH, - "%d.%d.%d", h->epoch_, h->major_, h->minor_); - /* No need to read board ID in an RO section. */ - continue; - } else { - /* RW. */ - snprintf(rw_fw_ver[slot_idx], MAX_FW_VER_LENGTH, - "%d.%d.%d", h->epoch_, h->major_, h->minor_); - } - - /* - * For RW sections, retrieves the board ID fields' contents, - * which are stored XORed with a padding value. - */ - bid[slot_idx].id = h->board_id_type ^ SIGNED_HEADER_PADDING; - bid[slot_idx].mask = - h->board_id_type_mask ^ SIGNED_HEADER_PADDING; - bid[slot_idx].flags = h->board_id_flags ^ SIGNED_HEADER_PADDING; - - dev_id0_[slot_idx] = h->dev_id0_; - dev_id1_[slot_idx] = h->dev_id1_; - /* Print the devid if any slot has a non-zero devid. */ - print_devid |= h->dev_id0_ | h->dev_id1_; - - /* - * If board ID is a 4-uppercase-letter string (as it ought to - * be), print it as 4 letters, otherwise print it as an 8-digit - * hex. - */ - cur_bid = bid[slot_idx].id; - for (j = 0; j < sizeof(cur_bid); ++j) - if (!isupper(((const char *)&cur_bid)[j])) - break; - - if (j == sizeof(cur_bid)) { - cur_bid = be32toh(cur_bid); - snprintf(bid_string[slot_idx], MAX_BOARD_ID_LENGTH, - "%.4s", (const char *)&cur_bid); - } else { - snprintf(bid_string[slot_idx], MAX_BOARD_ID_LENGTH, - "%08x", cur_bid); - } - } - - if (show_machine_output) { - print_machine_output("IMAGE_RO_FW_VER", "%s", ro_fw_ver[0]); - print_machine_output("IMAGE_RW_FW_VER", "%s", rw_fw_ver[0]); - print_machine_output("IMAGE_BID_STRING", "%s", bid_string[0]); - print_machine_output("IMAGE_BID_MASK", "%08x", bid[0].mask); - print_machine_output("IMAGE_BID_FLAGS", "%08x", bid[0].flags); - } else { - printf("RO_A:%s RW_A:%s[%s:%08x:%08x] ", - ro_fw_ver[0], rw_fw_ver[0], - bid_string[0], bid[0].mask, bid[0].flags); - printf("RO_B:%s RW_B:%s[%s:%08x:%08x]\n", - ro_fw_ver[1], rw_fw_ver[1], - bid_string[1], bid[1].mask, bid[1].flags); - - if (print_devid) { - printf("DEVID: 0x%08x 0x%08x", dev_id0_[0], - dev_id1_[0]); - /* - * Only print the second devid if it's different. - * Separate the devids with tabs, so it's easier to - * read. - */ - if (dev_id0_[0] != dev_id0_[1] || - dev_id1_[0] != dev_id1_[1]) - printf("\t\t\t\tDEVID_B: 0x%08x 0x%08x", - dev_id0_[1], dev_id1_[1]); - printf("\n"); - } - } - - return 0; -} - -/* - * The default flag value will allow to run images built for any hardware - * generation of a particular board ID. - */ -#define DEFAULT_BOARD_ID_FLAG 0xff00 -static int parse_bid(const char *opt, - struct board_id *bid, - enum board_id_action *bid_action) -{ - char *e; - const char *param2; - size_t param1_length; - - if (!opt) { - *bid_action = bid_get; - return 1; - } - - /* Set it here to make bailing out easier later. */ - bid->flags = DEFAULT_BOARD_ID_FLAG; - - *bid_action = bid_set; /* Ignored by caller on errors. */ - - /* - * Pointer to the optional second component of the command line - * parameter, when present - separated by a colon. - */ - param2 = strchr(opt, ':'); - if (param2) { - param1_length = param2 - opt; - param2++; - if (!*param2) - return 0; /* Empty second parameter. */ - } else { - param1_length = strlen(opt); - } - - if (!param1_length) - return 0; /* Colon is the first character of the string? */ - - if (param1_length <= 4) { - unsigned i; - - /* Input must be a symbolic board name. */ - bid->type = 0; - for (i = 0; i < param1_length; i++) - bid->type = (bid->type << 8) | opt[i]; - } else { - bid->type = (uint32_t)strtoul(opt, &e, 0); - if ((param2 && (*e != ':')) || (!param2 && *e)) - return 0; - } - - if (param2) { - bid->flags = (uint32_t)strtoul(param2, &e, 0); - if (*e) - return 0; - } - - return 1; -} - -/* - * Reads a two-character hexadecimal byte from a string. If the string is - * ill-formed, returns 0. Otherwise, |byte| contains the byte value and the - * return value is non-zero. - */ -static int read_hex_byte(const char* s, uint8_t* byte) { - uint8_t b = 0; - for (const char* end = s + 2; s < end; ++s) { - if (*s >= '0' && *s <= '9') - b = b * 16 + *s - '0'; - else if (*s >= 'A' && *s <= 'F') - b = b * 16 + 10 + *s - 'A'; - else if (*s >= 'a' && *s <= 'f') - b = b * 16 + 10 + *s - 'a'; - else - return 0; - } - *byte = b; - return 1; -} - -static int parse_sn_bits(const char *opt, uint8_t *sn_bits) -{ - size_t len = strlen(opt); - - if (!strncmp(opt, "0x", 2)) { - opt += 2; - len -= 2; - } - if (len != SN_BITS_SIZE * 2) return 0; - - for (int i = 0; i < SN_BITS_SIZE; ++i, opt +=2) - if (!read_hex_byte(opt, sn_bits++)) return 0; - - return 1; -} - -static int parse_sn_inc_rma(const char *opt, uint8_t *arg) -{ - uint32_t inc; - char *e; - - inc = (uint32_t)strtoul(opt, &e, 0); - - if (opt == e || *e != '\0' || inc > 7) - return 0; - - *arg = inc; - return 1; -} - -static uint32_t common_process_password(struct transfer_descriptor *td, - enum ccd_vendor_subcommands subcmd) -{ - size_t response_size; - uint8_t response; - uint32_t rv; - char *password = NULL; - char *password_copy = NULL; - size_t copy_len = 0; - size_t len = 0; - struct termios oldattr, newattr; - - /* Suppress command line echo while password is being entered. */ - tcgetattr(STDIN_FILENO, &oldattr); - newattr = oldattr; - newattr.c_lflag &= ~ECHO; - newattr.c_lflag |= (ICANON | ECHONL); - tcsetattr(STDIN_FILENO, TCSANOW, &newattr); - - /* With command line echo suppressed request password entry twice. */ - printf("Enter password:"); - len = getline(&password, &len, stdin); - printf("Re-enter password:"); - getline(&password_copy, ©_len, stdin); - - /* Restore command line echo. */ - tcsetattr(STDIN_FILENO, TCSANOW, &oldattr); - - /* Empty password will still have the newline. */ - if ((len <= 1) || !password_copy) { - if (password) - free(password); - if (password_copy) - free(password_copy); - fprintf(stderr, "Error reading password\n"); - exit(update_error); - } - - /* Compare the two inputs. */ - if (strcmp(password, password_copy)) { - fprintf(stderr, "Entered passwords don't match\n"); - free(password); - free(password_copy); - exit(update_error); - } - - /* - * Ok, we have a password, let's move it in the buffer to overwrite - * the newline and free a byte to prepend the subcommand code. - */ - memmove(password + 1, password, len - 1); - password[0] = subcmd; - response_size = sizeof(response); - rv = send_vendor_command(td, VENDOR_CC_CCD, - password, len, - &response, &response_size); - free(password); - free(password_copy); - - if ((rv != VENDOR_RC_SUCCESS) && (rv != VENDOR_RC_IN_PROGRESS)) - fprintf(stderr, "Error sending password: rv %d, response %d\n", - rv, response_size ? response : 0); - - return rv; -} - -static void process_password(struct transfer_descriptor *td) -{ - if (common_process_password(td, CCDV_PASSWORD) == VENDOR_RC_SUCCESS) - return; - - exit(update_error); -} - -void poll_for_pp(struct transfer_descriptor *td, - uint16_t command, - uint8_t poll_type) -{ - uint8_t response; - uint8_t prev_response; - size_t response_size; - int rv; - - prev_response = ~0; /* Guaranteed invalid value. */ - - while (1) { - response_size = sizeof(response); - rv = send_vendor_command(td, command, - &poll_type, sizeof(poll_type), - &response, &response_size); - - if (((rv != VENDOR_RC_SUCCESS) && (rv != VENDOR_RC_IN_PROGRESS)) - || (response_size != 1)) { - fprintf(stderr, "Error: rv %d, response %d\n", - rv, response_size ? response : 0); - exit(update_error); - } - - if (response == CCD_PP_DONE) { - printf("PP Done!\n"); - return; - } - - if (response == CCD_PP_CLOSED) { - fprintf(stderr, - "Error: Physical presence check timeout!\n"); - exit(update_error); - } - - - if (response == CCD_PP_AWAITING_PRESS) { - printf("Press PP button now!\n"); - } else if (response == CCD_PP_BETWEEN_PRESSES) { - if (prev_response != response) - printf("Another press will be required!\n"); - } else { - fprintf(stderr, "Error: unknown poll result %d\n", - response); - exit(update_error); - } - prev_response = response; - - usleep(500 * 1000); /* Poll every half a second. */ - } - -} - -static void print_ccd_info(void *response, size_t response_size) -{ - struct ccd_info_response ccd_info; - size_t i; - const struct ccd_capability_info cap_info[] = CAP_INFO_DATA; - const char *state_names[] = CCD_STATE_NAMES; - const char *cap_state_names[] = CCD_CAP_STATE_NAMES; - uint32_t caps_bitmap = 0; - - if (response_size != sizeof(ccd_info)) { - fprintf(stderr, "Unexpected CCD info response size %zd\n", - response_size); - exit(update_error); - } - - memcpy(&ccd_info, response, sizeof(ccd_info)); - - /* Convert it back to host endian format. */ - ccd_info.ccd_flags = be32toh(ccd_info.ccd_flags); - for (i = 0; i < ARRAY_SIZE(ccd_info.ccd_caps_current); i++) { - ccd_info.ccd_caps_current[i] = - be32toh(ccd_info.ccd_caps_current[i]); - ccd_info.ccd_caps_defaults[i] = - be32toh(ccd_info.ccd_caps_defaults[i]); - } - - /* Now report CCD state on the console. */ - printf("State: %s\n", ccd_info.ccd_state > ARRAY_SIZE(state_names) ? - "Error" : state_names[ccd_info.ccd_state]); - printf("Password: %s\n", (ccd_info.ccd_indicator_bitmap & - CCD_INDICATOR_BIT_HAS_PASSWORD) ? "Set" : "None"); - printf("Flags: %#06x\n", ccd_info.ccd_flags); - printf("Capabilities, current and default:\n"); - for (i = 0; i < CCD_CAP_COUNT; i++) { - int is_enabled; - int index; - int shift; - int cap_current; - int cap_default; - - index = i / (32 / CCD_CAP_BITS); - shift = (i % (32 / CCD_CAP_BITS)) * CCD_CAP_BITS; - - cap_current = (ccd_info.ccd_caps_current[index] >> shift) - & CCD_CAP_BITMASK; - cap_default = (ccd_info.ccd_caps_defaults[index] >> shift) - & CCD_CAP_BITMASK; - - if (ccd_info.ccd_force_disabled) { - is_enabled = 0; - } else { - switch (cap_current) { - case CCD_CAP_STATE_ALWAYS: - is_enabled = 1; - break; - case CCD_CAP_STATE_UNLESS_LOCKED: - is_enabled = (ccd_info.ccd_state != - CCD_STATE_LOCKED); - break; - default: - is_enabled = (ccd_info.ccd_state == - CCD_STATE_OPENED); - break; - } - } - - printf(" %-15s %c %s", - cap_info[i].name, - is_enabled ? 'Y' : '-', - cap_state_names[cap_current]); - - if (cap_current != cap_default) - printf(" (%s)", cap_state_names[cap_default]); - - printf("\n"); - - if (is_enabled) - caps_bitmap |= (1 << i); - } - printf("CCD caps bitmap: %#x\n", caps_bitmap); - printf("Capabilities are %s.\n", (ccd_info.ccd_indicator_bitmap & - CCD_INDICATOR_BIT_ALL_CAPS_DEFAULT) ? "default" : "modified"); -} - -static void process_ccd_state(struct transfer_descriptor *td, int ccd_unlock, - int ccd_open, int ccd_lock, int ccd_info) -{ - uint8_t payload; - /* Max possible response size is when ccd_info is requested. */ - uint8_t response[sizeof(struct ccd_info_response)]; - size_t response_size; - int rv; - - if (ccd_unlock) - payload = CCDV_UNLOCK; - else if (ccd_open) - payload = CCDV_OPEN; - else if (ccd_lock) - payload = CCDV_LOCK; - else - payload = CCDV_GET_INFO; - - response_size = sizeof(response); - rv = send_vendor_command(td, VENDOR_CC_CCD, - &payload, sizeof(payload), - &response, &response_size); - - /* - * If password is required - try sending the same subcommand - * accompanied by user password. - */ - if (rv == VENDOR_RC_PASSWORD_REQUIRED) - rv = common_process_password(td, payload); - - if (rv == VENDOR_RC_SUCCESS) { - if (ccd_info) - print_ccd_info(response, response_size); - return; - } - - if (rv != VENDOR_RC_IN_PROGRESS) { - fprintf(stderr, "Error: rv %d, response %d\n", - rv, response_size ? response[0] : 0); - exit(update_error); - } - - /* - * Physical presence process started, poll for the state the user - * asked for. Only two subcommands would return 'IN_PROGRESS'. - */ - if (ccd_unlock) - poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_UNLOCK); - else - poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_OPEN); -} - -static void process_wp(struct transfer_descriptor *td) -{ - size_t response_size; - uint8_t response; - int rv = 0; - - response_size = sizeof(response); - - printf("Getting WP\n"); - - rv = send_vendor_command(td, VENDOR_CC_WP, NULL, 0, - &response, &response_size); - if (rv != VENDOR_RC_SUCCESS) { - fprintf(stderr, "Error %d getting write protect\n", rv); - exit(update_error); - } - if (response_size != sizeof(response)) { - fprintf(stderr, "Unexpected response size %zd while getting " - "write protect\n", - response_size); - exit(update_error); - } - - printf("WP: %08x\n", response); - printf("Flash WP: %s%s\n", - response & WPV_FORCE ? "forced " : "", - response & WPV_ENABLE ? "enabled" : "disabled"); - printf(" at boot: %s\n", - !(response & WPV_ATBOOT_SET) ? "follow_batt_pres" : - response & WPV_ATBOOT_ENABLE ? "forced enabled" : - "forced disabled"); -} - - -void process_bid(struct transfer_descriptor *td, - enum board_id_action bid_action, - struct board_id *bid, - bool show_machine_output) -{ - size_t response_size; - - if (bid_action == bid_get) { - - response_size = sizeof(*bid); - send_vendor_command(td, VENDOR_CC_GET_BOARD_ID, - bid, sizeof(*bid), - bid, &response_size); - - if (response_size != sizeof(*bid)) { - fprintf(stderr, - "Error reading board ID: response size %zd, " - "first byte %#02x\n", - response_size, - response_size ? *(uint8_t *)&bid : -1); - exit(update_error); - } - - if (show_machine_output) { - print_machine_output( - "BID_TYPE", "%08x", be32toh(bid->type)); - print_machine_output( - "BID_TYPE_INV", "%08x", be32toh(bid->type_inv)); - print_machine_output( - "BID_FLAGS", "%08x", be32toh(bid->flags)); - - for (int i = 0; i < 4; i++) { - if (!isupper(((const char *)bid)[i])) { - print_machine_output( - "BID_RLZ", "%s", "????"); - return; - } - } - - print_machine_output( - "BID_RLZ", "%c%c%c%c", - ((const char *)bid)[0], - ((const char *)bid)[1], - ((const char *)bid)[2], - ((const char *)bid)[3]); - } else { - printf("Board ID space: %08x:%08x:%08x\n", - be32toh(bid->type), - be32toh(bid->type_inv), - be32toh(bid->flags)); - - } - - return; - } - - if (bid_action == bid_set) { - /* Sending just two fields: type and flags. */ - uint32_t command_body[2]; - uint8_t response; - - command_body[0] = htobe32(bid->type); - command_body[1] = htobe32(bid->flags); - - response_size = sizeof(command_body); - send_vendor_command(td, VENDOR_CC_SET_BOARD_ID, - command_body, sizeof(command_body), - command_body, &response_size); - - /* - * Speculative assignment: the response is expected to be one - * byte in size and be placed in the first byte of the buffer. - */ - response = *((uint8_t *)command_body); - - if (response_size == 1) { - if (!response) - return; /* Success! */ - - fprintf(stderr, "Error %d while setting board id\n", - response); - } else { - fprintf(stderr, "Unexpected response size %zd" - " while setting board id\n", - response_size); - } - exit(update_error); - } -} - -static void process_sn_bits(struct transfer_descriptor *td, - uint8_t *sn_bits) -{ - int rv; - uint8_t response_code; - size_t response_size = sizeof(response_code); - - rv = send_vendor_command(td, VENDOR_CC_SN_SET_HASH, - sn_bits, SN_BITS_SIZE, - &response_code, &response_size); - - if (rv) { - fprintf(stderr, "Error %d while sending vendor command\n", rv); - exit(update_error); - } - - if (response_size != 1) { - fprintf(stderr, - "Unexpected response size while setting sn bits\n"); - exit(update_error); - } - - if (response_code != 0) { - fprintf(stderr, "Error %d while setting sn bits\n", - response_code); - exit(update_error); - } -} - -static void process_sn_inc_rma(struct transfer_descriptor *td, - uint8_t arg) -{ - int rv; - uint8_t response_code; - size_t response_size = sizeof(response_code); - - rv = send_vendor_command(td, VENDOR_CC_SN_INC_RMA, - &arg, sizeof(arg), - &response_code, &response_size); - if (rv) { - fprintf(stderr, "Error %d while sending vendor command\n", rv); - exit(update_error); - } - - if (response_size != 1) { - fprintf(stderr, - "Unexpected response size while " - "incrementing sn rma count\n"); - exit(update_error); - } - - if (response_code != 0) { - fprintf(stderr, "Error %d while incrementing rma count\n", - response_code); - exit(update_error); - } -} - -/* Get/Set the primary seed of the info1 manufacture state. */ -static int process_endorsement_seed(struct transfer_descriptor *td, - const char *endorsement_seed_str) -{ - uint8_t endorsement_seed[32]; - uint8_t response_seed[32]; - size_t seed_size = sizeof(endorsement_seed); - size_t response_size = sizeof(response_seed); - size_t i; - int rv; - - if (!endorsement_seed_str) { - rv = send_vendor_command(td, VENDOR_CC_ENDORSEMENT_SEED, NULL, - 0, response_seed, &response_size); - if (rv) { - fprintf(stderr, "Error sending vendor command %d\n", - rv); - return update_error; - } - printf("Endorsement key seed: "); - for (i = 0; i < response_size; i++) - printf("%02x", response_seed[i]); - printf("\n"); - return 0; - } - if (seed_size * 2 != strlen(endorsement_seed_str)) { - printf("Invalid seed %s\n", endorsement_seed_str); - return update_error; - } - - for (i = 0; i < seed_size; i++) { - int nibble; - char c; - - c = endorsement_seed_str[2 * i]; - nibble = from_hexascii(c); - if (nibble < 0) { - fprintf(stderr, "Error: Non hex character in seed %c\n", - c); - return update_error; - } - endorsement_seed[i] = nibble << 4; - - c = endorsement_seed_str[2 * i + 1]; - nibble = from_hexascii(c); - if (nibble < 0) { - fprintf(stderr, "Error: Non hex character in seed %c\n", - c); - return update_error; - } - endorsement_seed[i] |= nibble; - } - - printf("Setting seed: %s\n", endorsement_seed_str); - rv = send_vendor_command(td, VENDOR_CC_ENDORSEMENT_SEED, - endorsement_seed, seed_size, - response_seed, &response_size); - if (rv == VENDOR_RC_NOT_ALLOWED) { - fprintf(stderr, "Seed already set\n"); - return update_error; - } - if (rv) { - fprintf(stderr, "Error sending vendor command %d\n", rv); - return update_error; - } - printf("Updated endorsement key seed.\n"); - return 0; -} - -/* - * Retrieve the RMA authentication challenge from the Cr50, print out the - * challenge on the console, then prompt the user for the authentication code, - * and send the code back to Cr50. The Cr50 would report if the code matched - * its expectations or not. - */ -static void process_rma(struct transfer_descriptor *td, const char *authcode) -{ - char rma_response[81]; - size_t response_size = sizeof(rma_response); - size_t i; - size_t auth_size = 0; - - if (!authcode) { - send_vendor_command(td, VENDOR_CC_RMA_CHALLENGE_RESPONSE, - NULL, 0, rma_response, &response_size); - - if (response_size == 1) { - fprintf(stderr, "error %d\n", rma_response[0]); - if (td->ep_type == usb_xfer) - shut_down(&td->uep); - exit(update_error); - } - - printf("Challenge:"); - for (i = 0; i < response_size; i++) { - if (!(i % 5)) { - if (!(i % 40)) - printf("\n"); - printf(" "); - } - printf("%c", rma_response[i]); - } - printf("\n"); - return; - } - - if (!*authcode) { - printf("Empty response.\n"); - exit(update_error); - return; - } - - if (!strcmp(authcode, "disable")) { - printf("Invalid arg. Try using 'gsctool -F disable'\n"); - exit(update_error); - return; - } - - printf("Processing response...\n"); - auth_size = strlen(authcode); - response_size = sizeof(rma_response); - - send_vendor_command(td, VENDOR_CC_RMA_CHALLENGE_RESPONSE, - authcode, auth_size, - rma_response, &response_size); - - if (response_size == 1) { - fprintf(stderr, "\nrma unlock failed, code %d ", - *rma_response); - switch (*rma_response) { - case VENDOR_RC_BOGUS_ARGS: - fprintf(stderr, "(wrong authcode size)\n"); - break; - case VENDOR_RC_INTERNAL_ERROR: - fprintf(stderr, "(authcode mismatch)\n"); - break; - default: - fprintf(stderr, "(unknown error)\n"); - break; - } - if (td->ep_type == usb_xfer) - shut_down(&td->uep); - exit(update_error); - } - printf("RMA unlock succeeded.\n"); -} - -/* - * Enable or disable factory mode. Factory mode will only be enabled if HW - * write protect is removed. - */ -static void process_factory_mode(struct transfer_descriptor *td, - const char *arg) -{ - uint8_t rma_response; - size_t response_size = sizeof(rma_response); - char *cmd_str; - int rv; - uint16_t subcommand; - - if (!strcasecmp(arg, "disable")) { - subcommand = VENDOR_CC_DISABLE_FACTORY; - cmd_str = "dis"; - } else if (!strcasecmp(arg, "enable")) { - subcommand = VENDOR_CC_RESET_FACTORY; - cmd_str = "en"; - - } else { - fprintf(stderr, "Invalid factory mode arg %s", arg); - exit(update_error); - } - - printf("%sabling factory mode\n", cmd_str); - rv = send_vendor_command(td, subcommand, NULL, 0, &rma_response, - &response_size); - if (rv) { - fprintf(stderr, "Failed %sabling factory mode\nvc error " - "%d\n", cmd_str, rv); - if (response_size == 1) - fprintf(stderr, "ec error %d\n", rma_response); - exit(update_error); - } - printf("Factory %sable succeeded.\n", cmd_str); -} - -static void report_version(void) -{ - /* Get version from the generated file, ignore the underscore prefix. */ - const char *v = strchr(VERSION, '_'); - - printf("Version: %s, built on %s by %s\n", v ? v + 1 : "?", - DATE, BUILDER); - exit(0); -} - -/* - * Either change or query TPM mode value. - */ -static int process_tpm_mode(struct transfer_descriptor *td, - const char *arg) -{ - int rv; - size_t command_size; - size_t response_size; - uint8_t response; - uint8_t command_body; - - response_size = sizeof(response); - if (!arg) { - command_size = 0; - } else if (!strcasecmp(arg, "disable")) { - command_size = sizeof(command_body); - command_body = (uint8_t) TPM_MODE_DISABLED; - } else if (!strcasecmp(arg, "enable")) { - command_size = sizeof(command_body); - command_body = (uint8_t) TPM_MODE_ENABLED; - } else { - fprintf(stderr, "Invalid tpm mode arg: %s.\n", arg); - return update_error; - } - - rv = send_vendor_command(td, VENDOR_CC_TPM_MODE, - &command_body, command_size, - &response, &response_size); - if (rv) { - fprintf(stderr, "Error %d in setting TPM mode.\n", rv); - return update_error; - } - if (response_size != sizeof(response)) { - fprintf(stderr, "Error in the size of response," - " %zu.\n", response_size); - return update_error; - } - if (response >= TPM_MODE_MAX) { - fprintf(stderr, "Error in the value of response," - " %d.\n", response); - return update_error; - } - - printf("TPM Mode: %s (%d)\n", (response == TPM_MODE_DISABLED) ? - "disabled" : "enabled", response); - - return rv; -} - -/* - * Retrieve from H1 flash log entries which are newer than the passed in - * timestamp. - * - * On error retry a few times just in case flash log is locked by a concurrent - * access. - */ -static int process_get_flog(struct transfer_descriptor *td, uint32_t prev_stamp) -{ - int rv; - const int max_retries = 3; - int retries = max_retries; - - while (retries--) { - union entry_u entry; - size_t resp_size; - size_t i; - - resp_size = sizeof(entry); - rv = send_vendor_command(td, VENDOR_CC_POP_LOG_ENTRY, - &prev_stamp, sizeof(prev_stamp), - &entry, &resp_size); - - if (rv) { - /* - * Flash log could be momentarily locked by a - * concurrent access, let it settle and try again, 10 - * ms should be enough. - */ - usleep(10 * 1000); - continue; - } - - if (resp_size == 0) - /* No more entries. */ - return 0; - - memcpy(&prev_stamp, &entry.r.timestamp, sizeof(prev_stamp)); - printf("%10u:%02x", prev_stamp, entry.r.type); - for (i = 0; i < FLASH_LOG_PAYLOAD_SIZE(entry.r.size); i++) - printf(" %02x", entry.r.payload[i]); - printf("\n"); - retries = max_retries; - } - - fprintf(stderr, "%s: error %d\n", __func__, rv); - - return rv; -} - -static int process_tstamp(struct transfer_descriptor *td, - const char *tstamp_ascii) -{ - char *e; - size_t expected_response_size; - size_t message_size; - size_t response_size; - uint32_t rv; - uint32_t tstamp = 0; - uint8_t max_response[sizeof(uint32_t)]; - - if (tstamp_ascii) { - tstamp = strtoul(tstamp_ascii, &e, 10); - if (*e) { - fprintf(stderr, "invalid base timestamp value \"%s\"\n", - tstamp_ascii); - return -1; - } - tstamp = htobe32(tstamp); - expected_response_size = 0; - message_size = sizeof(tstamp); - } else { - expected_response_size = 4; - message_size = 0; - } - - response_size = sizeof(max_response); - rv = send_vendor_command(td, VENDOR_CC_FLOG_TIMESTAMP, &tstamp, - message_size, max_response, &response_size); - - if (rv) { - fprintf(stderr, "error: return value %d\n", rv); - return rv; - } - if (response_size != expected_response_size) { - fprintf(stderr, "error: got %zd bytes, expected %zd\n", - response_size, expected_response_size); - return -1; /* Should never happen. */ - } - - if (response_size) { - memcpy(&tstamp, max_response, sizeof(tstamp)); - printf("Current H1 time is %d\n", be32toh(tstamp)); - } - return 0; -} - -/* - * Search the passed in zero terminated array of options_map structures for - * option 'option'. - * - * If found - set the corresponding integer to 1 and return 1. If not found - - * return 0. - */ -static int check_boolean(const struct options_map *omap, char option) -{ - do { - if (omap->opt != option) - continue; - - *omap->flag = 1; - return 1; - } while ((++omap)->opt); - - return 0; -} - -/* - * Set the long_opts table and short_opts string. - * - * This function allows to avoid maintaining two command line option - * descriptions, for short and long forms. - * - * The long_opts table is built based on the cmd_line_options table contents, - * and the short form is built based on the long_opts table contents. - * - * The 'required_argument' short options are followed by ':'. - * - * The passed in long_opts array and short_opts string are guaranteed to - * accommodate all necessary objects/characters. - */ -static void set_opt_descriptors(struct option *long_opts, char *short_opts) -{ - size_t i; - int j; - - for (i = j = 0; i < ARRAY_SIZE(cmd_line_options); i++) { - long_opts[i] = cmd_line_options[i].opt; - short_opts[j++] = long_opts[i].val; - if (long_opts[i].has_arg == required_argument) - short_opts[j++] = ':'; - } -} - -/* - * Find the long_opts table index where .val field is set to the passed in - * short option value. - */ -static int get_longindex(int short_opt, const struct option *long_opts) -{ - int i; - - for (i = 0; long_opts[i].name; i++) - if (long_opts[i].val == short_opt) - return i; - - /* - * We could never come here as the short options list is compiled - * based on long options table. - */ - fprintf(stderr, "could not find long opt table index for %d\n", - short_opt); - exit(1); - - return -1; /* Not reached. */ -} - -/* - * Combine searching for command line parameters and optional arguments. - * - * The canonical short options description string does not allow to specify - * that a command line argument expects an optional parameter. but gsctool - * users expect to be able to use the following styles for optional - * parameters: - * - * a) -x <param value> - * b) --x_long <param_value> - * c) --x_long=<param_value> - * - * Styles a) and b) are not supported standard getopt_long(), this function - * adds ability to handle cases a) and b). - */ -static int getopt_all(int argc, char *argv[]) -{ - int longindex = -1; - static char short_opts[2 * ARRAY_SIZE(cmd_line_options)] = {}; - static struct option long_opts[ARRAY_SIZE(cmd_line_options) + 1] = {}; - int i; - - if (!short_opts[0]) - set_opt_descriptors(long_opts, short_opts); - - i = getopt_long(argc, argv, short_opts, long_opts, &longindex); - if (i != -1) { - - if (longindex < 0) { - /* - * longindex is not set, this must have been the short - * option case, Find the long_opts table index based - * on the short option value. - */ - longindex = get_longindex(i, long_opts); - } - - if (long_opts[longindex].has_arg == optional_argument) { - /* - * This command line option may include an argument, - * let's check if it is there as the next token in the - * command line. - */ - if (!optarg && argv[optind] && argv[optind][0] != '-') - /* Yes, it is. */ - optarg = argv[optind++]; - } - } - - return i; -} - -int main(int argc, char *argv[]) -{ - struct transfer_descriptor td; - int errorcnt; - uint8_t *data = 0; - size_t data_len = 0; - uint16_t vid = 0; - uint16_t pid = 0; - int i; - size_t j; - int transferred_sections = 0; - int binary_vers = 0; - int show_fw_ver = 0; - int rma = 0; - const char *rma_auth_code; - int get_endorsement_seed = 0; - const char *endorsement_seed_str; - int corrupt_inactive_rw = 0; - struct board_id bid; - enum board_id_action bid_action; - int password = 0; - int ccd_open = 0; - int ccd_unlock = 0; - int ccd_lock = 0; - int ccd_info = 0; - int get_flog = 0; - uint32_t prev_log_entry = 0; - int wp = 0; - int try_all_transfer = 0; - int tpm_mode = 0; - bool show_machine_output = false; - int tstamp = 0; - const char *tstamp_arg = NULL; - - const char *exclusive_opt_error = - "Options -a, -s and -t are mutually exclusive\n"; - const char *openbox_desc_file = NULL; - int factory_mode = 0; - char *factory_mode_arg; - char *tpm_mode_arg = NULL; - char *serial = NULL; - int sn_bits = 0; - uint8_t sn_bits_arg[SN_BITS_SIZE]; - int sn_inc_rma = 0; - uint8_t sn_inc_rma_arg; - - /* - * All options which result in setting a Boolean flag to True, along - * with addresses of the flags. Terminated by a zeroed entry. - */ - const struct options_map omap[] = { - { 'B', &td.background_update_supported}, - { 'b', &binary_vers }, - { 'c', &corrupt_inactive_rw }, - { 'f', &show_fw_ver }, - { 'I', &ccd_info }, - { 'k', &ccd_lock }, - { 'o', &ccd_open }, - { 'P', &password }, - { 'p', &td.post_reset }, - { 'U', &ccd_unlock }, - { 'u', &td.upstart_mode }, - { 'V', &verbose_mode }, - { 'w', &wp }, - {}, - }; - - /* - * Explicitly sets buffering type to line buffered so that output - * lines can be written to pipe instantly. This is needed when the - * cr50-verify-ro.sh execution in verify_ro is moved from crosh to - * debugd. - */ - setlinebuf(stdout); - - progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - /* Usb transfer - default mode. */ - memset(&td, 0, sizeof(td)); - td.ep_type = usb_xfer; - - bid_action = bid_none; - errorcnt = 0; - opterr = 0; /* quiet, you */ - - while ((i = getopt_all(argc, argv)) != -1) { - if (check_boolean(omap, i)) - continue; - switch (i) { - case 'a': - if (td.ep_type) { - errorcnt++; - fprintf(stderr, "%s", exclusive_opt_error); - break; - } - try_all_transfer = 1; - /* Try dev_xfer first. */ - td.ep_type = dev_xfer; - break; - case 'd': - if (!parse_vidpid(optarg, &vid, &pid)) { - fprintf(stderr, - "Invalid device argument: \"%s\"\n", - optarg); - errorcnt++; - } - break; - case 'e': - get_endorsement_seed = 1; - endorsement_seed_str = optarg; - break; - case 'F': - factory_mode = 1; - factory_mode_arg = optarg; - break; - case 'h': - usage(errorcnt); - break; - case 'i': - if (!parse_bid(optarg, &bid, &bid_action)) { - fprintf(stderr, - "Invalid board id argument: \"%s\"\n", - optarg); - errorcnt++; - } - break; - case 'L': - get_flog = 1; - if (optarg) - prev_log_entry = strtoul(optarg, NULL, 0); - break; - case 'M': - show_machine_output = true; - break; - case 'm': - tpm_mode = 1; - tpm_mode_arg = optarg; - break; - case 'n': - serial = optarg; - break; - case 'O': - openbox_desc_file = optarg; - break; - case 'q': - td.force_ro = 1; - break; - case 'r': - rma = 1; - rma_auth_code = optarg; - break; - case 'R': - sn_inc_rma = 1; - if (!parse_sn_inc_rma(optarg, &sn_inc_rma_arg)) { - fprintf(stderr, - "Invalid sn_rma_inc argument: \"%s\"\n", - optarg); - errorcnt++; - } - - break; - case 's': - if (td.ep_type || try_all_transfer) { - errorcnt++; - fprintf(stderr, "%s", exclusive_opt_error); - break; - } - td.ep_type = dev_xfer; - break; - case 'S': - sn_bits = 1; - if (!parse_sn_bits(optarg, sn_bits_arg)) { - fprintf(stderr, - "Invalid sn_bits argument: \"%s\"\n", - optarg); - errorcnt++; - } - - break; - case 't': - if (td.ep_type || try_all_transfer) { - errorcnt++; - fprintf(stderr, "%s", exclusive_opt_error); - break; - } - td.ep_type = ts_xfer; - break; - case 'T': - tstamp = 1; - tstamp_arg = optarg; - break; - case 'v': - report_version(); /* This will call exit(). */ - break; - case 0: /* auto-handled option */ - break; - case '?': - if (optopt) - fprintf(stderr, "Unrecognized option: -%c\n", - optopt); - else - fprintf(stderr, "Unrecognized option: %s\n", - argv[optind - 1]); - errorcnt++; - break; - case ':': - fprintf(stderr, "Missing argument to %s\n", - argv[optind - 1]); - errorcnt++; - break; - default: - fprintf(stderr, "Internal error at %s:%d\n", - __FILE__, __LINE__); - exit(update_error); - } - } - - if (errorcnt) - usage(errorcnt); - - /* - * If no usb device information was given, default to the using cr50 - * vendor and product id to find the usb device. - */ - if (!serial && !vid && !pid) { - vid = VID; - pid = PID; - } - - if ((bid_action == bid_none) && - !ccd_info && - !ccd_lock && - !ccd_open && - !ccd_unlock && - !corrupt_inactive_rw && - !get_flog && - !get_endorsement_seed && - !factory_mode && - !password && - !rma && - !show_fw_ver && - !sn_bits && - !sn_inc_rma && - !openbox_desc_file && - !tstamp && - !tpm_mode && - !wp) { - if (optind >= argc) { - fprintf(stderr, - "\nERROR: Missing required <binary image>\n\n"); - usage(1); - } - - data = get_file_or_die(argv[optind], &data_len); - printf("read %zd(%#zx) bytes from %s\n", - data_len, data_len, argv[optind]); - if (data_len != CONFIG_FLASH_SIZE) { - fprintf(stderr, "Image file is not %d bytes\n", - CONFIG_FLASH_SIZE); - exit(update_error); - } - - fetch_header_versions(data); - - if (binary_vers) - exit(show_headers_versions(data, show_machine_output)); - } else { - if (optind < argc) - printf("Ignoring binary image %s\n", argv[optind]); - } - - - if (((bid_action != bid_none) + !!rma + !!password + !!ccd_open + - !!ccd_unlock + !!ccd_lock + !!ccd_info + !!get_flog + - !!openbox_desc_file + !!factory_mode + !!wp + - !!get_endorsement_seed) > 1) { - fprintf(stderr, - "ERROR: options" - "-e, -F, -I, -i, -k, -L, -O, -o, -P, -r, -U and -w " - "are mutually exclusive\n"); - exit(update_error); - } - - if (td.ep_type == usb_xfer) { - if (usb_findit(serial, vid, pid, USB_SUBCLASS_GOOGLE_CR50, - USB_PROTOCOL_GOOGLE_CR50_NON_HC_FW_UPDATE, - &td.uep)) - exit(update_error); - } else if (td.ep_type == dev_xfer) { - td.tpm_fd = open("/dev/tpm0", O_RDWR); - if (td.tpm_fd < 0) { - if (!try_all_transfer) { - perror("Could not open TPM"); - exit(update_error); - } - td.ep_type = ts_xfer; - } - } - - if (openbox_desc_file) - return verify_ro(&td, openbox_desc_file, show_machine_output); - - if (ccd_unlock || ccd_open || ccd_lock || ccd_info) - process_ccd_state(&td, ccd_unlock, ccd_open, - ccd_lock, ccd_info); - - if (password) - process_password(&td); - - if (bid_action != bid_none) - process_bid(&td, bid_action, &bid, show_machine_output); - - if (get_endorsement_seed) - exit(process_endorsement_seed(&td, endorsement_seed_str)); - - if (rma) - process_rma(&td, rma_auth_code); - - if (factory_mode) - process_factory_mode(&td, factory_mode_arg); - if (wp) - process_wp(&td); - - if (corrupt_inactive_rw) - invalidate_inactive_rw(&td); - - if (tpm_mode) { - int rv = process_tpm_mode(&td, tpm_mode_arg); - - exit(rv); - } - - if (tstamp) - return process_tstamp(&td, tstamp_arg); - - if (sn_bits) - process_sn_bits(&td, sn_bits_arg); - - if (sn_inc_rma) - process_sn_inc_rma(&td, sn_inc_rma_arg); - - if (get_flog) - process_get_flog(&td, prev_log_entry); - - if (data || show_fw_ver) { - - setup_connection(&td); - - if (data) { - transferred_sections = transfer_image(&td, - data, data_len); - free(data); - } - - /* - * Move USB updater sate machine to idle state so that vendor - * commands can be processed later, if any. - */ - if (td.ep_type == usb_xfer) - send_done(&td.uep); - - if (transferred_sections) - generate_reset_request(&td); - - if (show_fw_ver) { - if (show_machine_output) { - print_machine_output("RO_FW_VER", "%d.%d.%d", - targ.shv[0].epoch, - targ.shv[0].major, - targ.shv[0].minor); - print_machine_output("RW_FW_VER", "%d.%d.%d", - targ.shv[1].epoch, - targ.shv[1].major, - targ.shv[1].minor); - } else { - printf("Current versions:\n"); - printf("RO %d.%d.%d\n", targ.shv[0].epoch, - targ.shv[0].major, targ.shv[0].minor); - printf("RW %d.%d.%d\n", targ.shv[1].epoch, - targ.shv[1].major, targ.shv[1].minor); - } - } - } - - if (td.ep_type == usb_xfer) { - libusb_close(td.uep.devh); - libusb_exit(NULL); - } - - if (!transferred_sections) - return noop; - /* - * We should indicate if RO update was not done because of the - * insufficient RW version. - */ - for (j = 0; j < ARRAY_SIZE(sections); j++) - if (sections[j].ustatus == not_possible) { - /* This will allow scripting repeat attempts. */ - printf("Failed to update RO, run the command again\n"); - return rw_updated; - } - - printf("image updated\n"); - return all_updated; -} diff --git a/extra/usb_updater/gsctool.h b/extra/usb_updater/gsctool.h deleted file mode 100644 index 0be6faeb1c..0000000000 --- a/extra/usb_updater/gsctool.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#ifndef __EXTRA_USB_UPDATER_GSCTOOL_H -#define __EXTRA_USB_UPDATER_GSCTOOL_H - -#include <stdbool.h> -#include <stdint.h> -#include <sys/types.h> - -#include "usb_if.h" - -/* - * gsctool uses this structure to keep information about the communications - * channel used to talk to the Cr50, and about the state of the Cr50 image. - */ -struct transfer_descriptor { - /* - * Set to true for use in an upstart script. Do not reboot after - * transfer, and do not transfer RW if versions are the same. - * - * When using in development environment it is beneficial to transfer - * RW images with the same version, as they get started based on the - * header timestamp. - */ - int upstart_mode; - /* - * Override in case updater is used w/ boards that do not follow - * the cr50 versioning scheme. - */ - int background_update_supported; - /* - * Unconditionally update the inactive RO, helps to make sure both RO - * sections are at the same level. - */ - int force_ro; - /* - * offsets of RO and WR sections available for update (not currently - * active). - */ - uint32_t ro_offset; - uint32_t rw_offset; - - /* Do not reset the H1 immediately after update, wait for TPM reset. */ - int post_reset; - - /* Type of channel used to communicate with Cr50. */ - enum transfer_type { - usb_xfer = 0, /* usb interface. */ - dev_xfer = 1, /* /dev/tpm0 */ - ts_xfer = 2 /* trunks_send */ - } ep_type; - union { - struct usb_endpoint uep; - int tpm_fd; - }; -}; - -/* - * These are values returned by the gsctool utility, they are interpreted by - * the startup files to decide how to proceed (try to update to a new Cr50 - * image or not). - */ -enum exit_values { - noop = 0, /* All up to date, no update needed. */ - all_updated = 1, /* Update completed, reboot required. */ - rw_updated = 2, /* RO was not updated, reboot required. */ - update_error = 3 /* Something went wrong. */ -}; - - -struct board_id { - uint32_t type; /* Board type */ - uint32_t type_inv; /* Board type (inverted) */ - uint32_t flags; /* Flags */ -}; - -enum board_id_action { - bid_none, - bid_get, - bid_set -}; - -/* - * This function allows to retrieve or set (if not initialized) board ID of - * the H1 chip. If bid_action is bid_get and show_machine_output is set, - * prints out board ID in a machine-friendly format. - */ -void process_bid(struct transfer_descriptor *td, - enum board_id_action bid_action, - struct board_id *bid, - bool show_machine_output); - -/* - * This function can be used to retrieve the current PP status from Cr50 and - * prompt the user when a PP press is required. - * - * Physical presence can be required by different gsctool options, for which - * Cr50 behavior also differs. The 'command' and 'poll_type' parameters are - * used by Cr50 to tell what the host is polling for. - */ -void poll_for_pp(struct transfer_descriptor *td, - uint16_t command, - uint8_t poll_type); - -/* - * Function used to send vendor command to the Cr50 and receive a response. - * Returns the error code from TPM response header, which is set to zero on - * success. - */ -uint32_t send_vendor_command(struct transfer_descriptor *td, - uint16_t subcommand, - const void *command_body, - size_t command_body_size, - void *response, - size_t *response_size); - - -#endif // __EXTRA_USB_UPDATER_GSCTOOL_H diff --git a/extra/usb_updater/verify_ro.c b/extra/usb_updater/verify_ro.c deleted file mode 100644 index 4a4aea792a..0000000000 --- a/extra/usb_updater/verify_ro.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright 2018 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 <errno.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "config.h" -#include "desc_parser.h" -#include "gsctool.h" -#include "tpm_vendor_cmds.h" -#include "verify_ro.h" - -/* Index of the matching hash variant. */ -static ssize_t matching_variant; - -/* - * Print out passed in buffer contents in hex, 16 bytes per line, each line - * starting with the base address value. - * - * If the passed in base address is not aligned at 16 byte boundary, skip - * positions in the dump line so that the address is displayed rounded down to - * the closest lower 16 byte boundary. - * - * For instance passing base of 0x4007 and size of 20 will result in a - * printout like: - * - * 004000 e0 00 00 00 00 66 c7 05 04 - * 004010 80 06 e0 06 00 66 c7 05 20 90 06 - * - * If title is nonzero - print out the string it points to before printing - * out buffer contents. - */ -static void print_buffer_aligned(const char *title, uint32_t base, - size_t size, const void *data) -{ - const uint8_t *bytes = data; - size_t i; - uint8_t alignment; - - /* - * Calculate how many characters we need to skip in the first dump - * line. - */ - alignment = base % 16; - if (alignment) { - size += alignment; - base &= ~0xf; - } - - if (title) - printf("%s\n", title); - - /* Let's print data space separated 16 bytes per line. */ - for (i = 0; i < size; i++) { - if (!(i % 16)) - printf("\n%06zx", base + i); - - if (i < alignment) - printf(" "); - else - printf(" %02x", bytes[i - alignment]); - } -} - -/* Change the DUT spihash range to the new_type value. */ -static int set_new_range(struct transfer_descriptor *td, - enum range_type_t new_type) -{ - uint32_t rv; - struct vendor_cc_spi_hash_request req; - - memset(&req, 0, sizeof(req)); - - /* Need to send command to change spihash mode. */ - switch (new_type) { - case AP_RANGE: - req.subcmd = SPI_HASH_SUBCMD_AP; - break; - case EC_RANGE: - req.subcmd = SPI_HASH_SUBCMD_EC; - break; - case EC_GANG_RANGE: - req.subcmd = SPI_HASH_SUBCMD_EC; - req.flags = SPI_HASH_FLAG_EC_GANG; - break; - default: /* Should never happen. */ - return -EINVAL; - } - - rv = send_vendor_command(td, VENDOR_CC_SPI_HASH, &req, sizeof(req), - 0, NULL); - - if (!rv) - return 0; - - if (rv == VENDOR_RC_IN_PROGRESS) { - /* This will exit() on error. */ - poll_for_pp(td, VENDOR_CC_SPI_HASH, SPI_HASH_PP_POLL); - } else { - fprintf(stderr, - "%s: failed setting range type %d, error %d\n", - __func__, new_type, rv); - return -EINVAL; - } - - return 0; -} - -/* - * Verify a dump descriptor hash section defined by 'range'. The passed in by - * pointer structure req has the range offset and size already initialized. - * - * Make sure that matching hashes are at the same index in the hash variants - * arrays within the same board section. - */ -static int verify_hash_section(struct transfer_descriptor *td, - struct vendor_cc_spi_hash_request *req, - struct addr_range *range) -{ - size_t i; - uint8_t response[sizeof(range->variants->expected_result)]; - size_t response_size; - int rv; - - /* First retrieve hash from the DUT. */ - response_size = sizeof(response); - req->subcmd = SPI_HASH_SUBCMD_SHA256; - rv = send_vendor_command(td, VENDOR_CC_SPI_HASH, - req, sizeof(*req), response, &response_size); - - if (rv) { - fprintf(stderr, - "%s: failed retrieving hash at %x, tpm error %d\n", - __func__, req->offset, rv); - return -EINVAL; - } - - if (response_size != sizeof(response)) { - fprintf(stderr, "got %zd bytes in response for range %x:%x\n", - response_size, req->offset, req->size); - return -EINVAL; - } - - if (matching_variant < 0) { - /* This is the first hash range to be processed. */ - struct result_node *variant = range->variants; - - for (i = 0; i < range->variant_count; i++) { - if (!memcmp(variant->expected_result, - response, response_size)) { - matching_variant = i; - return 0; - } - variant++; - } - - fprintf(stderr, "no matching hash found for range %x:%x\n", - req->offset, req->size); - return -EINVAL; - } - - if (!memcmp(range->variants[matching_variant].expected_result, - response, response_size)) - return 0; - - fprintf(stderr, "hash mismatch for range %x:%x\n", - req->offset, req->size); - - return -EINVAL; -} - -/* - * Dump DUT's memory in the range defined by contents of the passed in req - * structure. - * - * The Cr50 SPI hash dump vendor command implementation limits size of the - * dump to 32, so in case the caller requests more than 32 bytes retrieve them - * in 32 byte blocks. - * - * If base address of the range is not aligned at 16, retrieve smaller - * quantity such that the following transactions retrieve block starting at - * aligned addresses, this makes for a better looking hex dump. - */ -static int dump_range(struct transfer_descriptor *td, - struct vendor_cc_spi_hash_request *req) -{ - size_t remaining_size = req->size; - size_t response_size; - /* Max size of a single shot is 32 bytes. */ - const size_t max_transfer = 32; - uint8_t response[max_transfer]; - - req->subcmd = SPI_HASH_SUBCMD_DUMP; - while (remaining_size) { - size_t shot_size = max_transfer; - uint8_t alignment; - uint32_t rv; - - alignment = req->offset % 16; - - if (alignment && ((alignment + remaining_size) > max_transfer)) - /* first line should be truncated. */ - shot_size = max_transfer - alignment; - else if (shot_size > remaining_size) - shot_size = remaining_size; - - req->size = shot_size; - response_size = shot_size; - rv = send_vendor_command(td, VENDOR_CC_SPI_HASH, - req, sizeof(*req), response, - &response_size); - if (rv) { - fprintf(stderr, - "%s: failed getting dump contents at %x\n", - __func__, req->offset); - return -EINVAL; - } - - if (response_size != shot_size) { - fprintf(stderr, - "%s: dump error: got %zd bytes, expected %zd\n", - __func__, response_size, shot_size); - return -EINVAL; - } - - print_buffer_aligned(NULL, req->offset, shot_size, response); - remaining_size -= shot_size; - req->offset += shot_size; - } - printf("\n"); - - return 0; -} - -/* - * Iterate through sections of a board descriptor database, retrieving hashes - * or straight memory blocks as defined by description sections. - */ -static int process_descriptor_sections(struct transfer_descriptor *td) -{ - struct vendor_cc_spi_hash_request req; - int rv; - struct addr_range *range; - enum range_type_t current_range = NOT_A_RANGE; - - do { - /* - * Retrieve next range descriptor section from the descriptor - * database. The function below is guaranteed to set range to - * NULL on any error. - */ - rv = parser_get_next_range(&range); - if (rv) { - /* - * ENODATA means all board's sections have been - * processed. - */ - if (rv == -ENODATA) - rv = 0; - break; - } - - if (current_range != range->range_type) { - rv = set_new_range(td, range->range_type); - if (rv) - break; - } - - memset(&req, 0, sizeof(req)); - req.offset = range->base_addr; - req.size = range->range_size; - - if (range->variant_count) - rv = verify_hash_section(td, &req, range); - else - rv = dump_range(td, &req); - - free(range); - range = NULL; - } while (!rv); - - if (range) - free(range); - - return rv; -} - -int verify_ro(struct transfer_descriptor *td, - const char *desc_file_name, - bool show_machine_output) -{ - /* First find out board ID of the target. */ - struct board_id bid; - char rlz_code[sizeof(bid.type) + 1]; - int section_count = 0; - int rv = 0; - - /* - * Find out what Board ID is the device we are talking to. This - * function calls exit() on any error. - */ - process_bid(td, bid_get, &bid, show_machine_output); - - if (bid.type != ~bid.type_inv) { - fprintf(stderr, "Inconsistent board ID: %08x != ~%08x\n", - bid.type, bid.type_inv); - return -EINVAL; - } - - /* - * Convert bid from int to asciiz so that it could be used for - * strcmp() on the descriptor file section headers. - */ - memcpy(rlz_code, &bid.type, sizeof(rlz_code) - 1); - rlz_code[sizeof(rlz_code) - 1] = '\0'; - - while (!parser_find_board(desc_file_name, rlz_code)) { - - /* - * Each board section might have different index of the - * matching hash variant. - */ - matching_variant = -1; - - section_count++; - rv = process_descriptor_sections(td); - if (rv) - break; - } - - if (section_count != 2) { - printf("Found wrong number of sections (%d) for board ID %s\n", - section_count, rlz_code); - rv = -EINVAL; - } else if (!rv) { - /* - * Check was successful, send command to exit verification - * mode. - */ - struct vendor_cc_spi_hash_request req; - - memset(&req, 0, sizeof(req)); - req.subcmd = SPI_HASH_SUBCMD_DISABLE; - rv = send_vendor_command(td, VENDOR_CC_SPI_HASH, &req, - sizeof(req), 0, NULL); - if (rv) { - fprintf(stderr, - "%s: spi hash disable TPM error %d\n", - __func__, rv); - rv = -EINVAL; - } - } - - parser_done(); - return rv; -} diff --git a/extra/usb_updater/verify_ro.h b/extra/usb_updater/verify_ro.h deleted file mode 100644 index de2443b8b4..0000000000 --- a/extra/usb_updater/verify_ro.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2018 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. - */ - -#ifndef __EXTRA_USB_UPDATER_VERIFY_RO_H -#define __EXTRA_USB_UPDATER_VERIFY_RO_H - -#include <stdbool.h> - -#include "gsctool.h" - -/* - * Runs RO verification on the target specified in td using the description file - * desc_file_name. If show_machine_output is set, target's board ID will be - * outputted in a machine-friendly format. Returns 0 on success or a negative - * value if there is an error. - */ -int verify_ro(struct transfer_descriptor *td, - const char *desc_file_name, - bool show_machine_output); - -#endif // __EXTRA_USB_UPDATER_VERIFY_RO_H diff --git a/fuzz/fuzz_config.h b/fuzz/fuzz_config.h index 963075efab..3e3e1f0872 100644 --- a/fuzz/fuzz_config.h +++ b/fuzz/fuzz_config.h @@ -12,76 +12,6 @@ /* Disable hibernate: We never want to exit while fuzzing. */ #undef CONFIG_HIBERNATE -#ifdef TEST_CR50_FUZZ -#define CONFIG_DCRYPTO -#define CONFIG_PINWEAVER -#define CONFIG_UPTO_SHA512 -#define SHA512_SUPPORT -#define CONFIG_MALLOC - -/******************************************************************************/ -/* From chip/g/config_chip.h */ - -#define CFG_FLASH_HALF (CONFIG_FLASH_SIZE >> 1) -#define CFG_TOP_SIZE 0x3000 -#define CFG_TOP_A_OFF (CFG_FLASH_HALF - CFG_TOP_SIZE) -#define CFG_TOP_B_OFF (CONFIG_FLASH_SIZE - CFG_TOP_SIZE) - -/******************************************************************************/ -/* From board/cr50/board.h */ -/* Non-volatile counter storage for U2F */ -#define CONFIG_CRC8 -#define CONFIG_FLASH_ERASED_VALUE32 (-1U) -#define CONFIG_FLASH_LOG -#define CONFIG_FLASH_LOG_BASE CONFIG_PROGRAM_MEMORY_BASE -#define CONFIG_FLASH_LOG_SPACE 0x800 - -/* We're using TOP_A for partition 0, TOP_B for partition 1 */ -#define CONFIG_FLASH_NVMEM -/* Offset to start of NvMem area from base of flash */ -#define CONFIG_FLASH_NVMEM_OFFSET_A (CFG_TOP_A_OFF) -#define CONFIG_FLASH_NVMEM_OFFSET_B (CFG_TOP_B_OFF) -/* Address of start of Nvmem area */ -#define CONFIG_FLASH_NVMEM_BASE_A \ - (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_A) -#define CONFIG_FLASH_NVMEM_BASE_B \ - (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_B) -#define CONFIG_FLASH_NEW_NVMEM_BASE_A \ - (CONFIG_FLASH_NVMEM_BASE_A + CONFIG_FLASH_BANK_SIZE) -#define CONFIG_FLASH_NEW_NVMEM_BASE_B \ - (CONFIG_FLASH_NVMEM_BASE_B + CONFIG_FLASH_BANK_SIZE) -/* Size partition in NvMem */ -#define NVMEM_PARTITION_SIZE (CFG_TOP_SIZE) -/* Size in bytes of NvMem area */ -#define CONFIG_FLASH_NVMEM_SIZE (NVMEM_PARTITION_SIZE * NVMEM_NUM_PARTITIONS) - -#define NEW_NVMEM_PARTITION_SIZE (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) -#define NEW_NVMEM_TOTAL_PAGES \ - (2 * NEW_NVMEM_PARTITION_SIZE / CONFIG_FLASH_BANK_SIZE) - -/* Enable <key, value> variable support. */ -#define CONFIG_FLASH_NVMEM_VARS -#define NVMEM_CR50_SIZE 272 -#define CONFIG_FLASH_NVMEM_VARS_USER_SIZE NVMEM_CR50_SIZE - -#ifndef __ASSEMBLER__ -enum nvmem_users { - NVMEM_TPM = 0, - NVMEM_CR50, - NVMEM_NUM_USERS -}; -#endif - -#define NVMEM_TPM_SIZE \ - (sizeof(((nvmem_partition *)(0))->buffer) - NVMEM_CR50_SIZE) - -#define CONFIG_FLASH_NVMEM_VARS_USER_NUM NVMEM_CR50 - -/******************************************************************************/ -#define CONFIG_SW_CRC - -#endif /* TEST_CR50_FUZZ */ - #ifdef TEST_HOST_COMMAND_FUZZ #undef CONFIG_HOSTCMD_DEBUG_MODE diff --git a/include/ccd_config.h b/include/ccd_config.h deleted file mode 100644 index 3952cb9bc9..0000000000 --- a/include/ccd_config.h +++ /dev/null @@ -1,359 +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. - * - * Case Closed Debugging configuration - */ -#ifndef __CROS_EC_CCD_CONFIG_H -#define __CROS_EC_CCD_CONFIG_H - -#include <stdint.h> -#include "common.h" -#include "compile_time_macros.h" - -/* Case-closed debugging state */ -enum ccd_state { - CCD_STATE_LOCKED = 0, - CCD_STATE_UNLOCKED, - CCD_STATE_OPENED, - - /* Number of CCD states */ - CCD_STATE_COUNT -}; - -/* Flags */ -enum ccd_flag { - /* Flags that can only be set internally; fill from bottom up */ - - /* - * Test lab mode is enabled. This MUST be in the first byte so that - * it's in a constant position across all versions of CCD config. - * - * Note: This is used internally by CCD config. Do NOT test this - * to control other things; use capabilities for those. - */ - CCD_FLAG_TEST_LAB = BIT(0), - - /* - * What state were we in when the password was set? - * (0=opened, 1=unlocked) - */ - CCD_FLAG_PASSWORD_SET_WHEN_UNLOCKED = BIT(1), - - /* - * Factory mode state - */ - CCD_FLAG_FACTORY_MODE_ENABLED = BIT(2), - - /* (flags in the middle are unused) */ - - /* Flags that can be set via ccd_set_flags(); fill from top down */ - - /* Override BATT_PRES_L at boot */ - CCD_FLAG_OVERRIDE_BATT_AT_BOOT = BIT(20), - - /* - * If overriding BATT_PRES_L at boot, set it to what value - * (0=disconnect, 1=connected) - */ - CCD_FLAG_OVERRIDE_BATT_STATE_CONNECT = BIT(21), - - /* Override write protect at boot */ - CCD_FLAG_OVERRIDE_WP_AT_BOOT = BIT(22), - - /* - * If overriding WP at boot, set it to what value - * (0=disabled, 1=enabled) - */ - CCD_FLAG_OVERRIDE_WP_STATE_ENABLED = BIT(23), -}; - -/* Capabilities */ -enum ccd_capability { - /* UARTs to/from AP and EC */ - CCD_CAP_GSC_RX_AP_TX = 0, - CCD_CAP_GSC_TX_AP_RX = 1, - CCD_CAP_GSC_RX_EC_TX = 2, - CCD_CAP_GSC_TX_EC_RX = 3, - - /* Access to AP SPI flash */ - CCD_CAP_AP_FLASH = 4, - - /* Access to EC flash (SPI or internal) */ - CCD_CAP_EC_FLASH = 5, - - /* Override WP temporarily or at boot */ - CCD_CAP_OVERRIDE_WP = 6, - - /* Reboot EC or AP */ - CCD_CAP_REBOOT_EC_AP = 7, - - /* GSC restricted console commands */ - CCD_CAP_GSC_RESTRICTED_CONSOLE = 8, - - /* Allow ccd-unlock or ccd-open without AP reboot */ - CCD_CAP_UNLOCK_WITHOUT_AP_REBOOT = 9, - - /* Allow ccd-unlock or ccd-open without short physical presence */ - CCD_CAP_UNLOCK_WITHOUT_SHORT_PP = 10, - - /* Allow ccd-open without wiping TPM data */ - CCD_CAP_OPEN_WITHOUT_TPM_WIPE = 11, - - /* Allow ccd-open without long physical presence */ - CCD_CAP_OPEN_WITHOUT_LONG_PP = 12, - - /* Allow removing the battery to bypass physical presence requirement */ - CCD_CAP_REMOVE_BATTERY_BYPASSES_PP = 13, - - /* Allow GSC firmware update without wiping TPM data */ - CCD_CAP_GSC_FW_UPDATE_WITHOUT_TPM_WIPE = 14, - - /* Access to I2C via USB */ - CCD_CAP_I2C = 15, - - /* Read-only access to hash or dump EC or AP flash */ - CCD_CAP_FLASH_READ = 16, - - /* Allow ccd open without dev mode enabled */ - CCD_CAP_OPEN_WITHOUT_DEV_MODE = 17, - - /* Allow ccd open from usb */ - CCD_CAP_OPEN_FROM_USB = 18, - - /* Override battery presence temporarily or at boot */ - CCD_CAP_OVERRIDE_BATT_STATE = 19, - - /* Number of currently defined capabilities */ - CCD_CAP_COUNT -}; - -/* Capability states */ -enum ccd_capability_state { - /* Default value */ - CCD_CAP_STATE_DEFAULT = 0, - - /* Always available (state >= CCD_STATE_LOCKED) */ - CCD_CAP_STATE_ALWAYS = 1, - - /* Unless locked (state >= CCD_STATE_UNLOCKED) */ - CCD_CAP_STATE_UNLESS_LOCKED = 2, - - /* Only if opened (state >= CCD_STATE_OPENED) */ - CCD_CAP_STATE_IF_OPENED = 3, - - /* Number of capability states */ - CCD_CAP_STATE_COUNT -}; - -struct ccd_capability_info { - /* Capability name */ - const char *name; - - /* Default state, if config set to CCD_CAP_STATE_DEFAULT */ - enum ccd_capability_state default_state; -}; - -#ifdef CONFIG_CCD_OPEN_PREPVT -/* In prepvt images always allow ccd open from the console without dev mode */ -#define CCD_CAP_STATE_OPEN_REQ CCD_CAP_STATE_ALWAYS -#else -/* In prod images restrict how ccd can be opened */ -#define CCD_CAP_STATE_OPEN_REQ CCD_CAP_STATE_IF_OPENED -#endif - -#define CAP_INFO_DATA { \ - {"UartGscRxAPTx", CCD_CAP_STATE_ALWAYS}, \ - {"UartGscTxAPRx", CCD_CAP_STATE_ALWAYS}, \ - {"UartGscRxECTx", CCD_CAP_STATE_ALWAYS}, \ - {"UartGscTxECRx", CCD_CAP_STATE_IF_OPENED}, \ - \ - {"FlashAP", CCD_CAP_STATE_IF_OPENED}, \ - {"FlashEC", CCD_CAP_STATE_IF_OPENED}, \ - {"OverrideWP", CCD_CAP_STATE_IF_OPENED}, \ - {"RebootECAP", CCD_CAP_STATE_IF_OPENED}, \ - \ - {"GscFullConsole", CCD_CAP_STATE_IF_OPENED}, \ - {"UnlockNoReboot", CCD_CAP_STATE_ALWAYS}, \ - {"UnlockNoShortPP", CCD_CAP_STATE_ALWAYS}, \ - {"OpenNoTPMWipe", CCD_CAP_STATE_IF_OPENED}, \ - \ - {"OpenNoLongPP", CCD_CAP_STATE_IF_OPENED}, \ - {"BatteryBypassPP", CCD_CAP_STATE_ALWAYS}, \ - {"UpdateNoTPMWipe", CCD_CAP_STATE_ALWAYS}, \ - {"I2C", CCD_CAP_STATE_IF_OPENED}, \ - {"FlashRead", CCD_CAP_STATE_ALWAYS}, \ - {"OpenNoDevMode", CCD_CAP_STATE_OPEN_REQ}, \ - {"OpenFromUSB", CCD_CAP_STATE_OPEN_REQ}, \ - {"OverrideBatt", CCD_CAP_STATE_IF_OPENED}, \ - } - -#define CCD_STATE_NAMES { "Locked", "Unlocked", "Opened" } -#define CCD_CAP_STATE_NAMES { "Default", "Always", "UnlessLocked", "IfOpened" } - -/* Macros regarding ccd_capabilities */ -#define CCD_CAP_BITS 2 -#define CCD_CAP_BITMASK (BIT(CCD_CAP_BITS) - 1) -#define CCD_CAPS_PER_BYTE (8 / CCD_CAP_BITS) - -/* - * Subcommand code, used to pass different CCD commands using the same TPM - * vendor command. - */ -enum ccd_vendor_subcommands { - CCDV_PASSWORD = 0, - CCDV_OPEN = 1, - CCDV_UNLOCK = 2, - CCDV_LOCK = 3, - CCDV_PP_POLL_UNLOCK = 4, - CCDV_PP_POLL_OPEN = 5, - CCDV_GET_INFO = 6 -}; - -enum ccd_pp_state { - CCD_PP_CLOSED = 0, - CCD_PP_AWAITING_PRESS = 1, - CCD_PP_BETWEEN_PRESSES = 2, - CCD_PP_DONE = 3 -}; - -/* Structure to communicate information about CCD state. */ -#define CCD_CAPS_WORDS ((CCD_CAP_COUNT * 2 + 31)/32) -struct ccd_info_response { - uint32_t ccd_caps_current[CCD_CAPS_WORDS]; - uint32_t ccd_caps_defaults[CCD_CAPS_WORDS]; - uint32_t ccd_flags; - uint8_t ccd_state; - uint8_t ccd_force_disabled; - /* - * A bitmap indicating ccd internal state. - * See "enum ccd_indicator_bits" below. - */ - uint8_t ccd_indicator_bitmap; -} __packed; - -enum ccd_indicator_bits { - /* has_password? */ - CCD_INDICATOR_BIT_HAS_PASSWORD = BIT(0), - - /* Are CCD capabilities in CCD_CAP_STATE_DEFAULT */ - CCD_INDICATOR_BIT_ALL_CAPS_DEFAULT = BIT(1), -}; - -/** - * Initialize CCD configuration at boot. - * - * This must be called before any command which gets/sets the configuration. - * - * @param state Initial case-closed debugging state. This should be - * CCD_STATE_LOCKED unless this is a debug build, or if - * a previous value is being restored after a low-power - * resume. - */ -void ccd_config_init(enum ccd_state state); - -/** - * Get a single CCD flag. - * - * @param flag Flag to get - * @return 1 if flag is set, 0 if flag is clear - */ -int ccd_get_flag(enum ccd_flag flag); - -/** - * Set a single CCD flag. - * - * @param flag Flag to set - * @param value New value for flag (0=clear, non-zero=set) - * @return EC_SUCCESS or non-zero error code. - */ -int ccd_set_flag(enum ccd_flag flag, int value); - -/** - * Check if a CCD capability is enabled in the current CCD mode. - * - * @param cap Capability to check - * @return 1 if capability is enabled, 0 if disabled - */ -int ccd_is_cap_enabled(enum ccd_capability cap); - -/** - * Get the current CCD state. - * - * This is intended for use by the board if it needs to back up the CCD state - * across low-power states and then restore it when calling ccd_config_init(). - * Do NOT use this to gate debug capabilities; use ccd_is_cap_enabled() or - * ccd_get_flag() instead. - * - * @return The current CCD state. - */ -enum ccd_state ccd_get_state(void); - -/** - * Force CCD disabled. - * - * This should be called if security checks fail and for some reason the board - * can't immediately reboot. It locks CCD and disables all CCD capabilities - * until reboot. - */ -void ccd_disable(void); - -/** - * Get the factory mode state. - * - * @return 0 if factory mode is disabled, !=0 if factory mode is enabled. - */ -int ccd_get_factory_mode(void); - -/* Flags for ccd_reset_config() */ -enum ccd_reset_config_flags { - /* Also reset test lab flag */ - CCD_RESET_TEST_LAB = BIT(0), - - /* Only reset Always/UnlessLocked settings */ - CCD_RESET_UNLOCKED_ONLY = BIT(1), - - /* - * Do a factory reset to enable factory mode. Factory mode sets all ccd - * capabilities to always and disables write protect - */ - CCD_RESET_FACTORY = BIT(2) -}; - -/** - * Reset CCD config to the desired state. - * - * @param flags Reset flags (see enum ccd_reset_config_flags) - * @return EC_SUCCESS, or non-zero if error. - */ -int ccd_reset_config(unsigned int flags); - -/** - * Inform CCD about TPM reset so that the password management state machine - * can be restarted. - */ -void ccd_tpm_reset_callback(void); - -/** - * Return True if the ccd password is set. It is possible that a pending ccd - * change would set or clear the password, but we don't think this is a big - * issue or risk for now. - * - * @return 1 if password is set, 0 if it's not - */ -int ccd_has_password(void); - -/** - * Enter CCD factory mode. This will clear the TPM, update the ccd config, and - * then do a hard reboot if 'reset_required' is True. - */ -void enable_ccd_factory_mode(int reset_required); - -/* - * Enable factory mode but not necessarily rebooting the device. This will - * clear the TPM and disable flash write protection. Will trigger system reset - * only if 'reset_required' is True. - */ -void factory_enable(int reset_required); - -#endif /* __CROS_EC_CCD_CONFIG_H */ diff --git a/include/config.h b/include/config.h index 2d1367778f..e3eca279c4 100644 --- a/include/config.h +++ b/include/config.h @@ -373,9 +373,6 @@ #undef CONFIG_AUDIO_CODEC_WOV_LANG_BUF_LEN #undef CONFIG_AUDIO_CODEC_WOV_LANG_BUF_TYPE -/* Allow proprietary communication protocols' extensions. */ -#undef CONFIG_EXTENSION_COMMAND - /* * Support controlling the display backlight based on the state of the lid * switch. The EC will disable the backlight when the lid is closed. @@ -732,13 +729,6 @@ */ #undef CONFIG_BUTTONS_RUNTIME_CONFIG -/* Support V1 CCD configuration */ -#undef CONFIG_CASE_CLOSED_DEBUG_V1 -/* Allow unsafe debugging functionality in V1 configuration */ -#undef CONFIG_CASE_CLOSED_DEBUG_V1_UNSAFE -/* Loosen Open restrictions for prePVT devices */ -#undef CONFIG_CCD_OPEN_PREPVT - /* * Capsense chip has buttons, too. */ @@ -1192,7 +1182,6 @@ #define CONFIG_CMD_RETIMER #undef CONFIG_CMD_BUTTON #define CONFIG_CMD_CBI -#undef CONFIG_CMD_CCD_DISABLE /* 'ccd disable' subcommand */ #undef CONFIG_CMD_CHARGEN #define CONFIG_CMD_CHARGER #undef CONFIG_CMD_CHARGER_ADC_AMON_BMON @@ -1431,42 +1420,6 @@ /* Include CRC-8 utility function */ #undef CONFIG_CRC8 -/* - * When enabled, build in support for software & hardware crypto; - * only supported on CR50. - * - * If this is enabled on the host board, a minimal implementation is included to - * allow fuzzing targets to fuzz code that depends on dcrypto. - */ -#undef CONFIG_DCRYPTO -/* - * This provides struct definitions and function declarations that can be - * implemented by unit tests for testing code that depends on dcrypto. - * This should not be set at the same time as CONFIG_DCRYPTO. - */ -#undef CONFIG_DCRYPTO_MOCK - -/* - * When enabled, RSA 2048 bit keygen gets a 40% performance boost, - * at the cost of 2184 bytes of image size increase. - */ -#undef CONFIG_DCRYPTO_RSA_SPEEDUP - -/* - * When enabled build support for SHA-384/512, requires CONFIG_DCRYPTO. - */ -#undef CONFIG_UPTO_SHA512 - -/* - * When enabled ignore version et al during fw upgrade for chip/g. - */ -#undef CONFIG_IGNORE_G_UPDATE_CHECKS - -/* - * Enable console shell command 'alerts' that prints chip alerts statistics. - */ -#undef CONFIG_ENABLE_H1_ALERTS_CONSOLE - /*****************************************************************************/ /* * Debugging config @@ -1606,9 +1559,6 @@ /* Default debounce time for external power signal */ #define CONFIG_EXTPOWER_DEBOUNCE_MS 30 -/* Add support for CCD factory mode */ -#undef CONFIG_FACTORY_MODE - /*****************************************************************************/ /* Number of cooling fans. Undef if none. */ #undef CONFIG_FANS @@ -1769,34 +1719,6 @@ #undef CONFIG_FP_SENSOR_FPC1145 /*****************************************************************************/ -/* NvMem Configuration */ -/* Enable NV Memory module within flash */ -#undef CONFIG_FLASH_NVMEM -/* Offset to start of NvMem area from base of flash */ -#undef CONFIG_FLASH_NVMEM_OFFSET_A -#undef CONFIG_FLASH_NVMEM_OFFSET_B -/* Address of start of Nvmem area */ -#undef CONFIG_FLASH_NVMEM_BASE_A -#undef CONFIG_FLASH_NVMEM_BASE_B - -/* Flash offsets for the 'new' (as of 1/2019) nvmem storage scheme. */ -#undef CONFIG_FLASH_NEW_NVMEM_BASE_A -#undef CONFIG_FLASH_NEW_NVMEM_BASE_B - -/* Size in bytes of NvMem area */ -#undef CONFIG_FLASH_NVMEM_SIZE - -/* Enable <key,value> variable support (requires CONFIG_FLASH_NVMEM) */ -#undef CONFIG_FLASH_NVMEM_VARS -/* - * We already have to define nvmem_user_sizes[] to specify the order and size - * of the user regions. CONFIG_FLASH_NVMEM_VARS looks for two symbols to - * specify the region number and size for the variable region. - */ -#undef CONFIG_FLASH_NVMEM_VARS_USER_NUM -#undef CONFIG_FLASH_NVMEM_VARS_USER_SIZE - -/*****************************************************************************/ /* Include a flashmap in the compiled firmware image */ #define CONFIG_FMAP @@ -2904,19 +2826,6 @@ */ #undef CONFIG_PECI_TJMAX -/* Support physical presence detection (via a physical button) */ -#undef CONFIG_PHYSICAL_PRESENCE - -/* Enable (unsafe!) developer debug features for physical presence */ -#undef CONFIG_PHYSICAL_PRESENCE_DEBUG_UNSAFE - -/*****************************************************************************/ -/* PinWeaver config - * A feature which exchanges a low entropy secret with rate limits for a high - * entropy secret. This enables a set of vendor specific commands for Cr50. - */ -#undef CONFIG_PINWEAVER - /*****************************************************************************/ /* PMU config */ @@ -3110,12 +3019,6 @@ #undef CONFIG_RAM_SIZE #undef CONFIG_ROM_SIZE -/* Enable rbox peripheral */ -#undef CONFIG_RBOX - -/* Enable rbox wakeup */ -#undef CONFIG_RBOX_WAKEUP - /* Support IR357x Link voltage regulator debugging / reprogramming */ #undef CONFIG_REGULATOR_IR357X @@ -3255,14 +3158,6 @@ /* Support deprecated SPI protocol version 2. */ #undef CONFIG_SPI_PROTOCOL_V2 -/* - * Support SPI Slave interfaces. The first board supporting this is cr50 and - * in its parlance SPI_SLAVE is called SPS. This convention might be - * reconsidered later, and the use of "SPI" in different config options needs - * to be cleaned up. (crbug.com/512613). - */ -#undef CONFIG_SPS - /* Define the SPI port to use to access SPI accelerometer */ #undef CONFIG_SPI_ACCEL_PORT @@ -3342,9 +3237,6 @@ */ #undef CONFIG_MCHP_GPSPI -/* Support testing SPI slave controller driver. */ -#undef CONFIG_SPS_TEST - /* Default stack size to use for tasks, in bytes */ #undef CONFIG_STACK_SIZE @@ -3616,12 +3508,6 @@ #undef CONFIG_TOUCHPAD_HASH_FW /*****************************************************************************/ -/* TPM-like configuration */ - -/* Speak to the TPM 2.0 hardware protocol on the I2C slave interface */ -#undef CONFIG_TPM_I2CS - -/*****************************************************************************/ /* USART stream config */ #undef CONFIG_STREAM_USART @@ -3635,10 +3521,6 @@ #undef CONFIG_STREAM_USART4 /*****************************************************************************/ -/* U2F config: second factor authentication */ -#undef CONFIG_U2F - -/*****************************************************************************/ /* USB stream config */ #undef CONFIG_STREAM_USB @@ -4221,9 +4103,6 @@ /* Disable automatic initialization of USB peripheral */ #undef CONFIG_USB_INHIBIT_INIT -/* Support control of multiple PHY */ -#undef CONFIG_USB_SELECT_PHY - /* Support simple control of power to the device's USB ports */ #undef CONFIG_USB_PORT_POWER_DUMB @@ -4504,12 +4383,6 @@ #undef CONFIG_EXTENDED_VERSION_INFO /* - * Define this if board ID support is required. For g chip based boards it - * allows to nail different images to different boards. - */ -#undef CONFIG_BOARD_ID_SUPPORT - -/* * Define this to enable Cros Board Info support. I2C_EEPROM_PORT and * I2C_EEPROM_ADDR must be defined as well. */ diff --git a/include/console_channel.inc b/include/console_channel.inc index f4558bef3c..e240bf4546 100644 --- a/include/console_channel.inc +++ b/include/console_channel.inc @@ -22,12 +22,6 @@ CONSOLE_CHANNEL(CC_BLUETOOTH_HCI,"bluetooth_hci") #ifdef CONFIG_CEC CONSOLE_CHANNEL(CC_CEC, "cec") #endif -#ifdef CONFIG_EXTENSION_COMMAND -CONSOLE_CHANNEL(CC_EXTENSION, "extension") -#endif -#if defined(CONFIG_PHYSICAL_PRESENCE) -CONSOLE_CHANNEL(CC_CCD, "ccd") -#endif CONSOLE_CHANNEL(CC_CHARGER, "charger") #ifdef HAS_TASK_CHIPSET CONSOLE_CHANNEL(CC_CHIPSET, "chipset") @@ -85,12 +79,6 @@ CONSOLE_CHANNEL(CC_PS2, "ps2") CONSOLE_CHANNEL(CC_PWM, "pwm") #endif CONSOLE_CHANNEL(CC_SPI, "spi") -#ifdef CONFIG_RBOX -CONSOLE_CHANNEL(CC_RBOX, "rbox") -#endif -#ifdef CONFIG_SPS -CONSOLE_CHANNEL(CC_SPS, "sps") -#endif #if defined(CONFIG_SWITCH) || defined(CONFIG_LID_SWITCH) CONSOLE_CHANNEL(CC_SWITCH, "switch") #endif @@ -106,9 +94,6 @@ CONSOLE_CHANNEL(CC_DPTF, "dptf") CONSOLE_CHANNEL(CC_ALS, "als") #endif CONSOLE_CHANNEL(CC_THERMAL, "thermal") -#ifdef CHIP_G -CONSOLE_CHANNEL(CC_TPM, "tpm") -#endif CONSOLE_CHANNEL(CC_USB, "usb") CONSOLE_CHANNEL(CC_USBCHARGE, "usbcharge") #if defined(CONFIG_USB_POWER_DELIVERY) || defined(CONFIG_USB_PD_TCPC) diff --git a/include/extension.h b/include/extension.h deleted file mode 100644 index 5ce0410f57..0000000000 --- a/include/extension.h +++ /dev/null @@ -1,102 +0,0 @@ -/* Copyright 2015 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. - */ - -#ifndef __EC_INCLUDE_EXTENSION_H -#define __EC_INCLUDE_EXTENSION_H - -#include <stddef.h> -#include <stdint.h> - -#include "common.h" -#include "tpm_vendor_cmds.h" - -/* Flags for vendor or extension commands */ -enum vendor_cmd_flags { - /* - * Command is coming from the USB interface (either via the vendor - * command endpoint or the console). If this flag is not present, - * the command is coming from the AP. - */ - VENDOR_CMD_FROM_USB = BIT(0), -}; - -/* Parameters for vendor commands */ -struct vendor_cmd_params { - /* Command code */ - enum vendor_cmd_cc code; - - /* On input, data to be processed. On output, response data. */ - void *buffer; - - /* Number of bytes of input data */ - size_t in_size; - - /* - * On input, size of output buffer. On output, actual response size. - * Both in bytes. A single response byte usually indicates an error - * and contains the error code. - */ - size_t out_size; - - /* Flags; zero or more of enum vendor_cmd_flags */ - uint32_t flags; -}; - -/* Type of function handling extension commands. */ -typedef enum vendor_cmd_rc - (*extension_handler)(struct vendor_cmd_params *params); - -/** - * Find handler for an extension command. - * - * Use the interface specific function call in order to check the policies for - * handling the commands on that interface. - * - * @param p Parameters for the command - * @return The return code from processing the command. - */ -uint32_t extension_route_command(struct vendor_cmd_params *p); - - -/* Pointer table */ -struct extension_command { - uint16_t command_code; - extension_handler handler; -} __packed; - -#define DECLARE_EXTENSION_COMMAND(code, func) \ - static enum vendor_cmd_rc \ - func##_wrap(struct vendor_cmd_params *params) \ - { \ - func(params->buffer, params->in_size, \ - ¶ms->out_size); \ - return VENDOR_RC_SUCCESS; \ - } \ - const struct extension_command __keep __no_sanitize_address \ - __extension_cmd_##code \ - __attribute__((section(".rodata.extensioncmds"))) \ - = {.command_code = code, .handler = func##_wrap } - -/* Vendor command which takes params directly */ -#define DECLARE_VENDOR_COMMAND(cmd_code, func) \ - static enum vendor_cmd_rc \ - func##_wrap(struct vendor_cmd_params *params) \ - { \ - return func(params->code, params->buffer, \ - params->in_size, ¶ms->out_size); \ - } \ - const struct extension_command __keep __no_sanitize_address \ - __vendor_cmd_##cmd_code \ - __attribute__((section(".rodata.extensioncmds"))) \ - = {.command_code = cmd_code, .handler = func##_wrap} - -/* Vendor command which takes params as struct */ -#define DECLARE_VENDOR_COMMAND_P(cmd_code, func) \ - const struct extension_command __keep __no_sanitize_address \ - __vendor_cmd_##cmd_code \ - __attribute__((section(".rodata.extensioncmds"))) \ - = {.command_code = cmd_code, .handler = func} - -#endif /* __EC_INCLUDE_EXTENSION_H */ diff --git a/include/hooks.h b/include/hooks.h index 9fd45c2853..0860a58d84 100644 --- a/include/hooks.h +++ b/include/hooks.h @@ -177,15 +177,6 @@ enum hook_type { */ HOOK_BATTERY_SOC_CHANGE, -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1 - /* - * Case-closed debugging configuration changed. - * - * Hook routines are called from the TICK, console, or TPM task. - */ - HOOK_CCD_CHANGE, -#endif - #ifdef CONFIG_USB_SUSPEND /* * Called when there is a change in USB power management status diff --git a/include/link_defs.h b/include/link_defs.h index 5ea500516f..45e9850015 100644 --- a/include/link_defs.h +++ b/include/link_defs.h @@ -56,10 +56,6 @@ extern const struct hook_data __hooks_pwrbtn_change[]; extern const struct hook_data __hooks_pwrbtn_change_end[]; extern const struct hook_data __hooks_battery_soc_change[]; extern const struct hook_data __hooks_battery_soc_change_end[]; -#ifdef CONFIG_CASE_CLOSED_DEBUG_V1 -extern const struct hook_data __hooks_ccd_change[]; -extern const struct hook_data __hooks_ccd_change_end[]; -#endif #ifdef CONFIG_USB_SUSPEND extern const struct hook_data __hooks_usb_change[]; extern const struct hook_data __hooks_usb_change_end[]; diff --git a/include/new_nvmem.h b/include/new_nvmem.h deleted file mode 100644 index 37399702f8..0000000000 --- a/include/new_nvmem.h +++ /dev/null @@ -1,155 +0,0 @@ -/* Copyright 2019 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. - */ -#ifndef __TPM2_NVMEM_TEST_NEW_NVMEM_H -#define __TPM2_NVMEM_TEST_NEW_NVMEM_H - -#include "common.h" -#include "nvmem.h" -#include "nvmem_vars.h" -#include "util.h" - -#define NVMEM_NOT_INITIALIZED ((unsigned int)-1) - -/* - * A totally arbitrary byte limit for space occupied by (key, value) pairs in - * the flash. This is an improvement compared to the legacy case where there - * were just 272 bytes dedicated to the (key, value) pairs storage. - */ -#define MAX_VAR_TOTAL_SPACE 1000 - -/* - * Let's be reasonable: we're unlikely to have keys longer than 40 or so - * bytes, and leave full 255 bytes for the value. Total data space occupied by - * a (key, value) pair is not to exceed the value below. - */ -#define MAX_VAR_BODY_SPACE 300 - -enum nn_object_type { - NN_OBJ_OLD_COPY = 0, - NN_OBJ_TUPLE = 1, - NN_OBJ_TPM_RESERVED = 2, - NN_OBJ_TPM_EVICTABLE = 3, - NN_OBJ_TRANSACTION_DEL = 4, - NN_OBJ_ESCAPE = 5, - NN_OBJ_ERASED = 7, -}; - -/* - * Structure placed at the base of each flash page used for NVMEM storage. - * - * page_number: allows to arrange pages in order they were added - * - * data_offset: the offset of the first element in the page (space above - * page header and below data_offset could be taken by the - * 'tail' of the object stored on the previous page). - * - * page_hash: is used to verify page header integrity - */ -struct nn_page_header { - unsigned int page_number : 21; - unsigned int data_offset : 11; - uint32_t page_hash; -} __packed; - -/* - * Index of the 'virtual' last reserved object. RAM index space and max - * counter objects stored at fixed location in the NVMEM cache are considered - * reserved objects by this NVMEM flash layer. - */ -#define NV_VIRTUAL_RESERVE_LAST (NV_RESERVE_LAST + 2) - -/* - * Container header for all blobs stored in flash. - * - * container_type: type of object stored in the container. MAKE SURE THIS - * FIELD TYPE IS THE FIRST FIELD IN THIS STRUCTURE, it is - * supposed to be in the first word of the container so that - * the type can be erased when object is deleted. - * - * container_type_copy: immutable copy of the container_type field, used to - * verify contents of deleted objects. - * - * encrypted: set to 1 if contents are encrypted. - * - * size: size of the payload, 12 bits allocated, 11 bits would be enough for - * this use case. - * - * generation: a free running counter, used to compare ages of two containers - * - * container_hash: hash of the ENTIRE container, both header and body - * included. This field is set to zero before hash is calculated - */ -struct nn_container { - unsigned int container_type : 3; - unsigned int container_type_copy : 3; - unsigned int encrypted : 1; - unsigned int size : 11; - unsigned int generation : 2; - unsigned int container_hash : 12; -} __packed; - -/* - * A structure to keep context of accessing to a page, page header and offset - * define where the next access would happen. - */ -struct page_tracker { - const struct nn_page_header *ph; - uint16_t data_offset; -}; - -/* - * Helper structure to keep track of accesses to the flash storage. - * - * mt: main tracker for read or write accesses. - * - * ct: keeps track of container fetches, as the location of containers has - * special significance: it is both part of the seed used when - * encrypting/decryping container contents, and also is necessary to - * unwind reading of the container header when the end of storage is - * reached and a header of all 0xff is read. - * - * dt: keeps track of delimiters which is important when assessing flash - * contents integrity. If during startup the last item in flash is not a - * delimiter, this is an indication of a failed transaction, all data - * after the previous delimiter needs to be discarded. - * - * list_index; index of the current page in the list of pages, useful when - * sequential reading and need to get to the next page in the - * list. - */ - -struct access_tracker { - struct page_tracker mt; /* Main tracker. */ - struct page_tracker ct; /* Container tracker. */ - struct page_tracker dt; /* Delimiter tracker.*/ - uint8_t list_index; -}; - -/* - * New nvmem interface functions, each of them could be blocking because each - * of them acquires nvmem flash protectioin mutex before proceeding. - */ -enum ec_error_list new_nvmem_init(void); -enum ec_error_list new_nvmem_migrate(unsigned int nvmem_act_partition); -enum ec_error_list new_nvmem_save(void); -int nvmem_erase_tpm_data(void); - -#if defined(TEST_BUILD) && !defined(TEST_FUZZ) -#define NVMEM_TEST_BUILD -enum ec_error_list browse_flash_contents(int); -enum ec_error_list compact_nvmem(void); -extern struct access_tracker master_at; -extern uint16_t total_var_space; -int is_uninitialized(const void *p, size_t size); -size_t init_object_offsets(uint16_t *offsets, size_t count); -struct nn_page_header *list_element_to_ph(size_t el); -void *evictable_offs_to_addr(uint16_t offset); -enum ec_error_list get_next_object(struct access_tracker *at, - struct nn_container *ch, - int include_deleted); -#endif - - -#endif /* ! __TPM2_NVMEM_TEST_NEW_NVMEM_H */ diff --git a/include/nvmem.h b/include/nvmem.h deleted file mode 100644 index f48c9cd9c4..0000000000 --- a/include/nvmem.h +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright 2016 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. - */ - -#ifndef __CROS_EC_NVMEM_UTILS_H -#define __CROS_EC_NVMEM_UTILS_H - -#include "crypto_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * In order to provide maximum robustness for NvMem operations, the NvMem space - * is divided into two equal sized partitions. A partition contains a tag - * and a buffer for each NvMem user. - * - * NvMem Partiion - * ------------------------------------------------------------------------ - * |36 byte tag | User Buffer 0 | User Buffer 1 | .... | User Buffer N-1 | - * ------------------------------------------------------------------------ - * - * Physical Block Tag details - * ------------------------------------------------------------------------ - * | sha | padding | version | generation | reserved | - * ------------------------------------------------------------------------- - * sha -> 16 bytes of sha1 digest - * padding -> 16 bytes for future extensions - * version -> nvmem layout version, currently at 0 - * generation -> 1 byte generation number (0 - 0xfe) - * reserved -> 2 bytes - * - * At initialization time, each partition is scanned to see if it has a good sha - * entry. One of the two partitions being valid is a supported condition. If - * neither partiion is valid a new partition is created with generation set to - * zero. - * - * Note that the NvMem partitions can be placed anywhere in flash space, but - * must be equal in total size. A table is used by the NvMem module to get the - * correct base address for each partition. - * - * A generation number is used to distinguish between two valid partitions with - * the newsest generation number (in a circular sense) marking the correct - * partition to use. The parition number 0/1 is tracked via a static - * variable. When the NvMem contents need to be updated, the flash erase/write - * of the updated partition will use the inactive partition space in NvMem. This - * way if there is a critical failure (i.e. loss of power) during the erase or - * write operation, then the contents of the active partition prior the most - * recent writes will still be preserved. - * - * The following CONFIG_FLASH_NVMEM_ defines are required for this module: - * CONFIG_FLASH_NVMEM -> enable/disable the module - * CONFIG_FLASH_NVMEM_OFFSET_(A|B) -> offset to start of each partition - * CONFIG_FLASH_NVMEM_BASE_(A|B) -> address of start of each partition - * - * The board.h file must define a macro or enum named NVMEM_NUM_USERS. - * The board.c file must implement: - * nvmem_user_sizes[] -> array of user buffer lengths - * The chip must provide - * app_compute_hash() -> function used to compute 16 byte sha (or equivalent) - * - * Note that total length of user buffers must satisfy the following: - * sum(user sizes) <= (NVMEM_PARTITION_SIZE) - sizeof(struct nvmem_tag) - */ - -/* NvMem user buffer length table */ -extern uint32_t nvmem_user_sizes[NVMEM_NUM_USERS]; - -#define NVMEM_NUM_PARTITIONS 2 -#define NVMEM_SHA_SIZE CIPHER_SALT_SIZE -#define NVMEM_GENERATION_BITS 8 -#define NVMEM_GENERATION_MASK (BIT(NVMEM_GENERATION_BITS) - 1) -#define NVMEM_PADDING_SIZE 16 -#define NVMEM_LAYOUT_VERSION 0 - -/* Struct for NV block tag */ -struct nvmem_tag { - uint8_t sha[NVMEM_SHA_SIZE]; - uint8_t padding[NVMEM_PADDING_SIZE]; - uint8_t layout_version; - uint8_t generation; - uint8_t reserved[2]; -}; - -/* Structure MvMem Partition */ -struct nvmem_partition { - struct nvmem_tag tag; - uint8_t buffer[NVMEM_PARTITION_SIZE - - sizeof(struct nvmem_tag)]; -}; - -/** - * Initialize NVMem translation table and state variables - * - * @return EC_SUCCESS if a valid translation table is constructed, else - * error code. - */ -int nvmem_init(void); - -/** - * Get Nvmem internal error state - * - * @return nvmem_error_state variable. - */ -int nvmem_get_error_state(void); - -/** - * Compare 'size' amount of bytes in NvMem - * - * @param offset: Offset (in bytes) into NVmem logical space - * @param size: Number of bytes to compare - * @param data: Pointer to data to be compared with - * @param user: Data section within NvMem space - * @return 0 if the data is same, non-zero if data is different - */ -int nvmem_is_different(uint32_t offset, uint32_t size, - void *data, enum nvmem_users user); - -/** - * Read 'size' amount of bytes from NvMem - * - * @param startOffset: Offset (in bytes) into NVmem logical space - * @param size: Number of bytes to read - * @param data: Pointer to destination buffer - * @param user: Data section within NvMem space - * @return EC_ERROR_OVERFLOW (non-zero) if the read operation would exceed the - * buffer length of the given user, otherwise EC_SUCCESS. - */ -int nvmem_read(uint32_t startOffset, uint32_t size, - void *data, enum nvmem_users user); - -/** - * Write 'size' amount of bytes to NvMem - * - * Calling this function will wait for the mutex, then lock it until - * nvmem_commit() is invoked. - * - * @param startOffset: Offset (in bytes) into NVmem logical space - * @param size: Number of bytes to write - * @param data: Pointer to source buffer - * @param user: Data section within NvMem space - * @return EC_ERROR_OVERFLOW if write exceeds buffer length - * EC_ERROR_TIMEOUT if nvmem cache buffer is not available - * EC_SUCCESS if no errors. - */ -int nvmem_write(uint32_t startOffset, uint32_t size, - void *data, enum nvmem_users user); - -/** - * Move 'size' amount of bytes within NvMem - * - * Calling this function will wait for the mutex, then lock it until - * nvmem_commit() is invoked. - * - * @param src_offset: source offset within NvMem logical space - * @param dest_offset: destination offset within NvMem logical space - * @param size: Number of bytes to move - * @param user: Data section within NvMem space - * @return EC_ERROR_OVERFLOW if write exceeds buffer length - * EC_ERROR_TIMEOUT if nvmem cache buffer is not available - * EC_SUCCESS if no errors. - */ -int nvmem_move(uint32_t src_offset, uint32_t dest_offset, uint32_t size, - enum nvmem_users user); -/** - * Commit all previous NvMem writes to flash - * - * @return EC_SUCCESS if flash erase/operations are successful. - - * EC_ERROR_OVERFLOW in case the mutex is not locked when this - * function is called - * EC_ERROR_INVAL if task trying to commit is not the one - * holding the mutex - * EC_ERROR_UNKNOWN in other error cases - */ -int nvmem_commit(void); - -/* - * Temporarily stopping NVMEM commits could be beneficial. One use case is - * when TPM operations need to be sped up. - * - * Calling this function will wait for the mutex, then lock it until - * nvmem_commit() is invoked. - * - * Both below functions should be called from the same task. - */ -void nvmem_disable_commits(void); - -/* - * Only the task holding the mutex is allowed to enable commits. - * - * @return error if this task does not hold the lock or commit - * fails, EC_SUCCESS otherwise. - */ -int nvmem_enable_commits(void); - -/* - * Function to retrieve the base address of the nvmem cache of the appropriate - * user. After migration there is only one user and one base address, this - * function will be eliminated. - * - * @return pointer to the base address. - */ -void *nvmem_cache_base(enum nvmem_users user); - -/* - * Clear all NVMEM cache in SRAM. - */ -void nvmem_clear_cache(void); - -void nvmem_wipe_cache(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __CROS_EC_NVMEM_UTILS_H */ diff --git a/include/nvmem_vars.h b/include/nvmem_vars.h deleted file mode 100644 index 08bd9164c8..0000000000 --- a/include/nvmem_vars.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright 2016 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. - */ - -#ifndef __EC_INCLUDE_NVMEM_VARS_H -#define __EC_INCLUDE_NVMEM_VARS_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * CONFIG_FLASH_NVMEM provides persistent, atomic-update storage in - * flash. The storage is logically divided into one or more "user regions", as - * configured in board.h and board.c - * - * CONFIG_FLASH_NVMEM_VARS stores a set of <KEY, VALUE> tuples in the nvmem - * user region designated by CONFIG_FLASH_NVMEM_VARS_USER_NUM (in board.h) - * - * Tuples are stored and managed using this struct: - */ - -struct tuple { - uint8_t key_len; /* 1 - 255 */ - uint8_t val_len; /* 1 - 255 */ - uint8_t flags; /* RESERVED, will be zeroed */ - uint8_t data_[0]; /* Opaque. Don't look here. */ -}; - -/* - * Both KEY and VALUE can be any binary blob between 1 and 255 bytes (flash - * memory is limited, so if you need longer values just use two keys and - * concatenate the blobs). Zero-length KEYs or VALUEs are not allowed. - * Assigning a zero-length VALUE to a KEY just deletes that tuple (if it - * existed). - * - * The expected usage is: - * - * 1. At boot, call initvars() to ensure that the variable storage region is - * valid. If it isn't, this will initialize it to an empty set. - * - * 2. Call getenv() or setenv() as needed. The first call to either will copy - * the storage regsion from flash into a RAM buffer. Any changes made with - * setenv() will affect only that RAM buffer. - * - * 3. Call writevars() to commit the RAM buffer to flash and free it. - * - * CAUTION: The underlying CONFIG_FLASH_NVMEM implementation allows access by - * multiple tasks, provided each task access only one user region. There is no - * support for simultaneous access to the *same* user region by multiple tasks. - * CONFIG_FLASH_NVMEM_VARS stores all variables in one user region, so if - * variable access by multiple tasks is required, the tasks should establish - * their own locks or mutexes to fit their usage. In general that would mean - * aquiring a lock before calling getvar() or setvar(), and releasing it after - * calling writevars(). - */ - -/* - * Initialize the persistent storage. This checks the user region to ensure - * that all tuples are valid and that there is one additional '\0' at the end. - * If any discrepancies are found, it erases all values. This should return - * EC_SUCCESS unless there is a problem writing to flash. - */ -int initvars(void); - -/* - * Look up the key passed in the input tuple and fill the value, if found. - * - * The val_len field in the passed in tuple indicates how much room is - * available, the actual value size could be smaller. - * - * Could block as it acquires the flash protection mutex before proceeding. - * - * Return: - * - * EC_SUCCESS - if the key was found and there was enough room in the passed - * in tuple for the value. - * EC_ERROR_INVAL - if the key was not found. - * - * EC_ERROR_MEMORY_ALLOCATION - if the value would not fit into the supplied - * tuple. - */ -const struct tuple *getvar(const uint8_t *key, uint8_t key_len); - -/* - * Free memory held by the previously read tuple. - * - * Note that tuple address is not the address to be returned to the heap, so - * the user must use this function to free this memory. If var is NULL this - * function is a no-op. - * - */ -void freevar(const struct tuple *var); - -/* Use these to access the data components of a valid struct tuple pointer */ -const uint8_t *tuple_key(const struct tuple *); -const uint8_t *tuple_val(const struct tuple *); - -/* - * Save the tuple in the RAM buffer. If val is NULL or val_len is 0, the - * tuple is deleted (if it existed). Returns EC_SUCCESS or error code. - * - * Could block as it acquires the flash protection mutex before proceeding. - */ -int setvar(const uint8_t *key, uint8_t key_len, - const uint8_t *val, uint8_t val_len); - -/* - * Commit any changes made with setvar() to persistent memory, and invalidate - * the RAM buffer. Return EC_SUCCESS or error code on failure. - */ -int writevars(void); - -/* - * A fully contained function which does not use any available nvmem_vars - * methods, as it is used solely for retrieving vars from legacy storage - * format. Runs only during migration. - */ -const struct tuple *legacy_getnextvar(const struct tuple *prev_var); - -int set_local_copy(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __EC_INCLUDE_NVMEM_VARS_H */ diff --git a/include/pinweaver.h b/include/pinweaver.h deleted file mode 100644 index 21571da7b0..0000000000 --- a/include/pinweaver.h +++ /dev/null @@ -1,188 +0,0 @@ -/* Copyright 2018 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. - */ - -#ifndef __CROS_EC_INCLUDE_PINWEAVER_H -#define __CROS_EC_INCLUDE_PINWEAVER_H - -/* This is required before pinweaver_types.h to provide __packed and __aligned - * while preserving the ability of pinweaver_types.h to be used in code outside - * of src/platform/ec. - */ -#include <common.h> -#include <pinweaver_types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define PW_STORAGE_VERSION 0 - -#define BITS_PER_LEVEL_MIN 1 -#define BITS_PER_LEVEL_MAX 5 -#define HEIGHT_MIN 1 -/* This will crash for logk == 0 so that condition must not be allowed when - * using this. - */ -#define HEIGHT_MAX(logk) ((sizeof(struct label_t) * 8) / logk) - -#define PW_LOG_ENTRY_COUNT 2 - -/* Persistent information used by this feature. */ -struct merkle_tree_t { - /* log2(Fan out). */ - struct bits_per_level_t bits_per_level; - /* Height of the tree or param_l / bits_per_level. */ - struct height_t height; - - /* Root hash of the Merkle tree. */ - uint8_t root[PW_HASH_SIZE]; - - /* Random bits used as part of the key derivation process. */ - uint8_t key_derivation_nonce[16]; - - /* Key used to compute the HMACs of the metadata of the leaves. */ - uint8_t PW_ALIGN_TO_WRD hmac_key[32]; - - /* Key used to encrypt and decrypt the metadata of the leaves. */ - uint8_t PW_ALIGN_TO_WRD wrap_key[32]; -}; - -/* Long term flash storage for tree metadata. */ -struct PW_PACKED pw_long_term_storage_t { - uint16_t storage_version; - - /* log2(Fan out). */ - struct bits_per_level_t bits_per_level; - /* Height of the tree or param_l / bits_per_level. */ - struct height_t height; - - /* Random bits used as part of the key derivation process. */ - uint8_t key_derivation_nonce[16]; -}; - -struct PW_PACKED pw_log_storage_t { - uint16_t storage_version; - uint32_t restart_count; - struct pw_get_log_entry_t entries[PW_LOG_ENTRY_COUNT]; -}; - -/* Do not remove fields within the same PW_LEAF_MAJOR_VERSION. */ -/* Encrypted part of the leaf data. - */ -struct PW_PACKED PW_ALIGN_TO_BLK leaf_sensitive_data_t { - uint8_t low_entropy_secret[PW_SECRET_SIZE]; - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - uint8_t reset_secret[PW_SECRET_SIZE]; -}; - -/* Represents leaf data in a form that can be exported for storage. */ -struct PW_PACKED wrapped_leaf_data_t { - /* This is first so that head.leaf_version will be the first field - * in the struct to keep the meaning of the struct from becoming - * ambiguous across versions. - */ - struct leaf_header_t head; - /* Covers .head, .pub, and .cipher_text. */ - uint8_t hmac[PW_HASH_SIZE]; - uint8_t iv[PW_WRAP_BLOCK_SIZE]; - struct leaf_public_data_t pub; - uint8_t cipher_text[sizeof(struct leaf_sensitive_data_t)]; -}; - -/* Represents encrypted leaf data after the lengths and version in the header - * have been validated. - */ -struct imported_leaf_data_t { - /* This is first so that head.leaf_version will be the first field - * in the struct to keep the meaning of the struct from becoming - * ambiguous across versions. - */ - const struct leaf_header_t *head; - /* Covers .head, .pub, and .cipher_text. */ - const uint8_t *hmac; - const uint8_t *iv; - const struct leaf_public_data_t *pub; - const uint8_t *cipher_text; - const uint8_t (*hashes)[PW_HASH_SIZE]; -}; - -/* The leaf data in a clear text working format. */ -struct leaf_data_t { - struct leaf_public_data_t pub; - struct leaf_sensitive_data_t sec; -}; - -/* Key names for nvmem_vars */ -#define PW_TREE_VAR "pwT0" -#define PW_LOG_VAR0 "pwL0" -/* The maximum key-value pair space allowed for the values of PinWeaver until - * the Cr50 NVRAM implementation is updated to use a separate object per - * key value pair. - */ -#define PW_MAX_VAR_USAGE 192 - -/* Initializes the PinWeaver feature. - * - * This needs to be called prior to handling any messages. - */ -void pinweaver_init(void); - -/* Handler for incoming messages after they have been reconstructed. - * - * merkle_tree->root needs to be updated with new_root outside of this function. - */ -int pw_handle_request(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request, - struct pw_response_t *response); - -/******************************************************************************/ -/* Struct helper functions. - */ - -/* Sets up pointers to the relevant fields inside an wrapped leaf based on the - * length fields in the header. These fields should be validated prior to - * calling this function. - */ -void import_leaf(const struct unimported_leaf_data_t *unimported, - struct imported_leaf_data_t *imported); - -/* Calculate how much is needed to add to the size of structs containing - * an struct unimported_leaf_data_t because the variable length fields at the - * end of the struct are not included by sizeof(). - */ -#define PW_LEAF_PAYLOAD_SIZE (sizeof(struct wrapped_leaf_data_t) - \ - sizeof(struct unimported_leaf_data_t)) - - -/******************************************************************************/ -/* Utility functions exported for better test coverage. - */ - -/* Computes the total number of the sibling hashes along a path. */ -int get_path_auxiliary_hash_count(const struct merkle_tree_t *merkle_tree); - -/* Computes the parent hash for an array of child hashes. */ -void compute_hash(const uint8_t hashes[][PW_HASH_SIZE], uint16_t num_hashes, - struct index_t location, - const uint8_t child_hash[PW_HASH_SIZE], - uint8_t result[PW_HASH_SIZE]); - -/* This should only be used in tests. */ -void force_restart_count(uint32_t mock_value); - -/* NV RAM log functions exported for use in test code. */ -int store_log_data(const struct pw_log_storage_t *log); -int store_merkle_tree(const struct merkle_tree_t *merkle_tree); -int log_insert_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE], - const uint8_t hmac[PW_HASH_SIZE]); -int log_remove_leaf(struct label_t label, const uint8_t root[PW_HASH_SIZE]); -int log_auth(struct label_t label, const uint8_t root[PW_HASH_SIZE], int code, - struct pw_timestamp_t timestamp); - -#ifdef __cplusplus -} -#endif - -#endif /* __CROS_EC_INCLUDE_PINWEAVER_H */ diff --git a/include/pinweaver_tpm_imports.h b/include/pinweaver_tpm_imports.h deleted file mode 100644 index f1ecd24202..0000000000 --- a/include/pinweaver_tpm_imports.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Compatibility layer between the TPM code and PinWeaver. - * - * This is needed because the headers for the TPM are not compatible with the - * headers used by pinweaver.c. It also makes it easier to mock the - * functionality derived from the TPM code. - */ - -#ifndef __CROS_EC_INCLUDE_PINWEAVER_TPM_IMPORTS_H -#define __CROS_EC_INCLUDE_PINWEAVER_TPM_IMPORTS_H - -#include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is used to get the storage seed from the TPM implementation so - * TPM_Clear() will break the keys used by PinWeaver so that any metadata - * that persists on the machine storage is unusable by attackers. - */ -void get_storage_seed(void *buf, size_t *len); - -/* Reads PCR values for indexes from bitmask and computes sha256 digest of - * concatenated values. Populates the digest in |sha256_of_selected_pcr|. - */ -uint8_t get_current_pcr_digest(const uint8_t bitmask[2], - uint8_t sha256_of_selected_pcr[32]); - -#ifdef __cplusplus -} -#endif - -#endif /* __CROS_EC_INCLUDE_PINWEAVER_TPM_IMPORTS_H */ diff --git a/include/pinweaver_types.h b/include/pinweaver_types.h deleted file mode 100644 index e8787eb29a..0000000000 --- a/include/pinweaver_types.h +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright 2018 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. - */ - -/* Shared types between Cr50 and the AP side code. */ - -#ifndef __CROS_EC_INCLUDE_PINWEAVER_TYPES_H -#define __CROS_EC_INCLUDE_PINWEAVER_TYPES_H - -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif - -#define PW_PACKED __packed - -#define PW_PROTOCOL_VERSION 1 -#define PW_LEAF_MAJOR_VERSION 0 -/* The change from version zero is the addition of valid_pcr_value metadata */ -#define PW_LEAF_MINOR_VERSION 1 - -#define PW_MAX_MESSAGE_SIZE (2048 - 12 /* sizeof(struct tpm_cmd_header) */) - -/* The block size of encryption used for wrapped_leaf_data_t. */ -#define PW_WRAP_BLOCK_SIZE 16 - -#define PW_ALIGN_TO_WRD __aligned(4) - -#define PW_ALIGN_TO_BLK __aligned(PW_WRAP_BLOCK_SIZE) - -enum pw_error_codes_enum { - PW_ERR_VERSION_MISMATCH = 0x10000, /* EC_ERROR_INTERNAL_FIRST */ - PW_ERR_TREE_INVALID, - PW_ERR_LENGTH_INVALID, - PW_ERR_TYPE_INVALID, - PW_ERR_BITS_PER_LEVEL_INVALID, - PW_ERR_HEIGHT_INVALID, - PW_ERR_LABEL_INVALID, - PW_ERR_DELAY_SCHEDULE_INVALID, - PW_ERR_PATH_AUTH_FAILED, - PW_ERR_LEAF_VERSION_MISMATCH, - PW_ERR_HMAC_AUTH_FAILED, - PW_ERR_LOWENT_AUTH_FAILED, - PW_ERR_RESET_AUTH_FAILED, - PW_ERR_CRYPTO_FAILURE, - PW_ERR_RATE_LIMIT_REACHED, - PW_ERR_ROOT_NOT_FOUND, - PW_ERR_NV_EMPTY, - PW_ERR_NV_LENGTH_MISMATCH, - PW_ERR_NV_VERSION_MISMATCH, - PW_ERR_PCR_NOT_MATCH, -}; - -/* Represents the log2(fan out) of a tree. */ -struct PW_PACKED bits_per_level_t { - uint8_t v; -}; - - /* Represent the height of a tree. */ -struct PW_PACKED height_t { - uint8_t v; -}; - -/* Represents a child index of a node in a tree. */ -struct PW_PACKED index_t { - uint8_t v; -}; - -/* Represents the child index for each level of a tree along a path to a leaf. - * It is a Little-endian unsigned integer with the following value (MSB->LSB) - * | Zero padding | 1st level index | ... | leaf index |, - * where each index is represented by bits_per_level bits. - */ -struct PW_PACKED label_t { - uint64_t v; -}; - -/* Represents a count of failed login attempts. This is capped at UINT32_MAX. */ -struct PW_PACKED attempt_count_t { - uint32_t v; -}; - -/* Represents a notion of time. */ -struct PW_PACKED pw_timestamp_t { - /* Number of boots. This is used to track if Cr50 has rebooted since - * timer_value was recorded. - */ - uint32_t boot_count; - /* Seconds since boot. */ - uint64_t timer_value; -}; - -/* Represents a time interval in seconds. - * - * This only needs to be sufficiently large to represent the longest time - * between allowed attempts. - */ -struct PW_PACKED time_diff_t { - uint32_t v; -}; -#define PW_BLOCK_ATTEMPTS UINT32_MAX - -/* Number of bytes required for a hash or hmac value in the merkle tree. */ -#define PW_HASH_SIZE 32 - -/* Represents a single entry in a delay schedule table. */ -struct PW_PACKED delay_schedule_entry_t { - struct attempt_count_t attempt_count; - struct time_diff_t time_diff; -}; - -/* Represents a set of PCR values hashed into a single digest. This is a - * criterion that can be added to a leaf. A leaf is valid only if at least one - * of the valid_pcr_value_t criteria it contains is satisfied. - */ -struct PW_PACKED valid_pcr_value_t { - /* The set of PCR indexes that have to pass the validation. */ - uint8_t bitmask[2]; - /* The hash digest of the PCR values contained in the bitmask */ - uint8_t digest[32]; -}; - -/* Represents the number of entries in the delay schedule table which can be - * used to determine the next time an authentication attempt can be made. - */ -#define PW_SCHED_COUNT 16 - -/* Represents the maximum number of criteria for valid PCR values. - */ -#define PW_MAX_PCR_CRITERIA_COUNT 2 - -/* Number of bytes required to store a secret. - */ -#define PW_SECRET_SIZE 32 - -struct PW_PACKED leaf_version_t { - /* minor comes first so this struct will be compatibile with uint32_t - * comparisons for little endian to make version comparisons easier. - * - * Changes to minor versions are allowed to add new fields, but not - * remove existing fields, and they are allowed to be interpreted by - * previous versions---any extra fields are truncated. - * - * Leafs will reject future major versions assuming they are - * incompatible, so fields in struct leaf_public_data_t and - * struct leaf_sensitive_data_t may be removed for new major versions. - * Upgrades across major versions will require explicit logic to - * map the old struct to the new struct or vice versa. - */ - uint16_t minor; - uint16_t major; -}; - -/* Do not change this within the same PW_LEAF_MAJOR_VERSION. */ -struct PW_PACKED leaf_header_t { - /* Always have leaf_version at the beginning of - * struct wrapped_leaf_data_t to maintain preditable behavior across - * versions. - */ - struct leaf_version_t leaf_version; - uint16_t pub_len; - uint16_t sec_len; -}; - -/* Do not remove fields within the same PW_LEAF_MAJOR_VERSION. */ -/* Unencrypted part of the leaf data. - */ -struct PW_PACKED leaf_public_data_t { - struct label_t label; - struct delay_schedule_entry_t delay_schedule[PW_SCHED_COUNT]; - - /* State used to rate limit. */ - struct pw_timestamp_t timestamp; - struct attempt_count_t attempt_count; - struct valid_pcr_value_t valid_pcr_criteria[PW_MAX_PCR_CRITERIA_COUNT]; -}; - -/* Represents a struct of unknown length to be imported to process a request. */ -struct PW_PACKED unimported_leaf_data_t { - /* This is first so that head.leaf_version will be the first field - * in the struct to make handling different struct versions easier. - */ - struct leaf_header_t head; - /* Covers .head, .iv, and .payload (excluding path_hashes) */ - uint8_t hmac[PW_HASH_SIZE]; - uint8_t iv[PW_WRAP_BLOCK_SIZE]; - /* This field is treated as having a zero size by the compiler so the - * actual size needs to be added to the size of this struct. This allows - * for forward compatibility using the pub_len and sec_len fields in the - * header. - * - * Has following layout: - * Required: - * uint8_t pub_data[head.pub_len]; - * uint8_t ciphter_text[head.sec_len]; - * - * For Requests only: - * uint8_t path_hashes[get_path_auxiliary_hash_count(.)][PW_HASH_SIZE]; - */ - uint8_t payload[]; -}; - -/******************************************************************************/ -/* Message structs - * - * The message format is a pw_request_header_t followed by the data - */ - -enum pw_message_type_enum { - PW_MT_INVALID = 0, - - /* Request / "Question" types. */ - PW_RESET_TREE = 1, - PW_INSERT_LEAF, - PW_REMOVE_LEAF, - PW_TRY_AUTH, - PW_RESET_AUTH, - PW_GET_LOG, - PW_LOG_REPLAY, -}; - -struct PW_PACKED pw_message_type_t { - uint8_t v; -}; - -struct PW_PACKED pw_request_header_t { - uint8_t version; - struct pw_message_type_t type; - uint16_t data_length; -}; - -struct PW_PACKED pw_response_header_t { - uint8_t version; - uint16_t data_length; /* Does not include the header. */ - uint32_t result_code; - uint8_t root[PW_HASH_SIZE]; -}; - -struct PW_PACKED pw_request_reset_tree_t { - struct bits_per_level_t bits_per_level; - struct height_t height; -}; - -/* This is only used for parsing incoming data of version 0:0 */ -struct PW_PACKED pw_request_insert_leaf00_t { - struct label_t label; - struct delay_schedule_entry_t delay_schedule[PW_SCHED_COUNT]; - uint8_t low_entropy_secret[PW_SECRET_SIZE]; - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - uint8_t reset_secret[PW_SECRET_SIZE]; - /* This is a variable length field because it size is determined at - * runtime based on the chosen tree parameters. Its size is treated as - * zero by the compiler so the computed size needs to be added to the - * size of this struct in order to determine the actual size. This field - * has the form: - * uint8_t path_hashes[get_path_auxiliary_hash_count(.)][PW_HASH_SIZE]; - */ - uint8_t path_hashes[][PW_HASH_SIZE]; -}; - -struct PW_PACKED pw_request_insert_leaf_t { - struct label_t label; - struct delay_schedule_entry_t delay_schedule[PW_SCHED_COUNT]; - uint8_t low_entropy_secret[PW_SECRET_SIZE]; - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - uint8_t reset_secret[PW_SECRET_SIZE]; - struct valid_pcr_value_t valid_pcr_criteria[PW_MAX_PCR_CRITERIA_COUNT]; - /* This is a variable length field because it size is determined at - * runtime based on the chosen tree parameters. Its size is treated as - * zero by the compiler so the computed size needs to be added to the - * size of this struct in order to determine the actual size. This field - * has the form: - * uint8_t path_hashes[get_path_auxiliary_hash_count(.)][PW_HASH_SIZE]; - */ - uint8_t path_hashes[][PW_HASH_SIZE]; -}; - -struct PW_PACKED pw_response_insert_leaf_t { - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_request_remove_leaf_t { - struct label_t leaf_location; - uint8_t leaf_hmac[PW_HASH_SIZE]; - /* See (struct pw_request_insert_leaf_t).path_hashes. */ - uint8_t path_hashes[][PW_HASH_SIZE]; -}; - -struct PW_PACKED pw_request_try_auth_t { - uint8_t low_entropy_secret[PW_SECRET_SIZE]; - struct unimported_leaf_data_t unimported_leaf_data; -}; - -/* This is only used to send response data of version 0:0 */ -struct PW_PACKED pw_response_try_auth00_t { - /* Valid for the PW_ERR_RATE_LIMIT_REACHED return code only. */ - struct time_diff_t seconds_to_wait; - /* Valid for the EC_SUCCESS return code only. */ - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - /* Valid for the PW_ERR_LOWENT_AUTH_FAILED and EC_SUCCESS return codes. - */ - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_response_try_auth_t { - /* Valid for the PW_ERR_RATE_LIMIT_REACHED return code only. */ - struct time_diff_t seconds_to_wait; - /* Valid for the EC_SUCCESS return code only. */ - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - /* Valid for the EC_SUCCESS return code only. */ - uint8_t reset_secret[PW_SECRET_SIZE]; - /* Valid for the PW_ERR_LOWENT_AUTH_FAILED and EC_SUCCESS return codes. - */ - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_request_reset_auth_t { - uint8_t reset_secret[PW_SECRET_SIZE]; - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_response_reset_auth_t { - uint8_t high_entropy_secret[PW_SECRET_SIZE]; - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_request_get_log_t { - /* The root on the CrOS side that needs to be brought back in sync with - * the root on Cr50. If this doesn't match a log entry, the entire log - * is returned. - */ - uint8_t root[PW_HASH_SIZE]; -}; - -struct PW_PACKED pw_request_log_replay_t { - /* The root hash after the desired log event. - * The log entry that matches this hash contains all the necessary - * data to update wrapped_leaf_data - */ - uint8_t log_root[PW_HASH_SIZE]; - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_response_log_replay_t { - struct unimported_leaf_data_t unimported_leaf_data; -}; - -struct PW_PACKED pw_get_log_entry_t { - /* The root hash after this operation. */ - uint8_t root[PW_HASH_SIZE]; - /* The label of the leaf that was operated on. */ - struct label_t label; - /* The type of operation. This should be one of - * PW_INSERT_LEAF, - * PW_REMOVE_LEAF, - * PW_TRY_AUTH. - * - * Successful PW_RESET_AUTH events are included - */ - struct pw_message_type_t type; - /* Type specific fields. */ - union { - /* PW_INSERT_LEAF */ - uint8_t leaf_hmac[PW_HASH_SIZE]; - /* PW_REMOVE_LEAF */ - /* PW_TRY_AUTH */ - struct PW_PACKED { - struct pw_timestamp_t timestamp; - int32_t return_code; - }; - }; -}; - -struct PW_PACKED pw_request_t { - struct pw_request_header_t header; - union { - struct pw_request_reset_tree_t reset_tree; - struct pw_request_insert_leaf00_t insert_leaf00; - struct pw_request_insert_leaf_t insert_leaf; - struct pw_request_remove_leaf_t remove_leaf; - struct pw_request_try_auth_t try_auth; - struct pw_request_reset_auth_t reset_auth; - struct pw_request_get_log_t get_log; - struct pw_request_log_replay_t log_replay; - } data; -}; - -struct PW_PACKED pw_response_t { - struct pw_response_header_t header; - union { - - struct pw_response_insert_leaf_t insert_leaf; - struct pw_response_try_auth00_t try_auth00; - struct pw_response_try_auth_t try_auth; - struct pw_response_reset_auth_t reset_auth; - /* An array with as many entries as are present in the log up to - * the present time or will fit in the message. - */ - uint8_t get_log[0]; - struct pw_response_log_replay_t log_replay; - } data; -}; - -/* An explicit limit is set because struct unimported_leaf_data_t can have more - * than one variable length field so the max length for these fields needs to be - * defined so that meaningful parameter limits can be set to validate the tree - * parameters. - * - * 1024 was chosen because it is 1/2 of 2048 and allows for a maximum tree - * height of 10 for the default fan-out of 4. - */ -#define PW_MAX_PATH_SIZE 1024 - -#ifdef __cplusplus -} -#endif - -#endif /* __CROS_EC_INCLUDE_PINWEAVER_TYPES_H */ diff --git a/include/tpm_manufacture.h b/include/tpm_manufacture.h deleted file mode 100644 index 4d62bb0e3b..0000000000 --- a/include/tpm_manufacture.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright 2016 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. - */ - -/* - * This header declares the TPM manufacture related interface. - * Individual boards are expected to provide implementations. - */ - -#ifndef __CROS_EC_TPM_MANUFACTURE_H -#define __CROS_EC_TPM_MANUFACTURE_H - -/* Returns non-zero if the TPM manufacture steps have been completed. */ -int tpm_manufactured(void); - -/* Codes for success and various manufacturing error conditions. */ -enum manufacturing_status { - mnf_success = 0, - mnf_no_certs = 1, - mnf_eps_decr = 2, - mnf_bad_rsa_size = 3, - mnf_bad_total_size = 4, - mnf_bad_rsa_type = 5, - mnf_bad_ecc_type = 6, - mnf_hmac_mismatch = 7, - mnf_rsa_proc = 8, - mnf_ecc_proc = 9, - mnf_store = 10, - mnf_manufactured = 11, - mnf_unverified_cert = 12, -}; - -enum manufacturing_status tpm_endorse(void); - -#endif /* __CROS_EC_TPM_MANUFACTURE_H */ diff --git a/include/tpm_nvmem.h b/include/tpm_nvmem.h deleted file mode 100644 index 2508c9ae65..0000000000 --- a/include/tpm_nvmem.h +++ /dev/null @@ -1,13 +0,0 @@ -/* Copyright 2018 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. - * - * TPM NVMEM definitions. - */ -#ifndef __CROS_EC_TPM_NVMEM_H -#define __CROS_EC_TPM_NVMEM_H - -#define FIRMWARE_NV_INDEX 0x1007 -#define FWMP_NV_INDEX 0x100a - -#endif /* __CROS_EC_TPM_NVMEM_H */ diff --git a/include/tpm_registers.h b/include/tpm_registers.h deleted file mode 100644 index dcdbe41566..0000000000 --- a/include/tpm_registers.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2015 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. - */ - -/* - * This defines the interface functions for TPM SPI Hardware Protocol. The SPI - * master reads or writes between 1 and 64 bytes to a register designated by a - * 24-bit address. There is no provision for error reporting at this level. - */ - -#ifndef __CROS_EC_TPM_REGISTERS_H -#define __CROS_EC_TPM_REGISTERS_H - -#include <stdint.h> - -#include "common.h" - -/* The SPI master is writing data into a TPM register. */ -void tpm_register_put(uint32_t regaddr, - const uint8_t *data, uint32_t data_size); - -/* The SPI master is reading data from a TPM register. */ -void tpm_register_get(uint32_t regaddr, uint8_t *dest, uint32_t data_size); - -/* Get the current value of the burst size field of the status register. */ -size_t tpm_get_burst_size(void); - -/* - * Register functions to start and stop TPM communications layer. The - * communications layer should be kept down while TPM is being reset. - */ -typedef void (*interface_control_func)(void); -void tpm_register_interface(interface_control_func interface_start, - interface_control_func interface_stop); - -/* - * This requests the TPM task to reset itself. - * - * If wait_until_done is false, it returns EC_SUCCESS immediately. Otherwise it - * returns EC_SUCCESS after the reset has completed, or an error code on - * failure. - * - * If wipe_nvmem_first is true, the caller is expected to keep the rest of the - * system in reset until TPM wipeout is completed. - */ -int tpm_reset_request(int wait_until_done, int wipe_nvmem_first); - -/* - * Tell the TPM task to re-enable nvmem commits. - * - * NOTE: This function is NOT to be used freely, but only meant to be used in - * exceptional cases such as unlocking the console following a TPM wipe. - */ -void tpm_reinstate_nvmem_commits(void); - -/* - * To be called by functions running on the TPM task context. Returns - * EC_SUCCESS on successful reset. - */ -int tpm_sync_reset(int wipe_first); - -/* - * It shuts down the tpm interface, until next tpm reset event. - */ -void tpm_stop(void); - -/* - * This structure describes the header of all commands and responses sent and - * received over TPM FIFO. - * - * Note that all fields are stored in the network (big endian) byte order. - */ - -struct tpm_cmd_header { - uint16_t tag; - uint32_t size; - uint32_t command_code; - uint16_t subcommand_code; /* Not a standard field. */ -} __packed; - -/* - * This function allows to process a TPM command coming from elsewhere, not - * from the communications interface. - * - * A common use case would be making cryptographic calculation on task - * contexts where stack the size is not large enough, for instance console - * commands. This function will block to let the TPM task a chance to run to - * execute the command and return the result in the same buffer. - * - * @param tpmh pointer to a buffer containing a marshalled TPM command, if it - * arrived over the communications channel. One of the header - * fields defines the command size. - * - * @param buffer_size the size of the buffer pointed to by tpmh - tells the - * TPM task how much room there is to store the response. - * - * Command execution result is reported in the response body. - * - * The extension command handler will consider all these commands to come from - * the USB interface, since the only current users for this are console - * commands. - */ -void tpm_alt_extension(struct tpm_cmd_header *tpmh, size_t buffer_size); - -/* - * The only TPM2 command we care about on the driver level, see - * crosbug.com/p/55667 for detals. - */ -#define TPM2_PCR_Read 0x0000017e -#define TPM2_Startup 0x00000144 - -/* TPM mode */ -enum tpm_modes { - TPM_MODE_ENABLED_TENTATIVE = 0, - TPM_MODE_ENABLED = 1, - TPM_MODE_DISABLED = 2, - TPM_MODE_MAX, -}; - -/* - * This function returns the current TPM_MODE value. - */ -enum tpm_modes get_tpm_mode(void); - -#endif /* __CROS_EC_TPM_REGISTERS_H */ diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h deleted file mode 100644 index 5afd1fc84b..0000000000 --- a/include/tpm_vendor_cmds.h +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright 2016 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. - */ - -#ifndef __INCLUDE_TPM_VENDOR_CMDS_H -#define __INCLUDE_TPM_VENDOR_CMDS_H - -#include "common.h" /* For __packed. */ -#include "compile_time_macros.h" /* For BIT. */ - -/* - * This file includes definitions of extended/vendor TPM2 commands and their - * return codes. The definitions are shared between the embedded code and the - * gsctool utility running on the host. - */ - -/* Extension and vendor commands. */ -enum vendor_cmd_cc { - /* Original extension commands */ - EXTENSION_AES = 0, - EXTENSION_HASH = 1, - EXTENSION_RSA = 2, - EXTENSION_ECC = 3, - EXTENSION_FW_UPGRADE = 4, - EXTENSION_HKDF = 5, - EXTENSION_ECIES = 6, - EXTENSION_POST_RESET = 7, - - LAST_EXTENSION_COMMAND = 15, - - /* Our TPMv2 vendor-specific command codes. 16 bits available. */ - VENDOR_CC_GET_LOCK = 16, - VENDOR_CC_SET_LOCK = 17, - VENDOR_CC_SYSINFO = 18, - /* - * VENDOR_CC_IMMEDIATE_RESET may have an argument, which is a (uint16_t) - * time delay (in milliseconds) in doing a reset. Max value is 1000. - * The command may also be called without an argument, which will be - * regarded as zero time delay. - */ - VENDOR_CC_IMMEDIATE_RESET = 19, - VENDOR_CC_INVALIDATE_INACTIVE_RW = 20, - VENDOR_CC_COMMIT_NVMEM = 21, - /* DEPRECATED(22): deep sleep control command. */ - VENDOR_CC_REPORT_TPM_STATE = 23, - VENDOR_CC_TURN_UPDATE_ON = 24, - VENDOR_CC_GET_BOARD_ID = 25, - VENDOR_CC_SET_BOARD_ID = 26, - VENDOR_CC_U2F_APDU = 27, - VENDOR_CC_POP_LOG_ENTRY = 28, - VENDOR_CC_GET_REC_BTN = 29, - VENDOR_CC_RMA_CHALLENGE_RESPONSE = 30, - /* DEPRECATED(31): CCD password command (now part of VENDOR_CC_CCD) */ - /* - * Disable factory mode. Reset all ccd capabilities to default and reset - * write protect to follow battery presence. - */ - VENDOR_CC_DISABLE_FACTORY = 32, - /* DEPRECATED(33): Manage CCD password phase */ - VENDOR_CC_CCD = 34, - VENDOR_CC_GET_ALERTS_DATA = 35, - VENDOR_CC_SPI_HASH = 36, - VENDOR_CC_PINWEAVER = 37, - /* - * Check the factory reset settings. If they're all set correctly, do a - * factory reset to enable ccd factory mode. All capabilities will be - * set to Always and write protect will be permanently disabled. This - * mode can't be reset unless VENDOR_CC_DISABLE_FACTORY is called or - * the 'ccd reset' console command is run. - */ - VENDOR_CC_RESET_FACTORY = 38, - /* - * Get the write protect setting. This will return a single byte with - * bits communicating the write protect setting as described by the - * WPV subcommands. - */ - VENDOR_CC_WP = 39, - /* - * Either enable or disable TPM mode. This is allowed for one-time only - * until next TPM reset EVENT. In other words, once TPM mode is set, - * then it cannot be altered to the other mode value. The allowed input - * values are either TPM_MODE_ENABLED or TPM_MODE_DISABLED as defined - * in 'enum tpm_modes', tpm_registers.h. - * If the input size is zero, it won't change TPM_MODE. - * If either the input size is zero or the input value is valid, - * it will respond with the current tpm_mode value in uint8_t format. - * - * Return code: - * VENDOR_RC_SUCCESS: completed successfully. - * VENDOR_RC_INTERNAL_ERROR: failed for an internal reason. - * VENDOR_RC_NOT_ALLOWED: failed in changing TPM_MODE, - * since it is already set. - * VENDOR_RC_NO_SUCH_SUBCOMMAND: failed because the given input - * is undefined. - */ - VENDOR_CC_TPM_MODE = 40, - /* - * Initializes INFO1 SN data space, and sets SN hash. Takes three - * int32 as parameters, which are written as the SN hash. - */ - VENDOR_CC_SN_SET_HASH = 41, - /* - * Increments the RMA count in the INFO1 SN data space. The space must - * have been previously initialized with the _SET_HASH command above for - * this to succeed. Takes one byte as parameter, which indicates the - * number to increment the RMA count by; this is typically 1 or 0. - * - * Incrementing the RMA count by 0 will set the RMA indicator, but not - * incremement the count. This is useful to mark that a device has been - * RMA'd, but that we were not able to log the new serial number. - * - * Incrementing the count by the maximum RMA count (currently 7) will - * always set the RMA count to the maximum value, regardless of the - * previous value. This can be used with any device, regardless of - * current state, to mark it as RMA'd but with an unknown RMA count. - */ - VENDOR_CC_SN_INC_RMA = 42, - - /* - * Gets the latched state of a power button press to indicate user - * recent user presence. The power button state is automatically cleared - * after PRESENCE_TIMEOUT. - */ - VENDOR_CC_GET_PWR_BTN = 43, - - /* - * U2F commands. - */ - VENDOR_CC_U2F_GENERATE = 44, - VENDOR_CC_U2F_SIGN = 45, - VENDOR_CC_U2F_ATTEST = 46, - - VENDOR_CC_FLOG_TIMESTAMP = 47, - VENDOR_CC_ENDORSEMENT_SEED = 48, - - VENDOR_CC_U2F_MODE = 49, - - /* - * HMAC-SHA256 DRBG invocation for ACVP tests - */ - VENDOR_CC_DRBG_TEST = 50, - - VENDOR_CC_TRNG_TEST = 51, - - LAST_VENDOR_COMMAND = 65535, -}; - -/* - * Error codes reported by extension and vendor commands. - * - * As defined by the TPM2 spec, the TPM response code is all zero for success, - * and errors are a little complicated: - * - * Bits 31:12 must be zero. - * - * Bit 11 S=0 Error - * Bit 10 T=1 Vendor defined response code - * Bit 9 r=0 reserved - * Bit 8 V=1 Conforms to TPMv2 spec - * Bit 7 F=0 Confirms to Table 14, Format-Zero Response Codes - * Bits 6:0 num 128 possible failure reasons - */ - -enum vendor_cmd_rc { - /* EXTENSION_HASH error codes */ - /* Attempt to start a session on an active handle. */ - EXC_HASH_DUPLICATED_HANDLE = 1, - EXC_HASH_TOO_MANY_HANDLES = 2, /* No room to allocate a new context. */ - /* Continuation/finish on unknown context. */ - EXC_HASH_UNKNOWN_CONTEXT = 3, - - /* Our TPMv2 vendor-specific response codes. */ - VENDOR_RC_SUCCESS = 0, - VENDOR_RC_BOGUS_ARGS = 1, - VENDOR_RC_READ_FLASH_FAIL = 2, - VENDOR_RC_WRITE_FLASH_FAIL = 3, - VENDOR_RC_REQUEST_TOO_BIG = 4, - VENDOR_RC_RESPONSE_TOO_BIG = 5, - VENDOR_RC_INTERNAL_ERROR = 6, - VENDOR_RC_NOT_ALLOWED = 7, - VENDOR_RC_NO_SUCH_SUBCOMMAND = 8, - VENDOR_RC_IN_PROGRESS = 9, - VENDOR_RC_PASSWORD_REQUIRED = 10, - - /* Maximum possible failure reason. */ - VENDOR_RC_NO_SUCH_COMMAND = 127, - - /* - * Bits 10 and 8 set, this is to be ORed with the rest of the error - * values to make the combined value compliant with the spec - * requirements. - */ - VENDOR_RC_ERR = 0x500, -}; - -/* - * The TPMv2 Spec mandates that vendor-specific command codes have bit 29 set, - * while bits 15-0 indicate the command. All other bits should be zero. - * We will define one of those 16-bit command values for Cr50 purposes, and use - * the subcommand_code in struct tpm_cmd_header to further distinguish the - * desired operation. - */ -#define TPM_CC_VENDOR_BIT_MASK 0x20000000 -#define VENDOR_CC_MASK 0x0000ffff -/* Our vendor-specific command codes go here */ -#define TPM_CC_VENDOR_CR50 0x0000 - -/*** Structures and constants for VENDOR_CC_SPI_HASH ***/ - -enum vendor_cc_spi_hash_request_subcmd { - /* Relinquish the bus */ - SPI_HASH_SUBCMD_DISABLE = 0, - /* Acquire the bus for AP SPI */ - SPI_HASH_SUBCMD_AP = 1, - /* Acquire the bus for EC SPI */ - SPI_HASH_SUBCMD_EC = 2, - /* Hash SPI data */ - SPI_HASH_SUBCMD_SHA256 = 4, - /* Read SPI data */ - SPI_HASH_SUBCMD_DUMP = 5, - /* Poll spi hash PP state. */ - SPI_HASH_PP_POLL = 6, -}; - -enum vendor_cc_spi_hash_request_flags { - /* EC uses gang programmer mode */ - SPI_HASH_FLAG_EC_GANG = BIT(0), -}; - -/* Structure for VENDOR_CC_SPI_HASH request which follows tpm_header */ -struct vendor_cc_spi_hash_request { - uint8_t subcmd; /* See vendor_cc_spi_hash_request_subcmd */ - uint8_t flags; /* See vendor_cc_spi_hash_request_flags */ - /* Offset and size used by SHA256 and DUMP; ignored by other subcmds */ - uint32_t offset; /* Offset in flash to hash/read */ - uint32_t size; /* Size in bytes to hash/read */ -} __packed; - -/* Maximum size of a response = SHA-256 hash or 1-32 bytes of data */ -#define SPI_HASH_MAX_RESPONSE_BYTES 32 - -/* - * Subcommand code, used to set write protect. - */ -#define WPV_UPDATE BIT(0) -#define WPV_ENABLE BIT(1) -#define WPV_FORCE BIT(2) -#define WPV_ATBOOT_SET BIT(3) -#define WPV_ATBOOT_ENABLE BIT(4) - -#endif /* __INCLUDE_TPM_VENDOR_CMDS_H */ diff --git a/include/u2f.h b/include/u2f.h deleted file mode 100644 index 0f54dfc990..0000000000 --- a/include/u2f.h +++ /dev/null @@ -1,126 +0,0 @@ -// Common U2F raw message format header - Review Draft -// 2014-10-08 -// Editor: Jakob Ehrensvard, Yubico, jakob@yubico.com - -#ifndef __U2F_H_INCLUDED__ -#define __U2F_H_INCLUDED__ - -#ifdef _MSC_VER // Windows -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long int uint64_t; -#else -#include <stdint.h> -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// General constants - -#define U2F_EC_KEY_SIZE 32 // EC key size in bytes -#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point -#define U2F_MAX_KH_SIZE 128 // Max size of key handle -#define U2F_MAX_ATT_CERT_SIZE 2048 // Max size of attestation certificate -#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature -#define U2F_CTR_SIZE 4 // Size of counter field -#define U2F_APPID_SIZE 32 // Size of application id -#define U2F_CHAL_SIZE 32 // Size of challenge -#define U2F_MAX_ATTEST_SIZE 256 // Size of largest blob to sign -#define U2F_P256_SIZE 32 -#define U2F_FIXED_KH_SIZE 64 // Size of fixed size key handles - -#define ENC_SIZE(x) ((x + 7) & 0xfff8) - -// EC (uncompressed) point - -#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format - -typedef struct { - uint8_t pointFormat; // Point type - uint8_t x[U2F_EC_KEY_SIZE]; // X-value - uint8_t y[U2F_EC_KEY_SIZE]; // Y-value -} U2F_EC_POINT; - -// Request Flags. - -#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign -#define U2F_AUTH_CHECK_ONLY 0x07 // Check only -#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set - -// TODO(louiscollard): Add Descriptions. - -typedef struct { - uint8_t appId[U2F_APPID_SIZE]; // Application id - uint8_t userSecret[U2F_P256_SIZE]; - uint8_t flags; -} U2F_GENERATE_REQ; - -typedef struct { - U2F_EC_POINT pubKey; // Generated public key - uint8_t keyHandle[U2F_FIXED_KH_SIZE]; // Key handle -} U2F_GENERATE_RESP; - -typedef struct { - uint8_t appId[U2F_APPID_SIZE]; // Application id - uint8_t userSecret[U2F_P256_SIZE]; - uint8_t keyHandle[U2F_FIXED_KH_SIZE]; // Key handle - uint8_t hash[U2F_P256_SIZE]; - uint8_t flags; -} U2F_SIGN_REQ; - -typedef struct { - uint8_t sig_r[U2F_P256_SIZE]; // Signature - uint8_t sig_s[U2F_P256_SIZE]; // Signature -} U2F_SIGN_RESP; - -typedef struct { - uint8_t userSecret[U2F_P256_SIZE]; - uint8_t format; - uint8_t dataLen; - uint8_t data[U2F_MAX_ATTEST_SIZE]; -} U2F_ATTEST_REQ; - -typedef struct { - uint8_t sig_r[U2F_P256_SIZE]; - uint8_t sig_s[U2F_P256_SIZE]; -} U2F_ATTEST_RESP; - -// Command status responses - -#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR -#define U2F_SW_WRONG_DATA 0x6A80 // SW_WRONG_DATA -#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED -#define U2F_SW_COMMAND_NOT_ALLOWED 0x6986 // SW_COMMAND_NOT_ALLOWED -#define U2F_SW_INS_NOT_SUPPORTED 0x6D00 // SW_INS_NOT_SUPPORTED - -// Protocol extensions - -// Non-standardized command status responses -#define U2F_SW_CLA_NOT_SUPPORTED 0x6E00 -#define U2F_SW_WRONG_LENGTH 0x6700 -#define U2F_SW_WTF 0x6f00 - -// Additional flags for P1 field -#define G2F_ATTEST 0x80 // Fixed attestation key -#define G2F_CONSUME 0x02 // Consume presence - -// The key handle format was changed when support for user secrets was added. -// U2F_SIGN requests that specify this flag will first try to validate the -// key handle as a new format key handle, and if that fails, will fall back -// to treating it as a legacy key handle (without user secrets). -#define SIGN_LEGACY_KH 0x40 - -// U2F Attest format for U2F Register Response. -#define U2F_ATTEST_FORMAT_REG_RESP 0 - -// Vendor command to enable/disable the extensions -#define U2F_VENDOR_MODE U2F_VENDOR_LAST - -#ifdef __cplusplus -} -#endif - -#endif // __U2F_H_INCLUDED__ diff --git a/include/u2f_impl.h b/include/u2f_impl.h deleted file mode 100644 index 0732a1b72d..0000000000 --- a/include/u2f_impl.h +++ /dev/null @@ -1,132 +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. - */ - -/* U2F implementation-specific callbacks and parameters. */ - -#ifndef __CROS_EC_U2F_IMPL_H -#define __CROS_EC_U2F_IMPL_H - -#include "common.h" -#include "cryptoc/p256.h" - -/* ---- Physical presence ---- */ - -enum touch_state { - POP_TOUCH_NO = 0, /* waiting for a user touch */ - POP_TOUCH_YES = 1, /* touch recorded and latched */ -}; - -/* - * Check whether the user presence event was latched. - * - * @param consume reset the latched touch event and the presence LED. - * @return POP_TOUCH_NO or POP_TOUCH_YES. - */ -enum touch_state pop_check_presence(int consume); - -/* ---- platform cryptography hooks ---- */ - -/** - * Generate an origin-specific ECDSA keypair. - * - * Calculates a diversified chip-unique 256b value. - * - * @param seed ptr to store 32-byte seed to regenerate this key on this chip - * @param d pointer to ECDSA private key - * @param pk_x pointer to public key point - * @param pk_y pointer to public key point - * - * @return EC_SUCCESS if a valid keypair was created. - */ -int u2f_origin_keypair(uint8_t *seed, p256_int *d, - p256_int *pk_x, p256_int *pk_y); - -/** - * Reconstitute the origin ECDSA private key from its seed. - * - * @param seed value returned by origin_keypair. - * @param d ptr to store the retrieved private key. - * @return EC_SUCCESS if we retrieved the key. - */ -int u2f_origin_key(const uint8_t *seed, p256_int *d); - -/** - * Pack the specified origin, user secret and origin-specific seed - * into a key handle. - * - * @param origin pointer to origin id - * @param user pointer to user secret - * @param pointer to origin-specific random seed - * - * @return EC_SUCCESS if a valid keypair was created. - */ -int u2f_origin_user_keyhandle(const uint8_t *origin, - const uint8_t *user, - const uint8_t *seed, - uint8_t *key_handle); - -/** - * Generate an origin and user-specific ECDSA keypair from the specified - * key handle. - * - * If pk_x and pk_y are NULL, public key generation will be skipped. - * - * @param key_handle pointer to the 64 byte key handle - * @param d pointer to ECDSA private key - * @param pk_x pointer to public key point - * @param pk_y pointer to public key point - * - * @return EC_SUCCESS if a valid keypair was created. - */ -int u2f_origin_user_keypair(const uint8_t *key_handle, - p256_int *d, - p256_int *pk_x, - p256_int *pk_y); - -/*** - * Generate a hardware derived 256b private key. - * - * @param kek ptr to store the generated key. - * @param key_len size of the storage buffer. Should be 32 bytes. - * @return EC_SUCCESS if a valid key was created. - */ -int u2f_gen_kek(const uint8_t *origin, uint8_t *kek, size_t key_len); - -/** - * Generate a hardware derived ECDSA keypair for individual attestation. - * - * @param seed ptr to store 32-byte seed to regenerate this key on this chip - * @param d pointer to ECDSA private key - * @param pk_x pointer to public key point - * @param pk_y pointer to public key point - * - * @return EC_SUCCESS if a valid keypair was created. - */ -int g2f_individual_keypair(p256_int *d, p256_int *pk_x, p256_int *pk_y); - -/*** - * Generates and persists to nvram a new seed that will be used to - * derive kek in future calls to u2f_gen_kek(). - * - * @param commit whether to commit nvram changes before returning. - * @return EC_SUCCESS if seed was successfully created - * (and persisted if requested). - */ -int u2f_gen_kek_seed(int commit); - -/* Maximum size in bytes of G2F attestation certificate. */ -#define G2F_ATTESTATION_CERT_MAX_LEN 315 - -/** - * Gets the x509 certificate for the attestation keypair returned - * by g2f_individual_keypair(). - * - * @param buf pointer to a buffer that must be at least - * G2F_ATTESTATION_CERT_MAX_LEN bytes. - * @return size of certificate written to buf, 0 on error. - */ -int g2f_attestation_cert(uint8_t *buf); - -#endif /* __CROS_EC_U2F_IMPL_H */ diff --git a/include/usb_api.h b/include/usb_api.h index 481a77272c..79ee9406e9 100644 --- a/include/usb_api.h +++ b/include/usb_api.h @@ -82,11 +82,4 @@ static inline void usb_wake(void) {} /* Board-specific USB wake, for side-band wake, called by usb_wake above. */ void board_usb_wake(void); -#ifdef CONFIG_USB_SELECT_PHY -/* Select which PHY to use. */ -void usb_select_phy(uint32_t phy); - -/* Get the current PHY */ -uint32_t usb_get_phy(void); -#endif #endif /* __CROS_EC_USB_API_H */ diff --git a/test/build.mk b/test/build.mk index 2658cca4af..aff698f125 100644 --- a/test/build.mk +++ b/test/build.mk @@ -29,7 +29,6 @@ test-list-host += entropy test-list-host += extpwr_gpio test-list-host += fan test-list-host += flash -test-list-host += flash_log test-list-host += float test-list-host += fp test-list-host += fpsensor @@ -58,7 +57,6 @@ test-list-host += mutex test-list-host += newton_fit test-list-host += online_calibration test-list-host += pingpong -test-list-host += pinweaver test-list-host += power_button test-list-host += printf test-list-host += queue @@ -115,7 +113,6 @@ entropy-y=entropy.o extpwr_gpio-y=extpwr_gpio.o fan-y=fan.o flash-y=flash.o -flash_log-y=flash_log.o fpsensor-y=fpsensor.o fpsensor_crypto-y=fpsensor_crypto.o fpsensor_state-y=fpsensor_state.o @@ -141,7 +138,6 @@ kasa-y=kasa.o mutex-y=mutex.o newton_fit-y=newton_fit.o pingpong-y=pingpong.o -pinweaver-y=pinweaver.o power_button-y=power_button.o powerdemo-y=powerdemo.o printf-y=printf.o diff --git a/test/flash_log.c b/test/flash_log.c deleted file mode 100644 index 48c842371e..0000000000 --- a/test/flash_log.c +++ /dev/null @@ -1,276 +0,0 @@ -/* Copyright 2019 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. - * - * Test Cr-50 Non-Voltatile memory module - */ - -#include <stdlib.h> - -#include "common.h" -#include "flash_log.h" -#include "test_util.h" -#include "timer.h" -#include "util.h" - -struct log_stats { - size_t total_size; - size_t entry_count; -}; - -static int verify_single_entry(uint8_t fill_byte, int expected_type) -{ - int entry_size; - union entry_u e; - size_t i; - uint8_t *log_base = (void *)CONFIG_FLASH_LOG_BASE; - - memset(log_base, fill_byte, CONFIG_FLASH_LOG_SPACE); - last_used_timestamp = 0; - flash_log_init(); - - /* After initialization there should be a single log entry. */ - entry_size = flash_log_dequeue_event(0, e.entry, sizeof(e.entry)); - TEST_ASSERT(entry_size == sizeof(e.r)); - TEST_ASSERT(e.r.type == expected_type); - - entry_size = flash_log_dequeue_event(e.r.timestamp, e.entry, - sizeof(e.entry)); - TEST_ASSERT(entry_size == 0); - - /* Verify proper entry padding. */ - i = sizeof(e.r); - TEST_ASSERT(i % CONFIG_FLASH_WRITE_SIZE); - for (; i % CONFIG_FLASH_WRITE_SIZE; i++) - TEST_ASSERT(log_base[i] == FE_LOG_PAD); - - TEST_ASSERT(log_base[i] == 0xff); /* First byte above padding. */ - - return EC_SUCCESS; -} - -static int test_init_from_scratch(void) -{ - return verify_single_entry(0xff, FE_LOG_START); -} - -static int test_init_from_corrupted(void) -{ - /* Let's mess up the log space. */ - return verify_single_entry(0x55, FE_LOG_CORRUPTED); -} - -static int verify_log(struct log_stats *stats) -{ - union entry_u e; - size_t actual_size; - size_t actual_count; - int entry_size; - - e.r.timestamp = 0; - actual_size = 0; - actual_count = 0; - - while ((entry_size = flash_log_dequeue_event(e.r.timestamp, e.entry, - sizeof(e))) > 0) { - actual_count++; - actual_size += FLASH_LOG_ENTRY_SIZE(e.r.size); - } - - TEST_ASSERT(entry_size == 0); - - stats->total_size = actual_size; - stats->entry_count = actual_count; - - return EC_SUCCESS; -} - -static int fill_to_threshold(size_t threshold, struct log_stats *stats) -{ - int i; - uint8_t entry_type; - uint8_t payload_size; - uint8_t p[MAX_FLASH_LOG_PAYLOAD_SIZE]; - size_t total_size; - size_t entry_count; - - /* Start with an only entry in the log. */ - TEST_ASSERT(verify_single_entry(0xff, FE_LOG_START) == EC_SUCCESS); - - srand(0); /* Let's make sure it is consistent. */ - entry_count = 1; - total_size = FLASH_LOG_ENTRY_SIZE(0); - - /* Let's fill up the log to compaction limit. */ - do { - entry_type = rand() % 0xfe; - payload_size = rand() % MAX_FLASH_LOG_PAYLOAD_SIZE; - for (i = 0; i < payload_size; i++) - p[i] = (i + entry_type) & 0xff; - - flash_log_add_event(entry_type, payload_size, p); - total_size += FLASH_LOG_ENTRY_SIZE(payload_size); - entry_count++; - } while (total_size <= threshold); - - TEST_ASSERT(verify_log(stats) == EC_SUCCESS); - TEST_ASSERT(stats->total_size == total_size); - TEST_ASSERT(stats->entry_count == entry_count); - - /* This should get the log over the compaction threshold. */ - flash_log_add_event(entry_type, payload_size, p); - TEST_ASSERT(verify_log(stats) == EC_SUCCESS); - - return EC_SUCCESS; -} - -static int test_run_time_compaction(void) -{ - struct log_stats stats; - - TEST_ASSERT(fill_to_threshold(RUN_TIME_LOG_FULL_WATERMARK, &stats) == - EC_SUCCESS); - - /* - * Compacted space is guaranteed not to exceed the threshold plus the - * size of the largest possible entry. - */ - TEST_ASSERT(stats.total_size < - (COMPACTION_SPACE_PRESERVE + - FLASH_LOG_ENTRY_SIZE(MAX_FLASH_LOG_PAYLOAD_SIZE))); - - return EC_SUCCESS; -} - -static int test_init_time_compaction(void) -{ - struct log_stats stats; - - TEST_ASSERT(fill_to_threshold(STARTUP_LOG_FULL_WATERMARK, &stats) == - EC_SUCCESS); - - /* - * Init should roll the log back below the compaction preservation - * threshold. - */ - flash_log_init(); - TEST_ASSERT(verify_log(&stats) == EC_SUCCESS); - - /* - * Compacted space is guaranteed not to exceed the threshold plus the - * size of the largest possible entry. - */ - TEST_ASSERT(stats.total_size < - (COMPACTION_SPACE_PRESERVE + - FLASH_LOG_ENTRY_SIZE(MAX_FLASH_LOG_PAYLOAD_SIZE))); - - return EC_SUCCESS; -} - -static int test_lock_failure_reporting(void) -{ - union entry_u e; - - TEST_ASSERT(test_init_from_scratch() == EC_SUCCESS); - lock_failures_count = 0; - log_event_in_progress = 1; - - /* This should fail. */ - flash_log_add_event(FE_LOG_TEST, 0, NULL); - - /* Lock count should have been incremented. */ - TEST_ASSERT(lock_failures_count == 1); - - /* This should also fail. */ - TEST_ASSERT(flash_log_dequeue_event(0, e.entry, sizeof(e.entry)) == - -EC_ERROR_BUSY); - - log_event_in_progress = 0; - /* This should succeed. */ - flash_log_add_event(FE_LOG_TEST, 0, NULL); - - TEST_ASSERT(lock_failures_count == 0); - - /* There should be three entries in the log now. */ - flash_log_dequeue_event(0, e.entry, sizeof(e.entry)); - TEST_ASSERT(e.r.type == FE_LOG_START); - - flash_log_dequeue_event(e.r.timestamp, e.entry, sizeof(e.entry)); - TEST_ASSERT(e.r.type == FE_LOG_LOCKS); - TEST_ASSERT(FLASH_LOG_PAYLOAD_SIZE(e.r.size) == 1); - TEST_ASSERT(e.r.payload[0] == 1); - - flash_log_dequeue_event(e.r.timestamp, e.entry, sizeof(e.entry)); - TEST_ASSERT(e.r.type == FE_LOG_TEST); - - return EC_SUCCESS; -} - -static int test_setting_base_timestamp(void) -{ - union entry_u eu; - uint32_t saved_stamp; - timestamp_t ts; - uint32_t delta_time; - /* Value collected on May 13 2019 */ - uint32_t recent_seconds_since_epoch = 1557793625; - - ts.val = 0; - force_time(ts); - TEST_ASSERT(verify_single_entry(0xff, FE_LOG_START) == EC_SUCCESS); - TEST_ASSERT(flash_log_dequeue_event(0, eu.entry, sizeof(eu)) > 0); - - saved_stamp = eu.r.timestamp; - - /* Let the next log timestamp be 1000 s later. */ - delta_time = 1000; - - /* - * Move internal clock uptime of 1000 s (convert value to microseconds - * first). - */ - ts.val = ((uint64_t)saved_stamp + delta_time) * 1000000; - force_time(ts); - - /* Verify that the second event is within 1001 s from the first one. */ - flash_log_add_event(FE_LOG_TEST, 0, NULL); - TEST_ASSERT(flash_log_dequeue_event(saved_stamp, eu.entry, sizeof(eu)) > - 0); - TEST_ASSERT((eu.r.timestamp - saved_stamp - delta_time) < 2); - - /* Set timestamp base to current time. */ - TEST_ASSERT(flash_log_set_tstamp(recent_seconds_since_epoch) == - EC_SUCCESS); - - /* Create an entry with the latest timestamp. */ - flash_log_add_event(FE_LOG_TEST, 0, NULL); - - /* Verify that it has been logged with the correct timestamp. */ - TEST_ASSERT(flash_log_dequeue_event(eu.r.timestamp, eu.entry, - sizeof(eu)) > 0); - TEST_ASSERT((eu.r.timestamp - recent_seconds_since_epoch) < 2); - - /* Verify that it is impossible to roll timestamps back. */ - TEST_ASSERT(flash_log_set_tstamp(recent_seconds_since_epoch - 100) == - EC_ERROR_INVAL); - - /* But is possible to roll further forward. */ - TEST_ASSERT(flash_log_set_tstamp(recent_seconds_since_epoch + 100) == - EC_SUCCESS); - - return EC_SUCCESS; -} - -void run_test(void) -{ - test_reset(); - - RUN_TEST(test_init_from_scratch); - RUN_TEST(test_init_from_corrupted); - RUN_TEST(test_run_time_compaction); - RUN_TEST(test_init_time_compaction); - RUN_TEST(test_lock_failure_reporting); - RUN_TEST(test_setting_base_timestamp); - - test_print_result(); -} diff --git a/test/flash_log.tasklist b/test/flash_log.tasklist deleted file mode 100644 index 9fc1a80f4d..0000000000 --- a/test/flash_log.tasklist +++ /dev/null @@ -1,9 +0,0 @@ -/* Copyright 2019 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. - */ - -/** - * See CONFIG_TASK_LIST in config.h for details. - */ -#define CONFIG_TEST_TASK_LIST diff --git a/test/nvmem_test.h b/test/nvmem_test.h deleted file mode 100644 index 58775d4bcb..0000000000 --- a/test/nvmem_test.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright 2019 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. - */ - -#ifndef __EC_TEST_NVMEM_TEST_H -#define __EC_TEST_NVMEM_TEST_H - -#define EMBEDDED_MODE 1 -#define NV_C -#include "Global.h" -#undef NV_C -#include "NV_fp.h" -#include "tpm_generated.h" - -enum test_failure_mode { - TEST_NO_FAILURE, - TEST_FAIL_WHEN_SAVING, - TEST_FAIL_WHEN_INVALIDATING, - TEST_FAIL_WHEN_COMPACTING, - TEST_FAIL_SAVING_VAR, - TEST_FAIL_FINALIZING_VAR, - TEST_FAILED_HASH, - TEST_SPANNING_PAGES -}; - -extern enum test_failure_mode failure_mode; - -size_t add_evictable_obj(void *obj, size_t obj_size); -void drop_evictable_obj(void *obj); - -#endif /* ! __EC_TEST_NVMEM_TEST_H */ diff --git a/test/pinweaver.c b/test/pinweaver.c deleted file mode 100644 index 63a7e2e067..0000000000 --- a/test/pinweaver.c +++ /dev/null @@ -1,2681 +0,0 @@ -/* Copyright 2018 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 <pinweaver.h> - -#include <dcrypto.h> -#include <nvmem_vars.h> -#include <sha256.h> -#include <stdint.h> -#include <string.h> -#include <timer.h> -#include <util.h> -#include <pinweaver_types.h> - -#include "test_util.h" - -#include <stdlib.h> - -struct pw_test_data_t { - union { - struct pw_request_t request; - struct pw_response_t response; - /* Reserve space for the variable length fields. */ - uint8_t tpm_buffer_size[PW_MAX_MESSAGE_SIZE]; - }; -} PW_ALIGN_TO_WRD; - -/******************************************************************************/ -/* Test data - */ -const int EMPTY_TREE_PATH_LENGTH = 18; -const struct merkle_tree_t EMPTY_TREE = { - {2} /* bits_per_level */, - {6} /* height */, - /* root */ - {0x81, 0xaa, 0xe9, 0xde, 0x93, 0xf4, 0xdf, 0x88, - 0x18, 0xfa, 0xff, 0xbd, 0xb7, 0x09, 0xc0, 0x86, - 0x48, 0xdd, 0xcd, 0x35, 0x00, 0xf2, 0x88, 0xd6, - 0x3f, 0xa6, 0x5e, 0x80, 0x10, 0x19, 0x41, 0x17}, - /* key derivation nonce. */ - {0x75, 0xf8, 0x43, 0xf7, 0x23, 0xbd, 0x2a, 0x0f, - 0x8d, 0x34, 0xbf, 0xa6, 0x6d, 0xf9, 0x44, 0x38}, - /* hmac_key */ - {0x96, 0xc6, 0xb1, 0x64, 0xb6, 0xa7, 0xa8, 0x01, - 0xd5, 0x1d, 0x8e, 0x97, 0x24, 0x86, 0xf8, 0x6f, - 0xd4, 0x84, 0x0f, 0x95, 0x52, 0x93, 0x8d, 0x7d, - 0x00, 0xbb, 0xba, 0xc8, 0xed, 0x7f, 0xa4, 0x7a}, - /* wrap_key */ - {0x95, 0xc9, 0x0a, 0xd4, 0xb3, 0x61, 0x1b, 0xcf, - 0x1b, 0x49, 0x2b, 0xd6, 0x5d, 0xbc, 0x80, 0xa9, - 0xf4, 0x83, 0xf2, 0x84, 0xd4, 0x04, 0x57, 0x7f, - 0x02, 0xae, 0x37, 0x64, 0xae, 0xda, 0x71, 0x2a}, -}; - -const struct leaf_data_t DEFAULT_LEAF = { - /*pub*/ - { - /* label = {0, 1, 2, 3, 0, 1} */ - {0x1b1llu}, - /* delay_schedule */ - {{{5}, {20} }, {{6}, {60} }, {{7}, {300} }, {{8}, {600} }, - {{9}, {1800} }, {{10}, {3600} }, {{50}, {PW_BLOCK_ATTEMPTS} }, - {{0}, {0} }, - {{0}, {0} }, {{0}, {0} }, {{0}, {0} }, {{0}, {0} }, - {{0}, {0} }, {{0}, {0} }, {{0}, {0} }, {{0}, {0} }, }, - /*timestamp*/ - {0, 0}, - /* attempt_count */ - {0}, - /* valid_pcr_criteria */ - {{{0, 0}, {0} }, {{0, 0}, {0} } }, - }, - /*sec*/ - { - /* low_entropy_secret */ - {0xba, 0xbc, 0x98, 0x9d, 0x97, 0x20, 0xcf, 0xea, - 0xaa, 0xbd, 0xb2, 0xe3, 0xe0, 0x2c, 0x5c, 0x55, - 0x06, 0x60, 0x93, 0xbd, 0x07, 0xe2, 0xba, 0x92, - 0x10, 0x19, 0x24, 0xb1, 0x29, 0x33, 0x5a, 0xe2}, - /* high_entropy_secret */ - {0xe3, 0x46, 0xe3, 0x62, 0x01, 0x5d, 0xfe, 0x0a, - 0xd3, 0x67, 0xd7, 0xef, 0xab, 0x01, 0xad, 0x0e, - 0x3a, 0xed, 0xe8, 0x2f, 0x99, 0xd1, 0x2d, 0x13, - 0x4d, 0x4e, 0xe4, 0x02, 0xbe, 0x71, 0x8e, 0x40}, - /* reset_secret */ - {0x8c, 0x33, 0x8c, 0xa7, 0x0f, 0x81, 0xa4, 0xee, - 0x24, 0xcd, 0x04, 0x84, 0x9c, 0xa8, 0xfd, 0xdd, - 0x14, 0xb0, 0xad, 0xe6, 0xb7, 0x6a, 0x10, 0xfc, - 0x03, 0x22, 0xcb, 0x71, 0x31, 0xd3, 0x74, 0xd6}, - }, -}; - -const struct leaf_header_t DEFAULT_HEAD = { - { - .minor = PW_LEAF_MINOR_VERSION, - .major = PW_LEAF_MAJOR_VERSION, - }, - sizeof(DEFAULT_LEAF.pub), - sizeof(DEFAULT_LEAF.sec), -}; - -const uint8_t DEFAULT_IV[] = { - 0xaa, 0x65, 0x97, 0xc7, 0x02, 0x23, 0xb8, 0xdc, - 0xb3, 0x55, 0xca, 0x3a, 0xab, 0xd0, 0x03, 0x90, -}; - -const uint8_t EMPTY_HMAC[32] = {}; - -const uint32_t DEFAULT_STORAGE_SEED[8] = { - 0xe9e9880b, 0xb2a9fa0e, 0x9dcf22af, 0xc40156d0, - 0xca8535dc, 0x748606ee, 0x68f0f627, 0x7df7558a, -}; - -/* This is not the actual hmac. */ -const uint8_t DEFAULT_HMAC[] = { - 0x87, 0x7e, 0xe2, 0xb2, 0x60, 0xeb, 0xf3, 0x4b, - 0x80, 0x3e, 0xca, 0xcb, 0xe6, 0x24, 0x21, 0x86, - 0xd9, 0xe3, 0x91, 0xf7, 0x2d, 0x16, 0x59, 0xd8, - 0x0f, 0x37, 0x0a, 0xf4, 0x64, 0x19, 0x44, 0xe7, -}; - -const uint8_t ROOT_WITH_DEFAULT_HMAC[] = { - 0x24, 0xad, 0xe4, 0xad, 0xf2, 0xdc, 0x40, 0x26, - 0x15, 0x03, 0x16, 0x6f, 0x3c, 0x32, 0x05, 0x99, - 0xf8, 0x25, 0x22, 0x92, 0xb9, 0xc7, 0xcd, 0x18, - 0x37, 0xc2, 0xf2, 0x72, 0x31, 0xdd, 0xc4, 0xaf, -}; - -/* This is not the actual hmac. */ -const uint8_t OTHER_HMAC[] = { - 0xec, 0x64, 0x73, 0x39, 0xcf, 0x53, 0xb7, 0x08, - 0x85, 0x8f, 0xb6, 0x20, 0x25, 0x98, 0x59, 0x97, - 0x58, 0x8c, 0x7a, 0x80, 0x10, 0xb4, 0xc1, 0xc8, - 0x8a, 0xdf, 0xe3, 0x69, 0x07, 0xd1, 0xc4, 0xdc, -}; - -const uint8_t ROOT_WITH_OTHER_HMAC[] = { - 0xdf, 0xce, 0xf4, 0xba, 0x18, 0xe8, 0xd0, 0x1d, - 0xcb, 0x3b, 0x29, 0x41, 0x44, 0x01, 0x6e, 0x72, - 0xe3, 0x19, 0x9a, 0x44, 0x62, 0x44, 0x2a, 0xf1, - 0xaf, 0x66, 0xb6, 0xf0, 0x61, 0x05, 0x9d, 0xc0, -}; - -const uint8_t DEFAULT_PCR_DIGEST[] = { - 0xdf, 0xce, 0xf4, 0xba, 0x18, 0xe8, 0xd0, 0x1d, - 0xcb, 0x3b, 0x29, 0x41, 0x44, 0x01, 0x6e, 0x72, - 0xe3, 0x19, 0x9a, 0x44, 0x62, 0x44, 0x2a, 0xf1, - 0xaf, 0x66, 0xb6, 0xf0, 0x61, 0x05, 0x9d, 0xc0, -}; - -/******************************************************************************/ -/* Config Variables and defines for Mocks. - */ - -struct pw_long_term_storage_t MOCK_pw_long_term_storage; -struct pw_log_storage_t MOCK_pw_log_storage; -int MOCK_getvar_ret = EC_SUCCESS; -int MOCK_setvar_ret = EC_SUCCESS; - -const uint8_t *MOCK_rand_bytes_src; -size_t MOCK_rand_bytes_offset; -size_t MOCK_rand_bytes_len; - -void (*MOCK_hash_update_cb)(const void *data, size_t len); -static void auth_hash_update_cb(const void *data, size_t len); - -const uint8_t *MOCK_hmac; -size_t MOCK_DECRYPTO_init_counter; -size_t MOCK_DECRYPTO_release_counter; - -#define MOCK_AES_XOR_BYTE(b) ((uint8_t)(0x77 + (b & 15))) -int MOCK_aes_fail; -int MOCK_appkey_derive_fail; -enum dcrypto_appid MOCK_hwctx_appkey; - -#define PW_VALID_PCR_CRITERIA_SIZE \ - (sizeof(struct valid_pcr_value_t) * PW_MAX_PCR_CRITERIA_COUNT) - -/******************************************************************************/ -/* Helper functions - */ - -static void convert_response_to_new_version(uint8_t req_type, - struct pw_response_t *response) -{ - if (response->header.version == 0) { - if (req_type == PW_TRY_AUTH) { - unsigned char *src = (unsigned char *) - (&response->data.try_auth.reset_secret); - memmove(src + PW_SECRET_SIZE, src, - PW_LEAF_PAYLOAD_SIZE); - memcpy(src, DEFAULT_LEAF.sec.reset_secret, - PW_SECRET_SIZE); - response->header.data_length += PW_SECRET_SIZE; - } - } -} - -static int do_request(struct merkle_tree_t *merkle_tree, - struct pw_test_data_t *buf) -{ - uint8_t req_type = buf->request.header.type.v; - int ret = pw_handle_request(merkle_tree, &buf->request, &buf->response); - size_t offset = buf->response.header.data_length + - sizeof(buf->response.header); - - /* Zero out bytes that won't be sent for testing.*/ - memset(buf->tpm_buffer_size + offset, 0, - sizeof(buf->tpm_buffer_size) - offset); - - if (buf->request.header.version < PW_PROTOCOL_VERSION) - convert_response_to_new_version(req_type, &buf->response); - - return ret; -} - -static const char *pw_error_str(int code) -{ - switch (code) { - case EC_SUCCESS: - return "EC_SUCCESS"; - case EC_ERROR_UNKNOWN: - return "EC_ERROR_UNKNOWN"; - case EC_ERROR_UNIMPLEMENTED: - return "EC_ERROR_UNIMPLEMENTED"; - case PW_ERR_VERSION_MISMATCH: - return "PW_ERR_VERSION_MISMATCH"; - case PW_ERR_LENGTH_INVALID: - return "PW_ERR_LENGTH_INVALID"; - case PW_ERR_TYPE_INVALID: - return "PW_ERR_TYPE_INVALID"; - case PW_ERR_BITS_PER_LEVEL_INVALID: - return "PW_ERR_BITS_PER_LEVEL_INVALID"; - case PW_ERR_HEIGHT_INVALID: - return "PW_ERR_HEIGHT_INVALID"; - case PW_ERR_LABEL_INVALID: - return "PW_ERR_LABEL_INVALID"; - case PW_ERR_DELAY_SCHEDULE_INVALID: - return "PW_ERR_DELAY_SCHEDULE_INVALID"; - case PW_ERR_PATH_AUTH_FAILED: - return "PW_ERR_PATH_AUTH_FAILED"; - case PW_ERR_LEAF_VERSION_MISMATCH: - return "PW_ERR_LEAF_VERSION_MISMATCH"; - case PW_ERR_HMAC_AUTH_FAILED: - return "PW_ERR_HMAC_AUTH_FAILED"; - case PW_ERR_LOWENT_AUTH_FAILED: - return "PW_ERR_LOWENT_AUTH_FAILED"; - case PW_ERR_RESET_AUTH_FAILED: - return "PW_ERR_RESET_AUTH_FAILED"; - case PW_ERR_CRYPTO_FAILURE: - return "PW_ERR_CRYPTO_FAILURE"; - case PW_ERR_RATE_LIMIT_REACHED: - return "PW_ERR_RATE_LIMIT_REACHED"; - case PW_ERR_ROOT_NOT_FOUND: - return "PW_ERR_ROOT_NOT_FOUND"; - case PW_ERR_NV_EMPTY: - return "PW_ERR_NV_EMPTY"; - case PW_ERR_NV_LENGTH_MISMATCH: - return "PW_ERR_NV_LENGTH_MISMATCH"; - case PW_ERR_NV_VERSION_MISMATCH: - return "PW_ERR_NV_VERSION_MISMATCH"; - default: - return "?"; - } -} - -/* Pinweaver specific return code check. This prints the string representation - * of the return code instead of just the number. - */ -#define TEST_RET_EQ(n, m) \ - do { \ - int val1 = n; \ - int val2 = m; \ - if (val1 != val2) { \ - ccprintf("%d: ASSERTION failed: %s (%d) != %s (%d)\n", \ - __LINE__, pw_error_str(val1), val1, \ - pw_error_str(val2), val2); \ - task_dump_trace(); \ - return EC_ERROR_UNKNOWN; \ - } \ - } while (0) - -/* Allows mock functions when that don't return success / failure to have - * assertions. - */ -#define TEST_ASRT_NORET(n) \ - do { \ - if (!(n)) { \ - int x = 0;\ - ccprintf("%d: ASSERTION failed: %s\n", __LINE__, #n); \ - task_dump_trace(); \ - x = 1 / x; \ - } \ - } while (0) - -/* For debugging and generating test data. */ -void print_array(const uint8_t *data, size_t n) __attribute__ ((unused)); -void print_array(const uint8_t *data, size_t n) -{ - size_t x; - - if (n > 0) { - ccprintf("uint8_t data[] = {"); - for (x = 0; x < n - 1; ++x) { - if ((x & 7) != 7) - ccprintf("0x%02x, ", data[x]); - else - ccprintf("0x%02x,\n", data[x]); - } - ccprintf("0x%02x};\n", data[x]); - } -} - -/* For exporting structs. This is useful for validating the results of crypto - * operations. - */ -void print_hex(const uint8_t *data, size_t n) __attribute__ ((unused)); -void print_hex(const uint8_t *data, size_t n) -{ - size_t x; - - for (x = 0; x < n; ++x) - ccprintf("%02x ", data[x]); -} - -/* Initialize the log. - * For num_operations: - * < 0 only zero out the storage. - * == 0 only initialize the tree - * > 0 cyclically applies operations in the following order: - * insert - * auth failed - * auth success - * remove - * So for num_operations == 4 the complete set of operations will be written to - * the log. - */ -static void setup_storage(int num_operations) -{ - MOCK_getvar_ret = EC_SUCCESS; - MOCK_setvar_ret = EC_SUCCESS; - - memset(&MOCK_pw_long_term_storage, 0, - sizeof(MOCK_pw_long_term_storage)); - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - if (num_operations < 0) - return; - --num_operations; - - store_merkle_tree(&EMPTY_TREE); - - while (num_operations > 0) { - --num_operations; - - log_insert_leaf(DEFAULT_LEAF.pub.label, ROOT_WITH_DEFAULT_HMAC, - DEFAULT_HMAC); - - if (num_operations < 0) - return; - --num_operations; - - log_auth(DEFAULT_LEAF.pub.label, ROOT_WITH_OTHER_HMAC, - PW_ERR_LOWENT_AUTH_FAILED, - (struct pw_timestamp_t) {7, 99}); - - if (num_operations < 0) - return; - --num_operations; - - log_auth(DEFAULT_LEAF.pub.label, ROOT_WITH_DEFAULT_HMAC, - EC_SUCCESS, - (struct pw_timestamp_t) {10, 100}); - - if (num_operations < 0) - return; - --num_operations; - - log_remove_leaf(DEFAULT_LEAF.pub.label, EMPTY_TREE.root); - } -} - -static void setup_default_empty_path(uint8_t hashes[][PW_HASH_SIZE]) -{ - uint8_t num_siblings = (1 << EMPTY_TREE.bits_per_level.v) - 1; - const uint8_t level_hashes[5][PW_HASH_SIZE] = { - /* Values for level 5 are all 0 for empty. */ - /* SHA256 for level 5, values for level 4. */ - {0x38, 0x72, 0x3a, 0x2e, 0x5e, 0x8a, 0x17, 0xaa, - 0x79, 0x50, 0xdc, 0x00, 0x82, 0x09, 0x94, 0x4e, - 0x89, 0x8f, 0x69, 0xa7, 0xbd, 0x10, 0xa2, 0x3c, - 0x83, 0x9d, 0x34, 0x1e, 0x93, 0x5f, 0xd5, 0xca}, - /* SHA256 for level 4, values for level 3. */ - {0xfe, 0xc1, 0x2b, 0x09, 0x33, 0x31, 0x28, 0x34, - 0x79, 0x1f, 0x07, 0x64, 0x1a, 0xed, 0x30, 0x53, - 0x11, 0x1f, 0x15, 0x3e, 0x1e, 0x3e, 0xd1, 0xf0, - 0xcd, 0x16, 0xcb, 0x39, 0x25, 0xfd, 0x5f, 0x84}, - /* SHA256 for level 3, values for level 2. */ - {0xb6, 0xd4, 0x9c, 0x89, 0x76, 0x45, 0x9c, 0xe9, - 0x9c, 0x0b, 0xad, 0x5d, 0x71, 0xdf, 0x92, 0x77, - 0xf6, 0x82, 0x62, 0x63, 0x81, 0x9f, 0xc9, 0x2f, - 0x61, 0x9c, 0x29, 0x67, 0x52, 0x37, 0x01, 0x51}, - /* SHA256 for level 2, values for level 1. */ - {0x87, 0xeb, 0x61, 0x6b, 0x2c, 0x42, 0x07, 0x5e, - 0x70, 0x2d, 0x48, 0x49, 0xf2, 0xe0, 0x13, 0x11, - 0xc4, 0xe6, 0x98, 0xfa, 0x22, 0x7e, 0x65, 0xc6, - 0x66, 0x33, 0x6b, 0xb6, 0xd7, 0xb9, 0x45, 0xfa}, - /* SHA256 for level 1, values for level 0. */ - {0x80, 0x91, 0x04, 0x3f, 0x6c, 0x29, 0x06, 0x35, - 0x86, 0x99, 0x21, 0x88, 0x1f, 0xd9, 0xae, 0xb8, - 0x35, 0x94, 0x26, 0x19, 0x64, 0x68, 0x4f, 0x4f, - 0x4c, 0x66, 0x13, 0xa9, 0x66, 0x69, 0x25, 0x0e},}; - uint8_t hx; - uint8_t kx; - - /* Empty first level. */ - memset(hashes, 0, num_siblings * PW_HASH_SIZE); - hashes += num_siblings; - - for (hx = 1; hx < EMPTY_TREE.height.v; ++hx) { - for (kx = 0; kx < num_siblings; ++kx) { - memcpy(hashes, level_hashes[hx - 1], PW_HASH_SIZE); - ++hashes; - } - } -} - -static void setup_default_unimported_leaf_data_and_hashes( - const struct leaf_data_t *leaf_data, - const uint8_t hmac[PW_HASH_SIZE], - const struct leaf_header_t *header, - struct unimported_leaf_data_t *data) -{ - memcpy(&data->head, header, sizeof(*header)); - memcpy(data->hmac, hmac, sizeof(data->hmac)); - memcpy(data->iv, DEFAULT_IV, sizeof(DEFAULT_IV)); - memcpy(data->payload, &leaf_data->pub, header->pub_len); - DCRYPTO_aes_ctr(data->payload + header->pub_len, - EMPTY_TREE.wrap_key, sizeof(EMPTY_TREE.wrap_key) * 8, - DEFAULT_IV, (const uint8_t *)&leaf_data->sec, - header->sec_len); - setup_default_empty_path((void *)(data->payload + header->pub_len + - header->sec_len)); -} - -static void setup_reset_tree_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memset(merkle_tree, 0, sizeof(*merkle_tree)); - memset(&MOCK_pw_long_term_storage, 0, - sizeof(MOCK_pw_long_term_storage)); - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_RESET_TREE; - request->header.data_length = sizeof(struct pw_request_reset_tree_t); - - request->data.reset_tree.bits_per_level.v = 2; /* k = 4 */ - request->data.reset_tree.height.v = 6; /* L = 12 */ - - MOCK_rand_bytes_src = (uint8_t *)EMPTY_TREE.key_derivation_nonce; - MOCK_rand_bytes_offset = 0; - MOCK_rand_bytes_len = sizeof(EMPTY_TREE.key_derivation_nonce); - MOCK_appkey_derive_fail = EC_SUCCESS; - MOCK_setvar_ret = EC_SUCCESS; -} - -static void setup_insert_leaf_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE)); - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_INSERT_LEAF; - request->header.data_length = sizeof(struct pw_request_insert_leaf_t) + - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE; - - request->data.insert_leaf.label.v = DEFAULT_LEAF.pub.label.v; - memcpy(&request->data.insert_leaf.delay_schedule, - &DEFAULT_LEAF.pub.delay_schedule, - sizeof(DEFAULT_LEAF.pub.delay_schedule)); - memcpy(&request->data.insert_leaf.valid_pcr_criteria, - &DEFAULT_LEAF.pub.valid_pcr_criteria, - sizeof(DEFAULT_LEAF.pub.valid_pcr_criteria)); - memcpy(&request->data.insert_leaf.low_entropy_secret, - &DEFAULT_LEAF.sec.low_entropy_secret, - sizeof(DEFAULT_LEAF.sec.low_entropy_secret)); - memcpy(&request->data.insert_leaf.high_entropy_secret, - &DEFAULT_LEAF.sec.high_entropy_secret, - sizeof(DEFAULT_LEAF.sec.high_entropy_secret)); - memcpy(&request->data.insert_leaf.reset_secret, - &DEFAULT_LEAF.sec.reset_secret, - sizeof(DEFAULT_LEAF.sec.reset_secret)); - setup_default_empty_path(request->data.insert_leaf.path_hashes); - - MOCK_rand_bytes_src = DEFAULT_IV; - MOCK_rand_bytes_offset = 0; - MOCK_rand_bytes_len = sizeof(DEFAULT_IV); - MOCK_hash_update_cb = 0; - MOCK_hmac = DEFAULT_HMAC; - MOCK_aes_fail = 0; - MOCK_setvar_ret = EC_SUCCESS; -} - -static void setup_remove_leaf_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE)); - memcpy(merkle_tree->root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_REMOVE_LEAF; - request->header.data_length = - sizeof(struct pw_request_remove_leaf_t) + - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE; - - request->data.remove_leaf.leaf_location = DEFAULT_LEAF.pub.label; - memcpy(request->data.remove_leaf.leaf_hmac, DEFAULT_HMAC, - sizeof(request->data.remove_leaf.leaf_hmac)); - setup_default_empty_path(request->data.remove_leaf.path_hashes); - - MOCK_setvar_ret = EC_SUCCESS; -} - -static void setup_try_auth_defaults_with_leaf( - const struct leaf_data_t *leaf_data, - uint8_t protocol_version, - uint8_t minor_version, - struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - struct leaf_header_t header = DEFAULT_HEAD; - - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE)); - if (leaf_data->pub.attempt_count.v != 6 && - leaf_data->pub.attempt_count.v != 10) { - memcpy(merkle_tree->root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - - /* Gets overwritten by auth_hash_update_cb. */ - MOCK_hmac = DEFAULT_HMAC; - } else - /* Gets overwritten by auth_hash_update_cb. */ - MOCK_hmac = EMPTY_HMAC; - - header.leaf_version.minor = minor_version; - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - request->header.version = protocol_version; - request->header.type.v = PW_TRY_AUTH; - request->header.data_length = - sizeof(struct pw_request_try_auth_t) + - PW_LEAF_PAYLOAD_SIZE + - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE; - - if (minor_version == 0) { - header.pub_len -= PW_VALID_PCR_CRITERIA_SIZE; - request->header.data_length -= PW_VALID_PCR_CRITERIA_SIZE; - } - - memcpy(request->data.try_auth.low_entropy_secret, - DEFAULT_LEAF.sec.low_entropy_secret, - sizeof(request->data.try_auth.low_entropy_secret)); - setup_default_unimported_leaf_data_and_hashes( - leaf_data, MOCK_hmac, &header, - &request->data.try_auth.unimported_leaf_data); - - force_restart_count(0); - force_time((timestamp_t){.val = 0}); - MOCK_rand_bytes_src = DEFAULT_IV; - MOCK_rand_bytes_offset = 0; - MOCK_rand_bytes_len = sizeof(DEFAULT_IV); - MOCK_hash_update_cb = auth_hash_update_cb; - MOCK_aes_fail = 0; - MOCK_setvar_ret = EC_SUCCESS; -} - -static void setup_try_auth_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - setup_try_auth_defaults_with_leaf(&DEFAULT_LEAF, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, merkle_tree, - request); -} - -static void setup_reset_auth_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - struct leaf_public_data_t *pub = - (void *)request->data.reset_auth.unimported_leaf_data - .payload; - - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - memcpy(merkle_tree, &EMPTY_TREE, sizeof(EMPTY_TREE)); - memset(&MOCK_pw_log_storage, 0, sizeof(MOCK_pw_log_storage)); - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_RESET_AUTH; - request->header.data_length = - sizeof(struct pw_request_reset_auth_t) + - PW_LEAF_PAYLOAD_SIZE + - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE; - - memcpy(request->data.reset_auth.reset_secret, - DEFAULT_LEAF.sec.reset_secret, - sizeof(request->data.reset_auth.reset_secret)); - - setup_default_unimported_leaf_data_and_hashes( - &DEFAULT_LEAF, EMPTY_HMAC, &DEFAULT_HEAD, - &request->data.try_auth.unimported_leaf_data); - pub->attempt_count.v = 6; - - MOCK_rand_bytes_src = DEFAULT_IV; - MOCK_rand_bytes_offset = 0; - MOCK_rand_bytes_len = sizeof(DEFAULT_IV); - MOCK_hash_update_cb = auth_hash_update_cb; - MOCK_hmac = EMPTY_HMAC; /* Gets overwritten by auth_hash_update_cb. */ - MOCK_aes_fail = 0; - MOCK_setvar_ret = EC_SUCCESS; -} - -static void setup_get_log_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memcpy(merkle_tree, &EMPTY_TREE, sizeof(*merkle_tree)); - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_GET_LOG; - request->header.data_length = sizeof(struct pw_request_get_log_t); - - /* Chosen not to match any of the root hashes in the log. */ - memcpy(request->data.get_log.root, OTHER_HMAC, - sizeof(OTHER_HMAC)); - - setup_storage(1); -} - -static void setup_log_replay_defaults_with_leaf( - const struct leaf_data_t *leaf_data, - struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - MOCK_DECRYPTO_init_counter = 0; - MOCK_DECRYPTO_release_counter = 0; - - memcpy(merkle_tree, &EMPTY_TREE, sizeof(*merkle_tree)); - if (leaf_data->pub.attempt_count.v != 6 && - leaf_data->pub.attempt_count.v != 10) - /* Gets overwritten by auth_hash_update_cb. */ - MOCK_hmac = DEFAULT_HMAC; - else - /* Gets overwritten by auth_hash_update_cb. */ - MOCK_hmac = EMPTY_HMAC; - - request->header.version = PW_PROTOCOL_VERSION; - request->header.type.v = PW_LOG_REPLAY; - request->header.data_length = - sizeof(struct pw_request_log_replay_t) + - PW_LEAF_PAYLOAD_SIZE + - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE; - - memcpy(request->data.log_replay.log_root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - - setup_default_unimported_leaf_data_and_hashes( - leaf_data, MOCK_hmac, &DEFAULT_HEAD, - &request->data.try_auth.unimported_leaf_data); - - MOCK_hash_update_cb = auth_hash_update_cb; - - setup_storage(4); -} - -static void setup_log_replay_defaults(struct merkle_tree_t *merkle_tree, - struct pw_request_t *request) -{ - setup_log_replay_defaults_with_leaf(&DEFAULT_LEAF, merkle_tree, - request); -} - -/* Increases the length of the pub and cipher_text by 4 each. */ -static void setup_mock_future_version( - struct unimported_leaf_data_t *unimported_leaf_data, - uint16_t *req_length) -{ - uint8_t *start = unimported_leaf_data->payload; - const uint8_t size_increase = 4; - const uint16_t cipher_text_offset = unimported_leaf_data->head.pub_len; - const uint16_t hashes_offset = cipher_text_offset + - unimported_leaf_data->head.sec_len; - - /* Shift hashes by 8*/ - memmove(start + hashes_offset + size_increase * 2, - start + hashes_offset, - get_path_auxiliary_hash_count(&EMPTY_TREE) * - PW_HASH_SIZE); - - /* Shift cipher_text by 4*/ - memmove(start + cipher_text_offset + size_increase, - start + cipher_text_offset, - unimported_leaf_data->head.sec_len); - - ++unimported_leaf_data->head.leaf_version.minor; - unimported_leaf_data->head.pub_len += size_increase; - unimported_leaf_data->head.sec_len += size_increase; - *req_length += size_increase * 2; -} - -static int test_handle_short_msg(struct merkle_tree_t *merkle_tree, - struct pw_test_data_t *buf, - const uint8_t root[PW_HASH_SIZE]) -{ - int ret = do_request(merkle_tree, buf); - - TEST_RET_EQ(buf->response.header.result_code, ret); - TEST_ASSERT(buf->response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf->response.header.data_length == 0); - TEST_ASSERT_ARRAY_EQ(buf->response.header.root, root, PW_HASH_SIZE); - TEST_ASSERT_ARRAY_EQ(buf->response.header.root, merkle_tree->root, - PW_HASH_SIZE); - return ret; -} - -/* Changes MOCK_hmac in a deterministic way based on the contents of the data - * with the goal of making it easier to catch bugs in the handling of try_auth - * and reset_auth requests. - */ -static void auth_hash_update_cb(const void *data, size_t len) -{ - const struct leaf_data_t *leaf_data = data; - - if (len != sizeof(leaf_data->pub) && len != sizeof(leaf_data->pub) + 4) - return; - - switch (leaf_data->pub.attempt_count.v) { - case 10: - case 6: - MOCK_hmac = EMPTY_HMAC; - break; - case 16: - MOCK_hmac = OTHER_HMAC; - break; - default: - MOCK_hmac = DEFAULT_HMAC; - break; - } -} - -/******************************************************************************/ -/* Mock implementations of TPM functionality. - */ - -void get_storage_seed(void *buf, size_t *len) -{ - *len = *len < sizeof(DEFAULT_STORAGE_SEED) ? *len : - sizeof(DEFAULT_STORAGE_SEED); - memcpy(buf, DEFAULT_STORAGE_SEED, *len); -} - -uint8_t get_current_pcr_digest(const uint8_t bitmask[2], - uint8_t sha256_of_selected_pcr[32]) -{ - memcpy(sha256_of_selected_pcr, DEFAULT_PCR_DIGEST, 32); - return 0; -} - -/******************************************************************************/ -/* Mock implementations of nvmem_vars functionality. - */ -const struct tuple *getvar(const uint8_t *key, uint8_t key_len) -{ - struct tuple *var = NULL; - size_t i; - - const struct { - size_t key_len; - const void *key; - size_t val_size; - const void *val; - } vars[] = { - {sizeof(PW_TREE_VAR) - 1, PW_TREE_VAR, - sizeof(MOCK_pw_long_term_storage), &MOCK_pw_long_term_storage}, - {sizeof(PW_LOG_VAR0) - 1, PW_LOG_VAR0, - sizeof(MOCK_pw_log_storage), &MOCK_pw_log_storage}, - }; - - if (!key || !key_len) - return NULL; - - if (MOCK_getvar_ret != EC_SUCCESS) - return NULL; - - for (i = 0; i < ARRAY_SIZE(vars); i++) { - if ((key_len != vars[i].key_len) || - memcmp(key, vars[i].key, key_len)) { - continue; - } - var = malloc(sizeof(struct tuple) + key_len + vars[i].val_size); - var->flags = 0; - var->val_len = vars[i].val_size; - memcpy(var->data_ + var->key_len, vars[i].val, var->val_len); - break; - } - - return var; -} - -void freevar(const struct tuple *var) -{ - if (!var) - return; - - /* This typecast is OK because we know that 'var' came from malloc. */ - free((void *)var); -} -const uint8_t *tuple_val(const struct tuple *tpl) -{ - return tpl->data_ + tpl->key_len; -} - -int setvar(const uint8_t *key, uint8_t key_len, const uint8_t *val, - uint8_t val_len) -{ - if (MOCK_setvar_ret != EC_SUCCESS) - return MOCK_setvar_ret; - - if (key_len == (sizeof(PW_TREE_VAR) - 1) && - memcmp(key, PW_TREE_VAR, (sizeof(PW_TREE_VAR) - 1)) == 0) { - TEST_ASSERT(val_len == sizeof(MOCK_pw_long_term_storage)); - memcpy(&MOCK_pw_long_term_storage, val, val_len); - return EC_SUCCESS; - } else if (key_len == (sizeof(PW_LOG_VAR0) - 1) && - memcmp(key, PW_LOG_VAR0, (sizeof(PW_LOG_VAR0) - 1)) == 0) { - TEST_ASSERT(val_len == sizeof(struct pw_log_storage_t)); - memcpy(&MOCK_pw_log_storage, val, val_len); - return EC_SUCCESS; - } else - return EC_ERROR_UNKNOWN; -} - -/******************************************************************************/ -/* Mock implementations of TRNG functionality. - */ - -void rand_bytes(void *buffer, size_t len) -{ - if (!MOCK_rand_bytes_src) - return; - - TEST_ASRT_NORET(len <= MOCK_rand_bytes_len - MOCK_rand_bytes_offset); - - memcpy(buffer, MOCK_rand_bytes_src + MOCK_rand_bytes_offset, len); - MOCK_rand_bytes_offset += len; - if (MOCK_rand_bytes_len == MOCK_rand_bytes_offset) - MOCK_rand_bytes_offset = 0; -} - -/******************************************************************************/ -/* Mock implementations of Dcrypto functionality. - */ - -void HASH_update(struct HASH_CTX *ctx, const void *data, size_t len) -{ - if (MOCK_hash_update_cb) - MOCK_hash_update_cb(data, len); - if (ctx) - SHA256_update(ctx, data, len); -} - -uint8_t *HASH_final(struct HASH_CTX *ctx) -{ - ++MOCK_DECRYPTO_release_counter; - return SHA256_final(ctx); -} - -void DCRYPTO_SHA256_init(LITE_SHA256_CTX *ctx, uint32_t sw_required) -{ - SHA256_init(ctx); - ++MOCK_DECRYPTO_init_counter; -} - -void DCRYPTO_HMAC_SHA256_init(LITE_HMAC_CTX *ctx, const void *key, - unsigned int len) -{ - TEST_ASRT_NORET(len == sizeof(EMPTY_TREE.hmac_key)); - TEST_ASRT_NORET(memcmp(key, EMPTY_TREE.hmac_key, - sizeof(EMPTY_TREE.hmac_key)) == 0); - SHA256_init(&ctx->hash); - ++MOCK_DECRYPTO_init_counter; -} - -const uint8_t *DCRYPTO_HMAC_final(LITE_HMAC_CTX *ctx) -{ - ++MOCK_DECRYPTO_release_counter; - return MOCK_hmac; -} - -/* Perform a symmetric transformation of the data to simulate AES without - * requiring a full AES-CTR implementation. - * - * 1 for success 0 for fail - */ -int DCRYPTO_aes_ctr(uint8_t *out, const uint8_t *key, uint32_t key_bits, - const uint8_t *iv, const uint8_t *in, size_t in_len) -{ - size_t x; - - if (MOCK_aes_fail) { - --MOCK_aes_fail; - return 0; - } - - TEST_ASSERT(key_bits == 256); - TEST_ASSERT_ARRAY_EQ(key, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key)); - TEST_ASSERT_ARRAY_EQ(iv, DEFAULT_IV, sizeof(DEFAULT_IV)); - TEST_ASSERT(in_len == sizeof(struct leaf_sensitive_data_t)); - - for (x = 0; x < in_len; ++x) - out[x] = MOCK_AES_XOR_BYTE(x) ^ in[x]; - return 1; -} - -/* 1 for success 0 for fail*/ -int DCRYPTO_appkey_init(enum dcrypto_appid appid, struct APPKEY_CTX *ctx) -{ - MOCK_hwctx_appkey = appid; - return 1; -} - -void DCRYPTO_appkey_finish(struct APPKEY_CTX *ctx) -{ - MOCK_hwctx_appkey = 0; -} - -/* 1 for success 0 for fail*/ -int DCRYPTO_appkey_derive(enum dcrypto_appid appid, const uint32_t input[8], - uint32_t output[8]) -{ - TEST_ASSERT(appid == PINWEAVER); - TEST_ASSERT(MOCK_hwctx_appkey == appid); - - if (MOCK_appkey_derive_fail != EC_SUCCESS) - return 0; - - if (input[6] ^ DEFAULT_STORAGE_SEED[6]) - memcpy(output, EMPTY_TREE.hmac_key, - sizeof(EMPTY_TREE.hmac_key)); - else - memcpy(output, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key)); - return 1; -} - -/******************************************************************************/ -/* Reusable test cases. - */ - -static int check_dcrypto_mutex_usage(void) -{ - if (MOCK_DECRYPTO_init_counter == MOCK_DECRYPTO_release_counter) - return EC_SUCCESS; - ccprintf("ASSERTION failed: DCRYPTO init(%zd) != DCRYPTO release(%zd)\n", - MOCK_DECRYPTO_init_counter, MOCK_DECRYPTO_release_counter); - return EC_ERROR_UNKNOWN; -} - -static int invalid_length_with_leaf_head( - size_t head_offset, - void (*defaults)(struct merkle_tree_t *, struct pw_request_t *)) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_header_t *req_head = (void *)&buf + head_offset; - uint8_t old_root[PW_HASH_SIZE]; - - defaults(&merkle_tree, &buf.request); - memcpy(old_root, merkle_tree.root, sizeof(old_root)); - - buf.request.header.data_length = 0; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root), - PW_ERR_LENGTH_INVALID); - - defaults(&merkle_tree, &buf.request); - - ++buf.request.header.data_length; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root), - PW_ERR_LENGTH_INVALID); - - defaults(&merkle_tree, &buf.request); - - ++req_head->pub_len; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root), - PW_ERR_LENGTH_INVALID); - - defaults(&merkle_tree, &buf.request); - - ++req_head->leaf_version.minor; - --req_head->pub_len; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, old_root), - PW_ERR_LENGTH_INVALID); - return check_dcrypto_mutex_usage(); - -} - -/******************************************************************************/ -/* Basic operation test cases. - */ - -static int get_path_auxiliary_hash_count_test(void) -{ - struct merkle_tree_t merkle_tree; - - memcpy(&merkle_tree, &EMPTY_TREE, sizeof(merkle_tree)); - - TEST_ASSERT(get_path_auxiliary_hash_count(&merkle_tree) == - EMPTY_TREE_PATH_LENGTH); - return EC_SUCCESS; -} - -static int compute_hash_test(void) -{ - const uint8_t hashes[4][PW_HASH_SIZE] = { - {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - {0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - }; - const struct { - struct index_t index; - uint8_t result[PW_HASH_SIZE]; - } test_cases[] = { - {{0}, - {0xd5, 0xd9, 0x25, 0xb6, 0xa9, 0x90, 0x24, 0x12, - 0x39, 0x0e, 0xfa, 0xd4, 0x8d, 0x55, 0x45, 0xf3, - 0x23, 0x6c, 0x6d, 0xff, 0xcc, 0xc8, 0xe1, 0x39, - 0xc7, 0xc3, 0x25, 0xf0, 0xd2, 0xa8, 0xf2, 0x0c} - }, - {{1}, - {0x64, 0x3e, 0x56, 0xbc, 0xb9, 0xda, 0x18, 0xaf, - 0xa0, 0x8c, 0x1f, 0xf8, 0x5e, 0xba, 0x58, 0xd0, - 0xe1, 0x99, 0x61, 0xe0, 0xe2, 0x12, 0xe9, 0x14, - 0xb5, 0x33, 0x46, 0x35, 0x52, 0x1e, 0xaf, 0x91} - }, - {{3}, - {0xd0, 0x90, 0xc7, 0x3d, 0x12, 0xfb, 0xbc, 0xbc, - 0x78, 0xcc, 0xbe, 0x58, 0x21, 0x14, 0xcf, 0x38, - 0x68, 0x49, 0x20, 0xe9, 0x61, 0xcb, 0x35, 0xc4, - 0x95, 0xb0, 0x14, 0x5a, 0x35, 0x43, 0x3e, 0x73} - }, - }; - uint8_t result[PW_HASH_SIZE]; - size_t x; - - for (x = 0; x < ARRAY_SIZE(test_cases); ++x) { - compute_hash(hashes, 3, test_cases[x].index, hashes[3], result); - TEST_ASSERT_ARRAY_EQ(result, test_cases[x].result, - sizeof(result)); - } - - return EC_SUCCESS; -} - -/******************************************************************************/ -/* Header validation test cases. - */ - -static int handle_request_version_mismatch(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - buf.request.header.version = PW_PROTOCOL_VERSION + 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC), - PW_ERR_VERSION_MISMATCH); - return EC_SUCCESS; -} - -static int handle_request_invalid_type(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - memcpy(&merkle_tree, &EMPTY_TREE, sizeof(merkle_tree)); - memset(&buf.response, 0x77, sizeof(buf.response)); - - buf.request.header.version = PW_PROTOCOL_VERSION; - buf.request.header.type.v = PW_MT_INVALID; - buf.request.header.data_length = 0; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_TYPE_INVALID); - return EC_SUCCESS; -} - -/******************************************************************************/ -/* Reset Tree test cases. - */ - -static int handle_reset_tree_invalid_length(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - ++buf.request.header.data_length; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC), - PW_ERR_LENGTH_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_tree_bits_per_level_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - /* Test lower bound. */ - buf.request.data.reset_tree.bits_per_level.v = BITS_PER_LEVEL_MIN - 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_BITS_PER_LEVEL_INVALID); - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - /* Test upper bound. */ - buf.request.data.reset_tree.bits_per_level.v = BITS_PER_LEVEL_MAX + 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC), - PW_ERR_BITS_PER_LEVEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_tree_height_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - /* Test lower bound. */ - buf.request.data.reset_tree.height.v = HEIGHT_MIN - 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_HEIGHT_INVALID); - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - /* Test upper bound. */ - buf.request.data.reset_tree.height.v = - HEIGHT_MAX(buf.request.data.reset_tree - .bits_per_level.v) + 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC), - PW_ERR_HEIGHT_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_tree_crypto_failure(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - /* Test lower bound. */ - MOCK_appkey_derive_fail = PW_ERR_CRYPTO_FAILURE; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_HMAC), - PW_ERR_CRYPTO_FAILURE); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_tree_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_NV_LENGTH_MISMATCH); - return EC_SUCCESS; -} - -static int handle_reset_tree_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_tree_defaults(&merkle_tree, &buf.request); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ((uint8_t *)&merkle_tree, (uint8_t *)&EMPTY_TREE, - sizeof(EMPTY_TREE)); - - TEST_ASSERT(MOCK_pw_long_term_storage.storage_version == - PW_STORAGE_VERSION); - TEST_ASSERT(MOCK_pw_long_term_storage.bits_per_level.v == - EMPTY_TREE.bits_per_level.v); - TEST_ASSERT(MOCK_pw_long_term_storage.height.v == - EMPTY_TREE.height.v); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_long_term_storage.key_derivation_nonce, - EMPTY_TREE.key_derivation_nonce, - sizeof(EMPTY_TREE.key_derivation_nonce)); - - TEST_ASSERT(MOCK_pw_log_storage.storage_version == PW_STORAGE_VERSION); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_RESET_TREE); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - EMPTY_TREE.root, sizeof(EMPTY_TREE.root)); - - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Insert leaf test cases. - */ - -static int handle_insert_leaf_invalid_length(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - ++buf.request.header.data_length; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_LENGTH_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_label_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - buf.request.data.insert_leaf.label.v |= 0x030000; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_LABEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_delay_schedule_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct delay_schedule_entry_t (*ds)[PW_SCHED_COUNT] = - &buf.request.data.insert_leaf.delay_schedule; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - /* Non-increasing attempt_count. */ - (*ds)[1].attempt_count.v = 0; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_DELAY_SCHEDULE_INVALID); - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - /* Non-increasing time_diff. */ - (*ds)[1].time_diff.v = 0; - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_DELAY_SCHEDULE_INVALID); - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - /* attempt_count noise. */ - (*ds)[14].attempt_count.v = 99; - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_DELAY_SCHEDULE_INVALID); - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - /* time_diff noise. */ - (*ds)[14].time_diff.v = 99; - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_DELAY_SCHEDULE_INVALID); - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - /* Empty delay_schedule. */ - memset(&(*ds)[0], 0, sizeof(*ds)); - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_DELAY_SCHEDULE_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_path_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - buf.request.data.insert_leaf.path_hashes[0][0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_PATH_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_crypto_failure(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - MOCK_aes_fail = 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_CRYPTO_FAILURE); - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_NV_LENGTH_MISMATCH); - return EC_SUCCESS; -} - -static int handle_insert_leaf_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - size_t x; - const uint8_t *plain_text = (const uint8_t *)&DEFAULT_LEAF.sec; - struct wrapped_leaf_data_t *wrapped_leaf_data = - (void *)&buf.response.data.insert_leaf - .unimported_leaf_data; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(buf.response.data.insert_leaf) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - PW_HASH_SIZE); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.insert_leaf.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ( - (uint8_t *)&wrapped_leaf_data->pub, - (uint8_t *)&DEFAULT_LEAF.pub, sizeof(DEFAULT_LEAF.pub)); - for (x = 0; x < sizeof(DEFAULT_LEAF.sec); ++x) - TEST_ASSERT(plain_text[x] == - (wrapped_leaf_data->cipher_text[x] ^ - MOCK_AES_XOR_BYTE(x))); - - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_INSERT_LEAF); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].leaf_hmac, - DEFAULT_HMAC, - sizeof(DEFAULT_HMAC)); - - return check_dcrypto_mutex_usage(); -} - -static int handle_insert_leaf_old_protocol_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - size_t x; - int hash_count; - unsigned char *src; - const uint8_t *plain_text = (const uint8_t *)&DEFAULT_LEAF.sec; - struct wrapped_leaf_data_t *wrapped_leaf_data = - (void *)&buf.response.data.insert_leaf - .unimported_leaf_data; - - setup_insert_leaf_defaults(&merkle_tree, &buf.request); - - // Make changes to simulate the protocol 0 request. - buf.request.header.version = 0; - hash_count = - get_path_auxiliary_hash_count(&merkle_tree); - src = (unsigned char *) - (&buf.request.data.insert_leaf.valid_pcr_criteria); - memmove(src, src + PW_VALID_PCR_CRITERIA_SIZE, - hash_count * PW_HASH_SIZE); - buf.request.header.data_length -= PW_VALID_PCR_CRITERIA_SIZE; - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == 0); - TEST_ASSERT(buf.response.header.data_length == - sizeof(buf.response.data.insert_leaf) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - PW_HASH_SIZE); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.insert_leaf.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ( - (uint8_t *)&wrapped_leaf_data->pub, - (uint8_t *)&DEFAULT_LEAF.pub, sizeof(DEFAULT_LEAF.pub)); - for (x = 0; x < sizeof(DEFAULT_LEAF.sec); ++x) - TEST_ASSERT(plain_text[x] == - (wrapped_leaf_data->cipher_text[x] ^ - MOCK_AES_XOR_BYTE(x))); - - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_INSERT_LEAF); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].leaf_hmac, - DEFAULT_HMAC, - sizeof(DEFAULT_HMAC)); - - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Remove leaf test cases. - */ - -static int handle_remove_leaf_invalid_length(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_remove_leaf_defaults(&merkle_tree, &buf.request); - - ++buf.request.header.data_length; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_LENGTH_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_remove_leaf_label_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_remove_leaf_defaults(&merkle_tree, &buf.request); - - buf.request.data.remove_leaf.leaf_location.v |= 0x030000; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_LABEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_remove_leaf_path_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_remove_leaf_defaults(&merkle_tree, &buf.request); - - buf.request.data.remove_leaf.path_hashes[0][0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_PATH_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_remove_leaf_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_remove_leaf_defaults(&merkle_tree, &buf.request); - - MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_NV_LENGTH_MISMATCH); - return EC_SUCCESS; -} - -static int handle_remove_leaf_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_remove_leaf_defaults(&merkle_tree, &buf.request); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - EC_SUCCESS); - - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == - PW_REMOVE_LEAF); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - EMPTY_TREE.root, sizeof(EMPTY_TREE.root)); - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Try auth test cases. - */ - -static int handle_try_auth_invalid_length(void) -{ - return invalid_length_with_leaf_head( - (size_t)&((struct pw_request_t *)0)->data.try_auth - .unimported_leaf_data.head, - setup_try_auth_defaults); -} - -static int handle_try_auth_leaf_version_mismatch(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_header_t *req_head = - &buf.request.data.try_auth.unimported_leaf_data.head; - - setup_try_auth_defaults(&merkle_tree, &buf.request); - - ++req_head->leaf_version.major; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_LEAF_VERSION_MISMATCH); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_label_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data; - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - leaf_data.pub.label.v |= 0x030000; - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_LABEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_path_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - uint8_t (*path_hashes)[32] = - (void *)buf.request.data.try_auth.unimported_leaf_data - .payload + - sizeof(struct leaf_public_data_t) + - sizeof(struct leaf_sensitive_data_t); - - setup_try_auth_defaults(&merkle_tree, &buf.request); - - (*path_hashes)[0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_PATH_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_hmac_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_try_auth_defaults(&merkle_tree, &buf.request); - - MOCK_hash_update_cb = 0; - MOCK_hmac = EMPTY_TREE.root; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_HMAC_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_crypto_failure(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_try_auth_defaults(&merkle_tree, &buf.request); - - MOCK_aes_fail = 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, - ROOT_WITH_DEFAULT_HMAC), - PW_ERR_CRYPTO_FAILURE); - return check_dcrypto_mutex_usage(); -} - -static int check_try_auth_rate_limit_reached_response( - struct merkle_tree_t *merkle_tree, - struct pw_test_data_t *buf, - const struct time_diff_t seconds_to_wait) -{ - uint8_t old_root[PW_HASH_SIZE]; - - memcpy(old_root, merkle_tree->root, sizeof(old_root)); - - TEST_RET_EQ(do_request(merkle_tree, buf), PW_ERR_RATE_LIMIT_REACHED); - - TEST_ASSERT(buf->response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf->response.header.data_length == - sizeof(struct pw_response_try_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf->response.header.result_code, - PW_ERR_RATE_LIMIT_REACHED); - TEST_ASSERT_ARRAY_EQ(buf->response.header.root, old_root, - sizeof(old_root)); - TEST_ASSERT_ARRAY_EQ(buf->response.header.root, merkle_tree->root, - sizeof(merkle_tree->root)); - TEST_ASSERT(buf->response.data.try_auth.seconds_to_wait.v == - seconds_to_wait.v); - TEST_ASSERT_MEMSET(buf->response.data.try_auth.high_entropy_secret, - 0, PW_SECRET_SIZE); - TEST_ASSERT_MEMSET((uint8_t *)&buf->response.data.try_auth - .unimported_leaf_data, 0, - sizeof(buf->response.data.try_auth - .unimported_leaf_data) + PW_LEAF_PAYLOAD_SIZE); - - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_rate_limit_reached(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - - /* Test PW_BLOCK_ATTEMPTS. */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - leaf_data.pub.attempt_count.v = 51; - force_restart_count(1); - force_time((timestamp_t){.val = 7200llu * SECOND}); - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - - TEST_RET_EQ(check_try_auth_rate_limit_reached_response( - &merkle_tree, &buf, - (const struct time_diff_t){PW_BLOCK_ATTEMPTS}), - EC_SUCCESS); - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - memset(leaf_data.pub.delay_schedule, 0, - sizeof(leaf_data.pub.delay_schedule)); - leaf_data.pub.delay_schedule[0].attempt_count.v = 5; - leaf_data.pub.delay_schedule[0].time_diff.v = PW_BLOCK_ATTEMPTS; - leaf_data.pub.attempt_count.v = 6; - force_restart_count(1); - force_time((timestamp_t){.val = 7200llu * SECOND}); - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - - TEST_RET_EQ(check_try_auth_rate_limit_reached_response( - &merkle_tree, &buf, - (const struct time_diff_t){PW_BLOCK_ATTEMPTS}), - EC_SUCCESS); - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - memset(leaf_data.pub.delay_schedule, 0, - sizeof(leaf_data.pub.delay_schedule)); - leaf_data.pub.delay_schedule[0].attempt_count.v = 5; - leaf_data.pub.delay_schedule[0].time_diff.v = PW_BLOCK_ATTEMPTS; - leaf_data.pub.attempt_count.v = 6; - force_restart_count(1); - force_time((timestamp_t){.val = 7200llu * SECOND}); - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - - TEST_RET_EQ(check_try_auth_rate_limit_reached_response( - &merkle_tree, &buf, - (const struct time_diff_t){PW_BLOCK_ATTEMPTS}), - EC_SUCCESS); - - /* Test same boot_count case. */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - leaf_data.pub.attempt_count.v = 10; - leaf_data.pub.timestamp.boot_count = 0; - leaf_data.pub.timestamp.timer_value = 7200llu; - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - force_restart_count(0); - force_time((timestamp_t){.val = (leaf_data.pub.timestamp.timer_value + - 3599llu) * SECOND}); - - TEST_RET_EQ(check_try_auth_rate_limit_reached_response( - &merkle_tree, &buf, (const struct time_diff_t){1}), - EC_SUCCESS); - - /* Test boot_count + 1 case. */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - leaf_data.pub.attempt_count.v = 10; - leaf_data.pub.timestamp.boot_count = 0; - leaf_data.pub.timestamp.timer_value = 7200llu; - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - force_restart_count(1); - force_time((timestamp_t){.val = 3599llu * SECOND}); - - TEST_RET_EQ(check_try_auth_rate_limit_reached_response( - &merkle_tree, &buf, (const struct time_diff_t){1}), - EC_SUCCESS); - - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_try_auth_defaults(&merkle_tree, &buf.request); - force_restart_count(0); - force_time((timestamp_t){.val = 65 * SECOND}); - - MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_NV_LENGTH_MISMATCH); - return EC_SUCCESS; -} - -static int handle_try_auth_lowent_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - struct leaf_public_data_t *pub = - (void *)buf.response.data.try_auth.unimported_leaf_data - .payload; - struct leaf_sensitive_data_t sec = {}; - uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub); - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(DEFAULT_LEAF)); - leaf_data.pub.attempt_count.v = 5; - leaf_data.sec.low_entropy_secret[ - sizeof(leaf_data.sec.low_entropy_secret) - 1] = - ~leaf_data.sec.low_entropy_secret[ - sizeof(leaf_data.sec.low_entropy_secret) - 1]; - - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - - force_restart_count(1); - force_time((timestamp_t){.val = (65ull * SECOND)}); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), PW_ERR_LOWENT_AUTH_FAILED); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_try_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, PW_ERR_LOWENT_AUTH_FAILED); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.try_auth.unimported_leaf_data.hmac, - EMPTY_HMAC, sizeof(EMPTY_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == leaf_data.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (uint8_t *)&pub->delay_schedule, - (uint8_t *)&leaf_data.pub.delay_schedule, - sizeof(leaf_data.pub.delay_schedule)); - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&leaf_data.sec, - sizeof(leaf_data.sec)); - TEST_ASSERT(pub->attempt_count.v == leaf_data.pub.attempt_count.v + 1); - TEST_ASSERT(pub->timestamp.boot_count == 1); - - TEST_ASSERT_MEMSET(buf.response.data.try_auth.high_entropy_secret, - 0, PW_SECRET_SIZE); - - /* A threshold of 100 is used since some time will pass after - * force_time() is called. - */ - TEST_ASSERT(pub->timestamp.timer_value - 65ull < 100); - - /* Validate the log entry for a failed auth attempt. */ - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == - PW_ERR_LOWENT_AUTH_FAILED); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count == - pub->timestamp.boot_count); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value == - pub->timestamp.timer_value); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_pcr_mismatch(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - - /* Test same boot_count case. */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.attempt_count.v = 6; - leaf_data.pub.valid_pcr_criteria[0].bitmask[0] = 1; - memset(leaf_data.pub.valid_pcr_criteria[0].digest, 0, 32); - setup_try_auth_defaults_with_leaf(&leaf_data, PW_PROTOCOL_VERSION, - PW_LEAF_MINOR_VERSION, &merkle_tree, - &buf.request); - force_restart_count(0); - force_time((timestamp_t){.val = 65 * SECOND}); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), PW_ERR_PCR_NOT_MATCH); - - return check_dcrypto_mutex_usage(); -} - -static int try_auth_success(uint8_t protocol_version, - uint8_t minor_version) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - struct leaf_public_data_t *pub = - (void *)buf.response.data.try_auth.unimported_leaf_data - .payload; - struct leaf_sensitive_data_t sec = {}; - uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub); - - /* Test same boot_count case. */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.attempt_count.v = 6; - leaf_data.pub.valid_pcr_criteria[0].bitmask[0] = 1; - memcpy(leaf_data.pub.valid_pcr_criteria[0].digest, - DEFAULT_PCR_DIGEST, 32); - setup_try_auth_defaults_with_leaf(&leaf_data, protocol_version, - minor_version, &merkle_tree, - &buf.request); - force_restart_count(0); - force_time((timestamp_t){.val = 65 * SECOND}); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == protocol_version); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_try_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.try_auth.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == leaf_data.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (uint8_t *)&pub->delay_schedule, - (uint8_t *)&leaf_data.pub.delay_schedule, - sizeof(leaf_data.pub.delay_schedule)); - if (protocol_version == PW_PROTOCOL_VERSION) { - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, - (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - } - TEST_ASSERT(pub->attempt_count.v == 0); - - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.high_entropy_secret, - DEFAULT_LEAF.sec.high_entropy_secret, - sizeof(DEFAULT_LEAF.sec.high_entropy_secret)); - - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.reset_secret, - DEFAULT_LEAF.sec.reset_secret, - sizeof(DEFAULT_LEAF.sec.reset_secret)); - - /* Validate the log entry on success. */ - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count == - pub->timestamp.boot_count); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value == - pub->timestamp.timer_value); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - - /* Test boot_count + 1 case. */ - leaf_data.pub.attempt_count.v = 6; - leaf_data.pub.timestamp.boot_count = 0; - leaf_data.pub.timestamp.timer_value = 7200llu; - setup_try_auth_defaults_with_leaf(&leaf_data, protocol_version, - minor_version, &merkle_tree, - &buf.request); - force_restart_count(1); - force_time((timestamp_t){.val = 65llu * SECOND}); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == protocol_version); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_try_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.try_auth.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == leaf_data.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (uint8_t *)&pub->delay_schedule, - (uint8_t *)&leaf_data.pub.delay_schedule, - sizeof(leaf_data.pub.delay_schedule)); - if (protocol_version == PW_PROTOCOL_VERSION) { - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, - (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - } - TEST_ASSERT(pub->attempt_count.v == 0); - TEST_ASSERT_ARRAY_EQ(buf.response.data.try_auth.high_entropy_secret, - DEFAULT_LEAF.sec.high_entropy_secret, - sizeof(DEFAULT_LEAF.sec.high_entropy_secret)); - return check_dcrypto_mutex_usage(); -} - -static int handle_try_auth_success(void) -{ - return try_auth_success(PW_PROTOCOL_VERSION, PW_LEAF_MINOR_VERSION); -} - -static int handle_try_auth_old_protocol_old_leaf_success(void) -{ - return try_auth_success(0, 0); -} - -static int handle_try_auth_old_protocol_new_leaf_success(void) -{ - return try_auth_success(0, PW_LEAF_MINOR_VERSION); -} - -/******************************************************************************/ -/* Reset auth test cases. - */ - -static int handle_reset_auth_invalid_length(void) -{ - return invalid_length_with_leaf_head( - (size_t)&((struct pw_request_t *)0)->data.reset_auth - .unimported_leaf_data.head, - setup_reset_auth_defaults); -} - -static int handle_reset_auth_label_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_public_data_t *pub = - (void *)buf.request.data.reset_auth.unimported_leaf_data - .payload; - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - pub->label.v |= 0x030000; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_LABEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_auth_path_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - uint8_t (*path_hashes)[32] = - (void *)buf.request.data.reset_auth.unimported_leaf_data - .payload + - sizeof(struct leaf_public_data_t) + - sizeof(struct leaf_sensitive_data_t); - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - (*path_hashes)[0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_PATH_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_auth_hmac_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - MOCK_hash_update_cb = 0; - MOCK_hmac = EMPTY_TREE.root; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_HMAC_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_auth_crypto_failure(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - MOCK_aes_fail = 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_CRYPTO_FAILURE); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_auth_reset_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - buf.request.data.reset_auth.reset_secret[0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_RESET_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_reset_auth_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - MOCK_setvar_ret = PW_ERR_NV_LENGTH_MISMATCH; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, merkle_tree.root), - PW_ERR_NV_LENGTH_MISMATCH); - return EC_SUCCESS; -} - -static int handle_reset_auth_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_public_data_t *pub = - (void *)buf.response.data.reset_auth - .unimported_leaf_data.payload; - struct leaf_sensitive_data_t sec = {}; - uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub); - - setup_reset_auth_defaults(&merkle_tree, &buf.request); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_reset_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.high_entropy_secret, - DEFAULT_LEAF.sec.high_entropy_secret, - sizeof(DEFAULT_LEAF.sec.high_entropy_secret)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (const uint8_t *)&pub->delay_schedule, - (const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule, - sizeof(DEFAULT_LEAF.pub.delay_schedule)); - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - TEST_ASSERT(pub->attempt_count.v == 0); - - /* Validate the log entry on success. */ - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count == - pub->timestamp.boot_count); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value == - pub->timestamp.timer_value); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - - /* Test with different minor version and struct lengths. */ - setup_reset_auth_defaults(&merkle_tree, &buf.request); - setup_mock_future_version( - &buf.request.data.reset_auth.unimported_leaf_data, - &buf.request.header.data_length); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_reset_auth_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.high_entropy_secret, - DEFAULT_LEAF.sec.high_entropy_secret, - sizeof(DEFAULT_LEAF.sec.high_entropy_secret)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.reset_auth.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (const uint8_t *)&pub->delay_schedule, - (const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule, - sizeof(DEFAULT_LEAF.pub.delay_schedule)); - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - TEST_ASSERT(pub->attempt_count.v == 0); - - /* Validate the log entry on success. */ - TEST_ASSERT(MOCK_pw_log_storage.entries[0].type.v == PW_TRY_AUTH); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].label.v == - DEFAULT_LEAF.pub.label.v); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].return_code == EC_SUCCESS); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.boot_count == - pub->timestamp.boot_count); - TEST_ASSERT(MOCK_pw_log_storage.entries[0].timestamp.timer_value == - pub->timestamp.timer_value); - TEST_ASSERT_ARRAY_EQ(MOCK_pw_log_storage.entries[0].root, - ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Get log test cases. - */ - -static int handle_get_log_invalid_length(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_get_log_defaults(&merkle_tree, &buf.request); - - ++buf.request.header.data_length; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_LENGTH_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_get_log_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_get_log_defaults(&merkle_tree, &buf.request); - - MOCK_getvar_ret = PW_ERR_NV_EMPTY; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_NV_EMPTY); - return check_dcrypto_mutex_usage(); -} - -static int handle_get_log_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - const struct pw_get_log_entry_t (*view)[PW_LOG_ENTRY_COUNT] = - (void *)buf.response.data.get_log; - - setup_get_log_defaults(&merkle_tree, &buf.request); - setup_storage(4); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_get_log_entry_t) * PW_LOG_ENTRY_COUNT); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - - TEST_ASSERT((*view)[0].type.v == PW_REMOVE_LEAF); - TEST_ASSERT((*view)[0].label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ((*view)[0].root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - - TEST_ASSERT((*view)[1].type.v == PW_TRY_AUTH); - TEST_ASSERT((*view)[1].label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT((*view)[1].return_code == EC_SUCCESS); - TEST_ASSERT((*view)[1].timestamp.boot_count == 10); - TEST_ASSERT((*view)[1].timestamp.timer_value == 100); - TEST_ASSERT_ARRAY_EQ((*view)[1].root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - - setup_get_log_defaults(&merkle_tree, &buf.request); - setup_storage(2); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT((*view)[0].type.v == PW_TRY_AUTH); - TEST_ASSERT((*view)[0].label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT((*view)[0].return_code == PW_ERR_LOWENT_AUTH_FAILED); - TEST_ASSERT((*view)[0].timestamp.boot_count == 7); - TEST_ASSERT((*view)[0].timestamp.timer_value == 99); - TEST_ASSERT_ARRAY_EQ((*view)[0].root, ROOT_WITH_OTHER_HMAC, - sizeof(ROOT_WITH_OTHER_HMAC)); - - TEST_ASSERT((*view)[1].type.v == PW_INSERT_LEAF); - TEST_ASSERT((*view)[1].label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ((*view)[1].root, ROOT_WITH_DEFAULT_HMAC, - sizeof(ROOT_WITH_DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ((*view)[1].leaf_hmac, DEFAULT_HMAC, - sizeof(DEFAULT_HMAC)); - - setup_get_log_defaults(&merkle_tree, &buf.request); - setup_storage(0); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT((*view)[0].type.v == PW_RESET_TREE); - TEST_ASSERT_ARRAY_EQ((*view)[0].root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Log replay test cases. - */ - -static int handle_log_replay_invalid_length(void) -{ - return invalid_length_with_leaf_head( - (size_t)&((struct pw_request_t *)0)->data.log_replay - .unimported_leaf_data.head, - setup_log_replay_defaults); -} - -static int handle_log_replay_nv_fail(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_log_replay_defaults(&merkle_tree, &buf.request); - - MOCK_getvar_ret = PW_ERR_NV_EMPTY; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_NV_EMPTY); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_root_not_found(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_log_replay_defaults(&merkle_tree, &buf.request); - - memcpy(buf.request.data.log_replay.log_root, DEFAULT_HMAC, - sizeof(DEFAULT_HMAC)); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_ROOT_NOT_FOUND); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_type_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - - setup_log_replay_defaults(&merkle_tree, &buf.request); - - memcpy(buf.request.data.log_replay.log_root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_TYPE_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_hmac_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.attempt_count.v = 7; - setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree, - &buf.request); - - memcpy(buf.request.data.log_replay.unimported_leaf_data.hmac, - EMPTY_HMAC, sizeof(EMPTY_HMAC)); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_HMAC_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_crypto_failure(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.attempt_count.v = 7; - setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree, - &buf.request); - - MOCK_aes_fail = 1; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_CRYPTO_FAILURE); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_label_invalid(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.label.v = 0; - setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree, - &buf.request); - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_LABEL_INVALID); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_path_auth_failed(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - uint8_t (*path_hashes)[32] = - (void *)buf.request.data.log_replay.unimported_leaf_data - .payload + - sizeof(struct leaf_public_data_t) + - sizeof(struct leaf_sensitive_data_t); - - setup_log_replay_defaults(&merkle_tree, &buf.request); - - (*path_hashes)[0] ^= 0xff; - - TEST_RET_EQ(test_handle_short_msg(&merkle_tree, &buf, EMPTY_TREE.root), - PW_ERR_PATH_AUTH_FAILED); - return check_dcrypto_mutex_usage(); -} - -static int handle_log_replay_success(void) -{ - struct merkle_tree_t merkle_tree; - struct pw_test_data_t buf; - struct leaf_data_t leaf_data = {}; - struct leaf_public_data_t *pub = - (void *)buf.response.data.log_replay - .unimported_leaf_data.payload; - struct leaf_sensitive_data_t sec = {}; - uint8_t *resp_cipher_text = (void *)pub + sizeof(*pub); - - /* - * Test for auth success. - */ - setup_log_replay_defaults(&merkle_tree, &buf.request); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_log_replay_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.log_replay.unimported_leaf_data.hmac, - DEFAULT_HMAC, sizeof(DEFAULT_HMAC)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.log_replay.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (const uint8_t *)&pub->delay_schedule, - (const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule, - sizeof(DEFAULT_LEAF.pub.delay_schedule)); - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - TEST_ASSERT(pub->attempt_count.v == 0); - TEST_ASSERT(pub->timestamp.boot_count == 10); - TEST_ASSERT(pub->timestamp.timer_value == 100); - - /* - * Test for auth failed. - */ - memcpy(&leaf_data, &DEFAULT_LEAF, sizeof(leaf_data)); - leaf_data.pub.attempt_count.v = 15; - setup_log_replay_defaults_with_leaf(&leaf_data, &merkle_tree, - &buf.request); - memcpy(buf.request.data.log_replay.log_root, ROOT_WITH_OTHER_HMAC, - sizeof(ROOT_WITH_OTHER_HMAC)); - setup_storage(2); - - TEST_RET_EQ(do_request(&merkle_tree, &buf), EC_SUCCESS); - - TEST_ASSERT(buf.response.header.version == PW_PROTOCOL_VERSION); - TEST_ASSERT(buf.response.header.data_length == - sizeof(struct pw_response_log_replay_t) + - PW_LEAF_PAYLOAD_SIZE); - TEST_RET_EQ(buf.response.header.result_code, EC_SUCCESS); - - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, EMPTY_TREE.root, - sizeof(EMPTY_TREE.root)); - TEST_ASSERT_ARRAY_EQ(buf.response.header.root, merkle_tree.root, - sizeof(merkle_tree.root)); - - TEST_ASSERT_ARRAY_EQ( - buf.response.data.log_replay.unimported_leaf_data.hmac, - OTHER_HMAC, sizeof(OTHER_HMAC)); - TEST_ASSERT_ARRAY_EQ( - buf.response.data.log_replay.unimported_leaf_data.iv, - DEFAULT_IV, sizeof(DEFAULT_IV)); - DCRYPTO_aes_ctr((uint8_t *)&sec, EMPTY_TREE.wrap_key, - sizeof(EMPTY_TREE.wrap_key) * 8, DEFAULT_IV, - resp_cipher_text, sizeof(sec)); - TEST_ASSERT(pub->label.v == DEFAULT_LEAF.pub.label.v); - TEST_ASSERT_ARRAY_EQ( - (const uint8_t *)&pub->delay_schedule, - (const uint8_t *)&DEFAULT_LEAF.pub.delay_schedule, - sizeof(DEFAULT_LEAF.pub.delay_schedule)); - TEST_ASSERT_ARRAY_EQ((uint8_t *)&sec, (uint8_t *)&DEFAULT_LEAF.sec, - sizeof(DEFAULT_LEAF.sec)); - TEST_ASSERT(pub->attempt_count.v == 16); - TEST_ASSERT(pub->timestamp.boot_count == 7); - TEST_ASSERT(pub->timestamp.timer_value == 99); - return check_dcrypto_mutex_usage(); -} - -/******************************************************************************/ -/* Main test function. Encapsulates the test cases.. - */ - -void run_test(void) -{ - test_reset(); - - /* Test basic operations. */ - RUN_TEST(get_path_auxiliary_hash_count_test); - RUN_TEST(compute_hash_test); - - /* Test header validation. */ - RUN_TEST(handle_request_version_mismatch); - RUN_TEST(handle_request_invalid_type); - - /* Test reset tree. */ - RUN_TEST(handle_reset_tree_invalid_length); - RUN_TEST(handle_reset_tree_bits_per_level_invalid); - RUN_TEST(handle_reset_tree_height_invalid); - RUN_TEST(handle_reset_tree_crypto_failure); - RUN_TEST(handle_reset_tree_nv_fail); - RUN_TEST(handle_reset_tree_success); - - /* Test insert leaf. */ - RUN_TEST(handle_insert_leaf_invalid_length); - RUN_TEST(handle_insert_leaf_label_invalid); - RUN_TEST(handle_insert_leaf_delay_schedule_invalid); - RUN_TEST(handle_insert_leaf_path_auth_failed); - RUN_TEST(handle_insert_leaf_crypto_failure); - RUN_TEST(handle_insert_leaf_nv_fail); - RUN_TEST(handle_insert_leaf_success); - RUN_TEST(handle_insert_leaf_old_protocol_success); - - /* Test remove leaf. */ - RUN_TEST(handle_remove_leaf_invalid_length); - RUN_TEST(handle_remove_leaf_label_invalid); - RUN_TEST(handle_remove_leaf_path_auth_failed); - RUN_TEST(handle_remove_leaf_nv_fail); - RUN_TEST(handle_remove_leaf_success); - - /* Test try auth. */ - RUN_TEST(handle_try_auth_invalid_length); - RUN_TEST(handle_try_auth_leaf_version_mismatch); - RUN_TEST(handle_try_auth_label_invalid); - RUN_TEST(handle_try_auth_path_auth_failed); - RUN_TEST(handle_try_auth_hmac_auth_failed); - RUN_TEST(handle_try_auth_crypto_failure); - RUN_TEST(handle_try_auth_rate_limit_reached); - RUN_TEST(handle_try_auth_nv_fail); - RUN_TEST(handle_try_auth_lowent_auth_failed); - RUN_TEST(handle_try_auth_pcr_mismatch); - RUN_TEST(handle_try_auth_success); - RUN_TEST(handle_try_auth_old_protocol_old_leaf_success); - RUN_TEST(handle_try_auth_old_protocol_new_leaf_success); - - /* Test reset auth. */ - RUN_TEST(handle_reset_auth_invalid_length); - RUN_TEST(handle_reset_auth_label_invalid); - RUN_TEST(handle_reset_auth_path_auth_failed); - RUN_TEST(handle_reset_auth_hmac_auth_failed); - RUN_TEST(handle_reset_auth_crypto_failure); - RUN_TEST(handle_reset_auth_reset_auth_failed); - RUN_TEST(handle_reset_auth_nv_fail); - RUN_TEST(handle_reset_auth_success); - - /* Test get log. */ - RUN_TEST(handle_get_log_invalid_length); - RUN_TEST(handle_get_log_nv_fail); - RUN_TEST(handle_get_log_success); - - /* Test log replay. */ - RUN_TEST(handle_log_replay_invalid_length); - RUN_TEST(handle_log_replay_nv_fail); - RUN_TEST(handle_log_replay_root_not_found); - RUN_TEST(handle_log_replay_type_invalid); - RUN_TEST(handle_log_replay_hmac_auth_failed); - RUN_TEST(handle_log_replay_crypto_failure); - RUN_TEST(handle_log_replay_label_invalid); - RUN_TEST(handle_log_replay_path_auth_failed); - RUN_TEST(handle_log_replay_success); - - test_print_result(); -} diff --git a/test/pinweaver.tasklist b/test/pinweaver.tasklist deleted file mode 100644 index 24870f2abb..0000000000 --- a/test/pinweaver.tasklist +++ /dev/null @@ -1,9 +0,0 @@ -/* Copyright 2018 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. - */ - -/** - * See CONFIG_TASK_LIST in config.h for details. - */ -#define CONFIG_TEST_TASK_LIST diff --git a/test/rma_auth.tasklist b/test/rma_auth.tasklist deleted file mode 100644 index 7150f17cbd..0000000000 --- a/test/rma_auth.tasklist +++ /dev/null @@ -1,9 +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. - */ - -/** - * See CONFIG_TASK_LIST in config.h for details. - */ -#define CONFIG_TEST_TASK_LIST /* No test task */ diff --git a/test/test_config.h b/test/test_config.h index 65e8ccffd4..ce49862647 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -456,43 +456,6 @@ int ncp15wb_calculate_temp(uint16_t adc); #define CONFIG_USB_PD_PORT_MAX_COUNT 2 #endif -#if defined(TEST_NVMEM) || defined(TEST_NVMEM_VARS) -#define CONFIG_CRC8 -#define CONFIG_FLASH_ERASED_VALUE32 (-1U) -#define CONFIG_FLASH_LOG -#define CONFIG_FLASH_LOG_BASE CONFIG_PROGRAM_MEMORY_BASE -#define CONFIG_FLASH_LOG_SPACE 0x800 -#define CONFIG_FLASH_NVMEM -#define CONFIG_FLASH_NVMEM_OFFSET_A 0x3d000 -#define CONFIG_FLASH_NVMEM_OFFSET_B 0x7d000 -#define CONFIG_FLASH_NVMEM_BASE_A \ - (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_A) -#define CONFIG_FLASH_NVMEM_BASE_B \ - (CONFIG_PROGRAM_MEMORY_BASE + CONFIG_FLASH_NVMEM_OFFSET_B) -#define CONFIG_FLASH_NEW_NVMEM_BASE_A (CONFIG_FLASH_NVMEM_BASE_A + 0x800) -#define CONFIG_FLASH_NEW_NVMEM_BASE_B (CONFIG_FLASH_NVMEM_BASE_B + 0x800) -#define CONFIG_MALLOC -/* This is legacy NVMEM partition size. */ -#define NVMEM_PARTITION_SIZE 0x3000 -#define NEW_FLASH_HALF_NVMEM_SIZE \ - (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) -#define NEW_NVMEM_PARTITION_SIZE (NVMEM_PARTITION_SIZE - CONFIG_FLASH_BANK_SIZE) -#define NEW_NVMEM_TOTAL_PAGES \ - (2 * NEW_NVMEM_PARTITION_SIZE / CONFIG_FLASH_BANK_SIZE) -#define CONFIG_SW_CRC -#define CONFIG_FLASH_NVMEM_VARS - -#ifndef __ASSEMBLER__ -enum nvmem_users { NVMEM_TPM = 0, NVMEM_CR50, NVMEM_NUM_USERS }; -#endif -#endif - -#ifdef TEST_PINWEAVER -#define CONFIG_DCRYPTO_MOCK -#define CONFIG_PINWEAVER -#define CONFIG_SHA256 -#endif /* TEST_PINWEAVER */ - #ifdef TEST_RTC #define CONFIG_HOSTCMD_RTC #endif diff --git a/util/g_regs b/util/g_regs deleted file mode 100755 index 28e6f4a53d..0000000000 --- a/util/g_regs +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/perl -# Copyright 2015 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. - -use strict; -our $opt_D; - -use File::Basename; -my $progdir = dirname($0); -my $prog = basename($0); - -use Getopt::Std; -my $usage = " -Usage: $prog [HEADER] - -This converts the FPGA release's generated C header file into the -hw_regdefs.h file that is included by chip/g/registers.h. -Mostly it just prefaces the macros with GC_ to avoid name collision. - -"; -getopts('D') or die $usage; - - -print "/* - * Copyright 2015 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. - */ - -/* This file is autogenerated by the $prog utility. Do not edit. */ - -"; - -while(<>) -{ - if ( s/\b\w+_REGDEFS_H/__EC_CHIP_G_CR50_FPGA_REGDEFS_H/g ) - { - print; - next; - } - - if ( s/__ENABLE_FLASH_DFT_DEFINITIONS__/GC__ENABLE_FLASH_DFT_DEFINITIONS__/g ) - { - print; - next; - } - - if ( s/\bFLASH_DFT/GC_FLASH_DFT/g ) - { - print; - next; - } - - if ( m/^#define\s+(\S+)\s+(\S+)\s*$/ ) - { - my ($k,$v) = ($1,$2); - - if ($k =~ m/^IRQNUM/) { - # irqnums must be decimal - $v = 0 + hex($v); - } - $k = "GC_$k"; - printf("#define %-40s %s\n", $k, $v); - if ( $k =~ m/0_BASE_ADDR$/ ) { - $k =~ s/0_BASE_ADDR/_BASE_ADDR/; - printf("#define %-40s %s\n", $k, $v); - } - next; - } - - next if m!//!; - next if m!/\*! .. m!\*/!; - - print; -} - diff --git a/util/signer/bs b/util/signer/bs deleted file mode 100755 index 23ee46039a..0000000000 --- a/util/signer/bs +++ /dev/null @@ -1,342 +0,0 @@ -#!/bin/bash - -# -# Copyright 2016 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. -# -# This script is a utility which allows to create differently signed CR50 -# images from different sources. -# -set -e -set -u - -progname=$(basename $0) - -OD="/usr/bin/od" - -tmpf="/tmp/bs_manifest.$$" -trap "{ if [[ -f 1.flat ]]; then rm -rf [01].flat ${tmpf} ; fi; }" EXIT - -usage() { - local rv="${1}" - cat <<EOF - -This script allows to sign CR50 RW images. By default it uses ec.RW.elf and -ec.RW_B.elf in build/cr50/RW as inputs and util/signer/ec_RW-manifest-dev.json -as the manifest, and places the newly signed images into build/cr50/ec.bin. - -The only outside dependency of this script is the signing utility itself, -which is expected to be available as /usr/bin/cr50-codesigner. - -The utility can be installed by running 'sudo emerge cr50-utils', - -The following command line options are accepted: - - b1 - generate signature for the b1 version of the H1 chip - elves <elf1> <elf2> - sign the supplied elf files instead of the default - ones. Handy if the builder generated files need to be signed - help - print this message - hex - generate hex output instead of binary (place in 0.signed.hex and - 1.signed.hex in the local directory) - prod - sign with prod key (no debug image will be signed) - -This script also allows to sign dev images for running on prod RO. To do that -invoke this script as follows: - - H1_DEVIDS='<dev id0> <dev id1>' ${progname} [other options, if any] - -where <dev id0> <dev id1> are values reported by sysinfo command in the -DEV_ID: line when run on the CR50 for which the image is built. - -The same values can be obtained in the lsusb command output: - - lsusb -vd 18d1:5014 | grep -i serial - -note that the lsusb reported values are in hex and need to be prefixed with -0x. - -Finally, this script also allows to specify the board ID fields of the RW -headers. The fields come from the evironment variable CR50_BOARD_ID, which is -required to include three colon separated fields. The first field is a four -letter board RLZ code, the second field is board id mask in hex, no 0x prefix, -and the third field - board ID flags, again, hex, no 0x prefix. - -CR50_BOARD_ID='XXYY:ffffff00:ff00' ${progname} [other options, if any] - -both H1_DEVIDS and CR50_BOARD_ID can be defined independently. - -EOF - exit "${rv}" -} - -# This function modifies the manifest to include device ID and board ID nodes, -# if H1_DEVIDS and CR50_BOARD_ID are defined in the environment, respectively, -tweak_manifest () { - local sub - - # If defined, plug in dev ID nodes before the 'fuses' node. - if [[ -z "${do_prod}" && -n "${H1_DEVIDS}" ]]; then - echo "creating a customized DEV image for DEV IDS ${H1_DEVIDS}" - sub=$(printf "\\\n \"DEV_ID0\": %s,\\\n \"DEV_ID1\": %s," ${H1_DEVIDS}) - sed -i "s/\"fuses\": {/\"fuses\": {${sub}/" "${tmpf}" - fi - - if [[ -z "${CR50_BOARD_ID}" ]]; then - return - fi - - # CR50_BOARD_ID is set, let's parse it and plug in the board ID related - # nodes into manifest before the 'fuses' node. - local bid_params - local rlz - - bid_params=( $(echo $CR50_BOARD_ID | sed 's/:/ /g') ) - # A very basic sanity check: it needs to consist of three colon separated - # fields. - if [[ ${#bid_params[@]} != 3 ]]; then - echo "Wrong board ID string \"$CR50_BOARD_ID\"}" >&2 - exit 1 - fi - - if [[ "${bid_params[0]}" == "0" ]] ; then - rlz="0" - elif [[ ${#bid_params[0]} == 4 ]] ; then - # Convert 4 char board RLZ code from ASCII to hex - rlz="0x$(echo -n ${bid_params[0]} | hexdump -ve '/1 "%02x"')" - else - echo "Invalid RLZ ${bid_params[0]}" - exit 1 - fi - - # Prepare text of all three board ID related nodes - sub="$(printf "\\\n\"board_id\": %s,\\\n" "${rlz}")" - sub+="$(printf "\"board_id_mask\": %s,\\\n" "0x${bid_params[1]}")" - sub+="$(printf "\"board_id_flags\": %s,\\\n" "0x${bid_params[2]}")" - sed -i "s/\"fuses\": {/${sub}\"fuses\": {/" "${tmpf}" -} - -# This function accepts two arguments, names of two binary files. -# -# It searches the first passed in file for the first 8 bytes of the second -# passed in file. The od utility is used to generate full hex dump of the -# first file (16 bytes per line) and the first 8 bytes of the second file. -# -# grep is used to check if the pattern is present in the full dump. If the -# pattern is not found, the first file is dumped again, this time with an 8 -# byte offset into the file. This makes sure that if the match is present, but -# is spanning two lines of the original hex dump, it is in a single dump line -# the second time around. -find_blob_in_blob() { - local main_blob="${1}" - local pattern_blob="${2}" - local pattern - local od_options="-An -tx1" - - # Get the first 8 bytes of the pattern blob. - pattern="$(${OD} ${od_options} -N8 "${pattern_blob}")" - - if "${OD}" ${od_options} "${main_blob}" | grep "${pattern}" > /dev/null; then - return 0 - fi - - # Just in case pattern was wrapped in the previous od output, let's do it - # again with an 8 bytes offset - if "${OD}" ${od_options} -j8 "${main_blob}" | - grep "${pattern}" > /dev/null; then - return 0 - fi - - return 1 -} - -# This function accepts two arguments, names of the two elf files. -# -# The files are searched for test RMA public key patterns - x25519 or p256, -# both files are supposed to have pattern of one of these keys and not the -# other. If this holds true the function prints the public key base name. If -# not both files include the same key, or include more than one key, the -# function reports failure and exits the script. -determine_rma_key_base() { - local base_name="${EC_ROOT}/board/cr50/rma_key_blob" - local curve - local curves=( "x25519" "p256" ) - local elf - local elves=( "$1" "$2" ) - local key_file - local mask=1 - local result=0 - - for curve in ${curves[@]}; do - key_file="${base_name}.${curve}.test" - for elf in ${elves[@]}; do - if find_blob_in_blob "${elf}" "${key_file}"; then - result=$(( result | mask )) - fi - mask=$(( mask << 1 )) - done - done - - case "${result}" in - (3) curve="x25519";; - (12) curve="p256";; - (*) echo "could not determine key type in the elves" >&2 - exit 1 - ;; - esac - - echo "${base_name}.${curve}" -} - -SIGNER="cr50-codesigner" -if ! which "${SIGNER}" 2>/dev/null > /dev/null; then - echo "${SIGNER} is not available, try running 'sudo emerge cr50-utils'" >&2 - exit 1 -fi - -# This is where the new signed image will be pasted into. -: ${RESULT_FILE=build/cr50/ec.bin} -TMP_RESULT_FILE="${RESULT_FILE}.tmp" - -if [[ -z "${CROS_WORKON_SRCROOT}" ]]; then - echo "${progname}: This script must run inside Chrome OS chroot" >&2 - exit 1 -fi - -: ${CR50_BOARD_ID=} -: ${H1_DEVIDS=} -EC_ROOT="${CROS_WORKON_SRCROOT}/src/platform/ec" -EC_BIN_ROOT="${EC_ROOT}/util/signer" - -do_hex= -do_b1= -do_prod= - -# Prepare the default manifest. -cp "${EC_BIN_ROOT}/ec_RW-manifest-dev.json" "${tmpf}" - -elves=( build/cr50/RW/ec.RW.elf build/cr50/RW/ec.RW_B.elf ) -cd "${EC_ROOT}" -while (( $# )); do - param="${1}" - case "${param}" in - (hex) do_hex='true';; - (b1) - do_b1='true' - sed -i 's/\(.*FW_DEFINED_DATA_BLK0.*\): 2/\1: 0/' "${tmpf}" - ;; - (elves) - if [[ (( $# < 3 )) ]]; then - echo "two elf file names are required" >&2 - exit 1 - fi - elves=( $2 $3 ) - shift - shift - ;; - (prod) - do_prod='true' - ;; - (help) - usage 0 - ;; - (*) - usage 1 - ;; - esac - shift -done - -if [[ -z "${do_hex}" && ! -f "${RESULT_FILE}" ]]; then - echo "${RESULT_FILE} not found. Run 'make BOARD=cr50' first" >&2 - exit 1 -fi - -if [[ -n "${do_prod}" && -n "${do_b1}" ]]; then - echo "can not build prod images for B1, sorry..." - exit 1 -fi - -# If signing a chip factory image (version 0.0.22) do not try figuring out the -# RMA keys. -ignore_rma_keys="$(awk ' - BEGIN {count = 0}; - /"major": 0,/ {count += 1}; - /"minor": 22,/ {count += 1}; - END {{if (count == 2) {print "yes"};}}' \ - "${EC_BIN_ROOT}/ec_RW-manifest-prod.json")" - -if [ "${ignore_rma_keys}" != "yes" ]; then - rma_key_base="$(determine_rma_key_base ${elves[@]})" -else - echo "Ignofing RMA keys for factory branch" -fi - -signer_command_params=() -signer_command_params+=(--b -x ${EC_BIN_ROOT}/fuses.xml) -if [[ -z "${do_prod}" ]]; then - signer_command_params+=(-k ${EC_BIN_ROOT}/cr50_rom0-dev-blsign.pem.pub) -else - cp "${EC_BIN_ROOT}/ec_RW-manifest-prod.json" "${tmpf}" - signer_command_params+=(-k ${EC_BIN_ROOT}/cr50_RW-prod.pem.pub) - # Swap test public RMA server key with the prod version. - if [ "${ignore_rma_keys}" != "yes" ]; then - signer_command_params+=(-S "${rma_key_base}.test","${rma_key_base}.prod") - fi -fi -signer_command_params+=(-j ${tmpf}) - -if [[ -n "${do_hex}" ]]; then - dst_suffix='signed.hex' -else - signer_command_params+=(--format=bin) - dst_suffix='flat' -fi - -tweak_manifest - -count=0 -for elf in ${elves[@]}; do - if [[ -n "${do_prod}" ]]; then - if strings "${elf}" | egrep -q "(DBG|SQA)/cr50"; then - echo "Will not sign debug or SQA image with prod keys" >&2 - exit 1 - fi - fi - signed_file="${count}.${dst_suffix}" - - # Make sure output file is not owned by root - touch "${signed_file}" - command="${SIGNER} ${signer_command_params[@]} -i ${elf} -o ${signed_file}" - if ! ${command}; then - echo "${progname}: \"${command}\" failed" >&2 - exit 1 - fi - - if [ "${ignore_rma_keys}" != "yes" ]; then - if find_blob_in_blob "${signed_file}" "${rma_key_base}.test"; then - echo "${progname}: test RMA key in the signed image!" >&2 - rm *."${dst_suffix}" - exit 1 - fi - - if ! find_blob_in_blob "${signed_file}" "${rma_key_base}.prod"; then - echo "${progname}: prod RMA key not in the signed image!" >&2 - rm *."${dst_suffix}" - exit 1 - fi - fi - : $(( count++ )) -done - -if [[ -z "${do_hex}" ]]; then - # Full binary image is required, paste the newly signed blobs into the - # output image, preserving it in case dd fails for whatever reason. - cp "${RESULT_FILE}" "${TMP_RESULT_FILE}" - dd if="0.flat" of="${TMP_RESULT_FILE}" seek=16384 bs=1 conv=notrunc - dd if="1.flat" of="${TMP_RESULT_FILE}" seek=278528 bs=1 conv=notrunc - rm [01].flat - mv "${TMP_RESULT_FILE}" "${RESULT_FILE}" -fi - -echo "SUCCESS!!!" diff --git a/util/signer/cr50_RW-prod.pem.pub b/util/signer/cr50_RW-prod.pem.pub deleted file mode 100644 index f043eea161..0000000000 --- a/util/signer/cr50_RW-prod.pem.pub +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEAthqml36PUHk5MgurodTG -puEsqK9/28/gEiCZGgfKL2rZKzU7CSiD82nmMgMoaxNTcPZgln+WELXIZUv81Up3 -GT6dA2dSDSQgmdgI1/x3OkEf9BkmHajuvhZTDteI18X/9TsXwly9zoxEFRy/JW8X -Cz9/eOE7xcgoIzji0WmnosMKyxiOv67hhH+JvJ01uQhcxOag2606uIBknovHZT7l -kf3RsEquoZqGK2WFwin9gl4KXv8yQ2F0h9LnfezIURWuz4J6pNc8EI7jYeP5eBrJ -AfE8HsnDD6I2OpoNNM0BnbPq7gbn5CJJn5bZ6dNM4YBH8saJgNVBYOV9XqHdtiLV -uwIBAw== ------END PUBLIC KEY----- diff --git a/util/signer/cr50_rom0-dev-blsign.pem.pub b/util/signer/cr50_rom0-dev-blsign.pem.pub deleted file mode 100644 index 4e4e765ca5..0000000000 --- a/util/signer/cr50_rom0-dev-blsign.pem.pub +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA3BvAb0OUrzmPfwQPOz7D -c5JOiiv6p9Es42XR4kLajBPIJog4ZMIFHrTk8R3IvQkt5TQb7SbvAv/rDESVLplM -OJX9/5i5MK4Wh6j/msopEwRfdCgHD5dXOSN3mqC8bqyWhspF0L9fUlZXAsPD0zUe -sXNL0dTSuvE4GZ53WoE8bM9d1w5A6L9NzODAgI1hOFqg9qnpir9R/CWiH0/JwlbP -k5amvRfVFPeyivq4zRW4LGa6I3woVjp36iRUYEktbvabq6/qmAGDiL4hy4AHhLGn -2g7s1sY6V9W9cYQQ7sja8x+xqH4Mwt1QxlLoGrVfhf0sh0hUETnUPSXwZFRQqU+0 -4QIBAw== ------END PUBLIC KEY----- diff --git a/util/signer/create_released_image.sh b/util/signer/create_released_image.sh deleted file mode 100755 index f5d4673887..0000000000 --- a/util/signer/create_released_image.sh +++ /dev/null @@ -1,232 +0,0 @@ -#!/bin/bash - -# -# 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. -# -# This script is a utility which allows to sign prod CR50 images for release -# and place them in a tarball suitable for uploading to the BCS. -# -# The util/signer/ec_RW-manifest-prod.json manifest present in the EC -# directory is used for signing. -# - -set -u - -# A very crude RO verification function. The key signature found at a fixed -# offset into the RO blob must match the RO type. Prod keys have bit D2 set to -# one, dev keys have this bit set to zero. -verify_ro() { - local ro_bin="${1}" - local type_expected="${2}" - local key_byte - - if [ ! -f "${ro_bin}" ]; then - echo "${ro_bin} not a file!" >&2 - exit 1 - fi - - # Key signature's lowest byte is byte #5 in the line at offset 0001a0. - key_byte="$(od -Ax -t x1 -v "${ro_bin}" | awk '/0001a0/ {print $6};')" - case "${key_byte}" in - (?[4567cdef]) - if [ "${type_expected}" == "prod" ]; then - return 0 - fi - ;; - (?[012389ab]) - if [ "${type_expected}" == "dev" ]; then - return 0 - fi - ;; - esac - - echo "RO key in ${ro_bin} does not match type ${type_expected}" >&2 - exit 1 -} - -# This function prepares a full CR50 image, consisting of two ROs and two RWs -# placed at their respective offsets into the resulting blob. It invokes the -# bs (binary signer) script to actually convert elf versions of RWs into -# binaries and sign them. -# -# The signed image is placed in the directory named as concatenation of RO and -# RW version numbers and board ID fields, if set to non-default. The ebuild -# downloading the tarball from the BCS expects the image to be in that -# directory. -prepare_image() { - local awk_prog - local count=0 - local extra_param= - local image_type="${1}" - local raw_version - local ro_a_hex="$(readlink -f "${2}")" - local ro_b_hex="$(readlink -f "${3}")" - local rw_a="$(readlink -f "${4}")" - local rw_b="$(readlink -f "${5}")" - local version - - for f in "${ro_a_hex}" "${ro_b_hex}"; do - if ! objcopy -I ihex "${f}" -O binary "${TMPD}/${count}.bin"; then - echo "failed to convert ${f} from hex to bin" >&2 - exit 1 - fi - verify_ro "${TMPD}/${count}.bin" "${image_type}" - : $(( count += 1 )) - done - - if [ "${image_type}" == "prod" ]; then - extra_param+=' prod' - fi - - if ! "${EC_ROOT}/util/signer/bs" ${extra_param} elves \ - "${rw_a}" "${rw_b}" > /dev/null; - then - echo "Failed invoking ${EC_ROOT}/util/signer/bs ${extra_param} " \ - "elves ${rw_a} ${rw_b}" >&2 - exit 1 - fi - - dd if="${TMPD}/0.bin" of="${RESULT_FILE}" conv=notrunc - dd if="${TMPD}/1.bin" of="${RESULT_FILE}" seek=262144 bs=1 conv=notrunc - - # A typical Cr50 version reported by gsctool looks as follows: - # RO_A:0.0.10 RW_A:0.0.22[ABCD:00000013:00000012] ...(the same for R[OW]_B). - # - # In case Board ID field is not set in the image, it is reported as - # [00000000:00000000:00000000] - # - # We want the generated tarball file name to include all relevant version - # fields. Let's retrieve the version string and process it using awk to - # generate the proper file name. Only the RO_A and RW_A version numbers are - # used, this script trusts the user to submit for processing a proper image - # where both ROs and both RWs are of the same version respectively. - # - # As a result, blob versions are converted as follows: - # RO_A:0.0.10 RW_A:0.0.22[ABCD:00000013:00000012] into - # r0.0.10.w0.0.22_ABCD_00000013_00000012 - # - # RO_A:0.0.10 RW_A:0.0.22[00000000:00000000:00000000] into - # r0.0.10.w0.0.22 - # - # The below awk program accomplishes this preprocessing. - awk_prog='/^RO_A:/ { - # drop the RO_A/RW_A strings - gsub(/R[OW]_A:/, "") - # Drop default mask value completely. - gsub(/\[00000000:00000000:00000000\]/, "") - # If there is a non-default mask: - # - replace opening brackets and colons with underscores. - gsub(/[\[\:]/, "_") - # - drop the trailing bracket. - gsub(/\]/, "") - # Print filtered out RO_A and RW_A values - print "r" $1 ".w" $2 -}' - - raw_version="$("${GSCTOOL}" -b "${RESULT_FILE}")" || - ( echo "${ME}: Failed to retrieve blob version" >&2 && exit 1 ) - - version="$(awk "${awk_prog}" <<< "${raw_version}" )" - if [ -z "${dest_dir}" ]; then - # Note that this is a global variable - dest_dir="cr50.${version}" - if [ ! -d "${dest_dir}" ]; then - mkdir "${dest_dir}" - else - echo "${dest_dir} already exists, will overwrite" >&2 - fi - elif [ "${dest_dir}" != "cr50.${version}" ]; then - echo "dev and prod versions mismatch!" >&2 - exit 1 - fi - - cp "${RESULT_FILE}" "${dest_dir}/cr50.bin.${image_type}" - echo "saved ${image_type} binary in ${dest_dir}/cr50.bin.${image_type}" -} - -# Execution starts here =========================== -ME="$(basename $0)" - -if [ -z "${CROS_WORKON_SRCROOT}" ]; then - echo "${ME}: This script must run inside Chrome OS chroot" >&2 - exit 1 -fi - -SCRIPT_ROOT="${CROS_WORKON_SRCROOT}/src/scripts" -. "${SCRIPT_ROOT}/build_library/build_common.sh" || exit 1 - -TMPD="$(mktemp -d /tmp/${ME}.XXXXX)" -trap "/bin/rm -rf ${TMPD}" SIGINT SIGTERM EXIT - -EC_ROOT="${CROS_WORKON_SRCROOT}/src/platform/ec" -RESULT_FILE="${TMPD}/release.bin" -dest_dir= -IMAGE_SIZE='524288' -export RESULT_FILE - -GSCTOOL="/usr/sbin/gsctool" -if [[ ! -x "${GSCTOOL}" ]]; then - emerge_command="USE=cr50_onboard sudo -E emerge ec-utils" - echo "${ME}: gsctool not found, run \"${emerge_command}\"" >&2 - exit 1 -fi - -DEFINE_string cr50_board_id "" \ - "Optional string representing Board ID field of the Cr50 RW header. -Consists of three fields separated by colon: <RLZ>:<hex mask>:<hex flags>" - -# Do not put this before the DEFINE_ invocations - they routinely experience -# error return values. -set -e - -FLAGS_HELP="usage: ${ME} [flags] <blobs> - -blobs are: - <prod RO A>.hex <prod RO B>.hex <RW.elf> <RW_B.elf> - or - <prod RO A>.hex <prod RO B>.hex <dir> - where <dir> contains files named ec.RW.elf and ec.RW_B.elf -" - -# Parse command line. -FLAGS "$@" || exit 1 - -eval set -- "${FLAGS_ARGV}" - -if [[ $# == 3 && -d "${3}" ]]; then - rw_a="${3}/ec.RW.elf" - rw_b="${3}/ec.RW_B.elf" -elif [[ $# == 4 ]]; then - rw_a="${3}" - rw_b="${4}" -else - flags_help - exit 1 -fi - -prod_ro_a="${1}" -prod_ro_b="${2}" - -dd if=/dev/zero bs="${IMAGE_SIZE}" count=1 2>/dev/null | - tr \\000 \\377 > "${RESULT_FILE}" -if [ "$(stat -c '%s' "${RESULT_FILE}")" != "${IMAGE_SIZE}" ]; then - echo "Failed creating ${RESULT_FILE}" >&2 - exit 1 -fi - -# Used by the bs script. -export CR50_BOARD_ID="${FLAGS_cr50_board_id}" - -prepare_image 'prod' "${prod_ro_a}" "${prod_ro_b}" "${rw_a}" "${rw_b}" -tarball="${dest_dir}.tbz2" -tar jcf "${tarball}" "${dest_dir}" -rm -rf "${dest_dir}" - -bcs_path="gs://chromeos-localmirror-private/distfiles/cr50" -echo "SUCCESS!!!!!!" -echo "use the below commands to copy the new image to the GFS" -echo "gsutil cp ${tarball} ${bcs_path}" -echo "gsutil acl ch -g cr50-firmware@google.com:R ${bcs_path}/${tarball}" - diff --git a/util/signer/ec_RW-manifest-dev.json b/util/signer/ec_RW-manifest-dev.json deleted file mode 100644 index 1f65d68e91..0000000000 --- a/util/signer/ec_RW-manifest-dev.json +++ /dev/null @@ -1,48 +0,0 @@ -{ -// List of fuses and their expected values. -"fuses": { - "FLASH_PERSO_PAGE_LOCK": 5, // individualized - "FW_DEFINED_DATA_BLK0": 2, // kevin EVT 1 - "FW_DEFINED_DATA_EXTRA_BLK6": 0 // escape hatch -}, -// Rollback state. -"info": { - "2": -1, "3": -1, "4": -1, "5": -1, "6": -1, - "7": -1, "8": -1, "9": -1, "10": -1, "11": -1, "12": -1 , "13": -1, - "14": -1, "15": -1, "16": -1, "17": -1, "18": -1, "19": -1, "20": -1, - "21": -1, "22": -1, "23": -1, "24": -1, "25": -1, "26": -1, "27": -1, - "28": -1, "29": -1, "30": -1, "31": -1, "32": -1, "33": -1, "34": -1, - "35": -1, "36": -1, "37": -1, "38": -1, "39": -1, "40": -1, "41": -1, - "42": -1, "43": -1, "44": -1, "45": -1, "46": -1, "47": -1, "48": -1, - "49": -1, "50": -1, "51": -1, "52": -1, "53": -1, "54": -1, "55": -1, - "56": -1, "57": -1, "58": -1, "59": -1, "60": -1, "61": -1, "62": -1, - "63": -1, "64": -1, "65": -1, "66": -1, "67": -1, "68": -1, "69": -1, - "70": -1, "71": -1, "72": -1, "73": -1, "74": -1, "75": -1, "76": -1, - "77": -1, "78": -1, "79": -1, "80": -1, "81": -1, "82": -1, "83": -1, - "84": -1, "85": -1, "86": -1, "87": -1, "88": -1, "89": -1, "90": -1, - "91": -1, "92": -1, "93": -1, "94": -1, "95": -1, "96": -1, "97": -1, - "98": -1, "99": -1, "100": -1, "101": -1, "102": -1, "103": -1, "104": -1, -"105": -1, "106": -1, "107": -1, "108": -1, "109": -1, "110": -1, "111": -1, -"112": -1, "113": -1, "114": -1, "115": -1, "116": -1, "117": -1, "118": -1, -"119": -1, "120": -1, "121": -1, "122": -1, "123": -1, "124": -1, "125": -1, -"126": -1, "127": -1 -}, - - // Note: tag needs to match what cros_personalize anticipated! - // https://cs.corp.google.com/search/?q=kCrosFwr - "tag": "00000000000000000000000000000000000000000000000000000000", - - // cros_loader uses b1-dev key as key to verify RW with - "keyid": 860844255, // b1-dev, RO 0.0.11 key - - "p4cl": 177, // P4 sync cl for XML we link against. 177 == 0xb1. - - "timestamp": 0, - "epoch": 0, // FWR diversification contributor, 32 bits. - "major": 4, // FW2_HIK_CHAIN counter. - "minor": 24, // Mostly harmless version field. - "applysec": -1, // Mask to and with fuse BROM_APPLYSEC. - "config1": 13, // Which BROM_CONFIG1 actions to take before launching. - "err_response": 0, // Mask to or with fuse BROM_ERR_RESPONSE. - "expect_response": 3 // purgatory level when expectation fails. -} diff --git a/util/signer/ec_RW-manifest-prod.json b/util/signer/ec_RW-manifest-prod.json deleted file mode 100644 index 4d725af315..0000000000 --- a/util/signer/ec_RW-manifest-prod.json +++ /dev/null @@ -1,52 +0,0 @@ -{ -// List of fuses and their expected values. -"fuses": { - "FLASH_PERSO_PAGE_LOCK": 5, // individualized - "FW_DEFINED_DATA_BLK0": 2, // cros SKU - "FW_DEFINED_DATA_EXTRA_BLK6": 0 // escape hatch -}, -// Rollback state. -"info": { - "2": -1, "3": -1, "4": -1, "5": -1, "6": -1, - "7": -1, "8": -1, "9": -1, "10": -1, "11": -1, "12": -1 , "13": -1, - "14": -1, "15": -1, "16": -1, "17": -1, "18": -1, "19": -1, "20": -1, - "21": -1, "22": -1, "23": -1, "24": -1, "25": -1, "26": -1, "27": -1, - "28": -1, "29": -1, "30": -1, "31": -1, "32": -1, "33": -1, "34": -1, - "35": -1, "36": -1, "37": -1, "38": -1, "39": -1, "40": -1, "41": -1, - "42": -1, "43": -1, "44": -1, "45": -1, "46": -1, "47": -1, "48": -1, - "49": -1, "50": -1, "51": -1, "52": -1, "53": -1, "54": -1, "55": -1, - "56": -1, "57": -1, "58": -1, "59": -1, "60": -1, "61": -1, "62": -1, - "63": -1, "64": -1, "65": -1, "66": -1, "67": -1, "68": -1, "69": -1, - "70": -1, "71": -1, "72": -1, "73": -1, "74": -1, "75": -1, "76": -1, - "77": -1, "78": -1, "79": -1, "80": -1, "81": -1, "82": -1, "83": -1, - "84": -1, "85": -1, "86": -1, "87": -1, "88": -1, "89": -1, "90": -1, - "91": -1, "92": -1, "93": -1, "94": -1, "95": -1, "96": -1, "97": -1, - "98": -1, "99": -1, "100": -1, "101": -1, "102": -1, "103": -1, "104": -1, -"105": -1, "106": -1, "107": -1, "108": -1, "109": -1, "110": -1, "111": -1, -"112": -1, "113": -1, "114": -1, "115": -1, "116": -1, "117": -1, "118": -1, -"119": -1, "120": -1, "121": -1, "122": -1, "123": -1, "124": -1, "125": -1, -"126": -1, "127": -1 -}, - - // Note: tag needs to match what cros_personalize anticipated! - // https://cs.corp.google.com/search/?q=kCrosFwr - "tag": "00000000000000000000000000000000000000000000000000000000", - - // cros_loader uses b1-dev key as key to verify RW with - //"keyid": -1187158727, // b1-dev key - "keyid": -561489779, // prod RW key - - "p4cl": 177, // P4 sync cl for XML we link against. 177 == 0xb1. - - // Make sure a value is there so that current time is not used, and make - // sure the value is small so that any dev build with the same - // epoch/major/minor would be preferred - "timestamp": 1, - "epoch": 0, // FWR diversification contributor, 32 bits. - "major": 3, // FW2_HIK_CHAIN counter. - "minor": 24, // Mostly harmless version field. - "applysec": -1, // Mask to and with fuse BROM_APPLYSEC. - "config1": 13, // Which BROM_CONFIG1 actions to take before launching. - "err_response": 0, // Mask to or with fuse BROM_ERR_RESPONSE. - "expect_response": 3 // purgatory level when expectation fails. -} diff --git a/util/signer/fuses.xml b/util/signer/fuses.xml deleted file mode 100644 index 627c8796b8..0000000000 --- a/util/signer/fuses.xml +++ /dev/null @@ -1,2034 +0,0 @@ -<ArrayType> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK0_INTG_CHKSUM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>0</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>24</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK0_INTG_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>1</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DS_GRP0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>2</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>9</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DS_GRP1</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>3</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>9</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DS_GRP2</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>4</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>9</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DEV_ID0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>5</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>32</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DEV_ID1</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>6</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>32</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK1_INTG_CHKSUM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>7</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>24</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK1_INTG_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>8</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB0_POST_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>9</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB0_POST_PATCNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>10</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB0_POST_WARMUP_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>11</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB0_POST_WARMUP_CNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>12</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB1_POST_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>13</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB1_POST_PATCNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>14</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB1_POST_WARMUP_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>15</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB1_POST_WARMUP_CNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>16</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB2_POST_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>17</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB2_POST_PATCNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>18</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB2_POST_WARMUP_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>19</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB2_POST_WARMUP_CNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>20</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB3_POST_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>21</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB3_POST_PATCNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>22</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB3_POST_WARMUP_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>23</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB3_POST_WARMUP_CNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>24</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB4_POST_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>25</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB4_POST_PATCNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>26</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB4_POST_WARMUP_OVRD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>27</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LB4_POST_WARMUP_CNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>28</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>MBIST_POST_SEQ</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>29</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>25</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LBIST_POST_SEQ</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>30</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>25</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>LBIST_VIA_TAP_DIS</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>31</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>MBIST_VIA_TAP_DIS</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>32</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TAP_DISABLE</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>33</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RNGBIST_AR_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>34</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TESTMODE_KEYS_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>35</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>PKG_ID</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>36</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BIN_ID</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>37</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_JTR_OSC48_CC_TRIM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>38</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_JTR_OSC48_CC_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>39</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_JTR_OSC60_CC_TRIM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>40</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_JTR_OSC60_CC_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>41</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_TIMER_OSC48_CC_TRIM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>42</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_TIMER_OSC48_CC_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>43</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_TIMER_OSC48_FC_TRIM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>44</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>5</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_TIMER_OSC48_FC_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>45</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_RTC_OSC256K_CC_TRIM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>46</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RC_RTC_OSC256K_CC_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>47</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>SEL_VREG_REG_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>48</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>SEL_VREF_REG</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>49</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>4</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>SEL_VREF_BATMON_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>50</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>SEL_VREF_BATMON</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>51</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>X_OSC_LDO_CTRL_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>52</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>X_OSC_LDO_CTRL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>53</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>4</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TEMP_OFFSET_CAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>54</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>12</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TRNG_LDO_CTRL_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>55</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TRNG_LDO_CTRL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>56</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>5</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TRNG_ANALOG_CTRL_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>57</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TRNG_ANALOG_CTRL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>58</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>4</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>EXT_XTAL_PDB</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>59</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>DIS_EXT_XTAL_CLK_TREE</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>60</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>OBFUSCATION_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>61</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>HIK_CREATE_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>62</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK2_INTG_CHKSUM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>63</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>24</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK2_INTG_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>64</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>TESTMODE_OTPW_DIS</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>65</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>HKEY_WDOG_TIMER_EN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>66</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FLASH_PERSO_PAGE_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>67</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>ALERT_RSP_CFG</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>68</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK3_INTG_CHKSUM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>69</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>24</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK3_INTG_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>70</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_BLK0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>71</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_BROM_ERR_RESPONSE</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>72</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>16</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_BROM_APPLYSEC</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>73</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>12</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_BROM_CONFIG0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>74</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_BROM_CONFIG1</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>75</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_MODE_DBG_OVRD_DIS</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>76</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_MODE_OUTPUT_OVRD_DIS</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>77</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>7</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_CLK10HZ_COUNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>78</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>16</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_SHORT_DELAY_COUNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>79</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>16</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_LONG_DELAY_COUNT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>80</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DEBOUNCE_PERIOD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>81</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>16</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DEBOUNCE_BYPASS_PWRB</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>82</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DEBOUNCE_BYPASS_KEY0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>83</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DEBOUNCE_BYPASS_KEY1</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>84</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO0_VAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>85</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO1_VAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>86</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO2_VAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>87</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO0_HOLD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>88</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO1_HOLD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>89</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_KEY_COMBO2_HOLD</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>90</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_BLOCK_KEY0_SEL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>91</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_BLOCK_KEY1_SEL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>92</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_BLOCK_KEY0_VAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>93</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_BLOCK_KEY1_VAL</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>94</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_AC_PRESENT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>95</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_PWRB_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>96</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_PWRB_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>97</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_KEY0_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>98</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_KEY0_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>99</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_KEY1_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>100</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_KEY1_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>101</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_EC_RST</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>102</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_POL_BATT_DISABLE</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>103</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>1</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_AC_PRESENT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>104</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_ENTERING_RW</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>105</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_PWRB_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>106</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_PWRB_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>107</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_KEY0_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>108</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_KEY0_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>109</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_KEY1_IN</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>110</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_TERM_KEY1_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>111</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DRIVE_PWRB_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>112</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DRIVE_KEY0_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>113</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DRIVE_KEY1_OUT</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>114</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DRIVE_EC_RST</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>115</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>RBOX_DRIVE_BATT_DISABLE</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>116</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>2</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK4_INTG_CHKSUM</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>117</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>24</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>BNK4_INTG_LOCK</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>118</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>3</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK0</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>119</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK1</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>120</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK2</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>121</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK3</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>122</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK4</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>123</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK5</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>124</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>8</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> - <HashType> - <HashItem> - <Key>RegName</Key> - <Value>FW_DEFINED_DATA_EXTRA_BLK6</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>125</Value> - </HashItem> - <HashItem> - <Key>Width</Key> - <Value>5</Value> - </HashItem> - </HashType> -</ArrayItem> -<ArrayItem> -<HashType> - <HashItem> - <Key>RegName</Key> - <Value>SWDP_P4_LAST_SYNC</Value> - </HashItem> - <HashItem> - <Key>Default</Key> - <Value>177</Value> - </HashItem> - <HashItem> - <Key>FuseLogicalOffset</Key> - <Value>0</Value> - </HashItem> -</HashType> -</ArrayItem> -</ArrayType> diff --git a/util/signer/loader-testkey-A.pem b/util/signer/loader-testkey-A.pem deleted file mode 100644 index ea16e603e9..0000000000 --- a/util/signer/loader-testkey-A.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAp/kh8/NGr1GUMA6c0tq9cRhVMaMwhYCF6mkpeW/D+1k3lL5q -pkjqDcYBZG4xbhdCgEH9ppPYKzwKBVieWuqf7uymLBlCLmaPA6P4J+IwhS001WoD -0kACEhnbL4xeP21fwuz9/u6ucoM8kJsFV/gacADmuOKTrU89Kyj2J5iLWVQPMMAM -BOk+3BNamWwnCRk+CvcT+EQHtzcFkK2avm4HUQNSzhL407NbvsHwUjv7N6wtjeu5 -VLaTLTHxk9Z5savcn2jgxWASn4M59dpD7KSTYi4LsY8NPUWswz0E2a0vk8rfthtA -amTkU4MT9ohVYq2JTCj5DC3DV/0Z7xiZ+ZsYPQIBAwKCAQBv+2v394R04Q11XxM3 -PH5LZY4hF3WuVa6cRhumSoKnkM+4fvHEMJwJLquYSXZJZNcAK/5vDTrHfVwDkGmR -8b/0ncQdZiwe7woCbVAalssDc3iORq021Va2u+d1CD7U85Usnf6p9HRMV321vK46 -pWb1Ve8l7GJziijHcKQaZbI7jEq4JKyk9lL7seEWjf2zHyiLnh8wxQK7Ebizrqw9 -EIH3tmC6JKvbGJPizQ6tz1O0bVwiaHmZObouRxBTE8fL2zuSmJunqsYK4xqWfRsb -+RcSDndzBTW89qZr7i3h22g8jUsMiPBqV9/l9w1dOxnWwAtQSHfebcCA2u3OxUGM -9dpTAoGBANhm0GYySwuCJc8lJpsBUl2tbuw7pzRdDe8BuqGv2aaEHx7arwFat1AA -ZHVlQquWaKxwCuyFY/QlGq4uTNHhkBgygnFeEvtZ0KaKSVBBXY0Fbhq+N6rsX7FQ -eRb4sz7We/aFR2K1V52dHaetOjMBfLhX1e7dZRwX8xnSSKuQeB6DAoGBAMa1uKLb -LLbgYrnScI97GCOMGvjzdU9BjoGBbPay+53ZUqLcLPWwVy3qKeToQlISn3bqRBZp -fAfCrKro6/weUusRAYXrzO41XeuJ1UsBUWPBqj3Gz5G1dAHQ3qkOMNRievieBnUV -iXbdctg9dXufEL/75lZhJAZ+wZtmqAwVsjI/AoGBAJBEiu7MMgesGTTDbxIA4ZPI -9J19GiLos/Sr0cEf5m8Cv2nnH1Y8ejVVmE5Dgce5mx2gB0hY7U1uEcl0MzaWYBAh -rEuUDKeRNcRcMOArk7NY9BHUJRydlSDgULn7IinkUqRY2kHOOmkTaRpzfCIA/dA6 -jp8+Q2gP92aMMHJgUBRXAoGBAIR5JcHncySVlyaMSwpSEBeyvKX3o4ortFZWSKR3 -Umk7jGySyKPK5MlGxpia1uFhv6ScLWRGUq/XHcdF8qgUN0dgq66dM0l46UexONyr -i5fWcX6EimEjoqvglHC0II2W/KW+rvi5Bk8+TJAo+P0UtdVSmY7rbVmp1meZxV1j -zCF/AoGAcm2nAn275kfGZjXkTCYTZ6IXJgxcc4vXhv573UfNIJnC0Sg9rsgFiXHc -nuQwFh5pTm4hU7uEknc/IobFLdCqM9mqujuYmboj0pmbRfOsjV9hqcmuo1OrSbJa -gozzsNqU2I6srVW5SlCwWu1c4rBlBZvcdUtBRRb2b6bnhe29ykg= ------END RSA PRIVATE KEY----- diff --git a/util/signer/rom-testkey-A.pem b/util/signer/rom-testkey-A.pem deleted file mode 100644 index 77a69d8448..0000000000 --- a/util/signer/rom-testkey-A.pem +++ /dev/null @@ -1,39 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIG4AIBAAKCAYB7AIp3IzOv+FL4TNw2NwTD/Zx/ZOXmRYN14bICBHv9SufXlHT3 -klWR6GYZdGrY4/8VViz+Ax2JU6Rjgm7R4+Dh0Ny8TSlhIFloyVE2Dgb463hONrH+ -N09r7xPM34dMNJRQcd/2ptYD1Q+fnsg874EZtLXY2/b11jjj9mxyDru33MzNcQYm -lTcAMayQs/nvBzsaUqJvMn89OtMg9BnKJwapcLvFywtNrCiC4iywqQSiqLt/FrbK -nZd03Z/dT42fHt5h4MYfvT61S6XnkeOgFXD3lDHMbtD/Xg7eDT5Oh+wkSyXlpZHr -HRLWkvZGSbHwywU91G/K8O05jnhv1q9Tawvxs5AKuqvOjNrhY8u8LgoJ88XhGvGQ -yzhJuOeuEWomV/9F4CZqbFJ/+mFPRUfbjpRoauX0GCoO/BSSIgijlF2Ax1SoaZoi -bY8E2TJUBXvxifMvHg/zdxiHeAR/8G5g43jfZz4HJ8PIHdmXRz5/IeK5IdEgSnxx -5b3Rv/amI6vOe40CAQMCggGAUgBcT2zNH/rh+t3oJCSt1/5oVO3umYOs+UEhVq2n -/jHv5Q2jT7bjtpruu6Lx5e1UuOQd/qy+W40YQlb0i+1Alos90t4blhWQ8IY2JAlZ -+0eliXnL/s+KR/S33epaMs24NaE/+cSOrTi1FRSFffUAu83OkJKko+Ql7U7y9rR9 -JT3d3ktZbw4kqsvIYHf79K98vDcW9MxU03yMwKK73BoEcPXSg9yyM8gbAewdyxtY -bHB8/2R53GkPoz5qk4peahSTRslgZHmnUc4zHp0lmy8LOvaGm++wb1m+5sw/8cte -Kjdyh7KFYH1Sdzin5Fw5oabdIz+oercj34JJP1Gx1TV0oQA7yjCWDfVfnGgoN7AX -3QNSW5HonmkaY5TYZ+la7kGocxewN1pLtun03OZDQlpF73dXWYZFWfky4Lc2Egkk -rE2LjmFQQ5YlYOB+qaxaZCOM7i8BYJHwAMT1kKDXoqqdqqqLwcJcorXdYXME0IMS -OIfFDhhYgUF1f5Ex/DgcG0RrAoHBAPl7mWuOjpCo6eNcFICvIoR64dNF0ud9lvUG -RiUD5wTnR0cyGuWqvfDFYw1G4gUQsVsE/dOWPkevetb4RZAMie0tvbR2FIYL0ZgV -vdbV7puSLWjZF3Ap2AnX9dH7HrxADPd1y84JvhQK3zTurz35AhGEQZM4GyAunxEh -zfMew3fCKoMzsmky92q+IN4Za6HZPkOMzfJDlc/nRZIU5riCQsoKFWboO2Y9hQUg -royXy7+CE18jE8QJ6qzt5JgdiPYOxQKBwH43HB14NSntb1ZKFrafvZqnhg9BdXDZ -2Y7UmD7S9+AQstLnrvS2WTL4l2J4eXlACC3v9T9H+SKbj7nj3wOOUxMFeKb7tjOQ -+d6x0ZHP96LcnO7m/TMDuKqBrUA4QwS1daHG0klbItmQks79M7oOKW+zoVqWpufX -qS/taZVn4waQ2M+j71PZX4jKU3dpiLl7YYZKv/BYmrZpTpTqRDRhSZVdVv2b/W3P -iH/6CLnFe6TUFiwC4+v5ouV4RxOx+K+GKQKBwQCmUmZHtF8LG0aXkrhVyhcC/JaM -2TdE/mSjWYQYrUSt74TaIWdDxylLLkII2ewDYHY8rf6NDtQvylHkpYO1XbFIySki -+WMEB+EQDn6POUm9DB5F5g+gG+Vb5U6L/L8oKrNPo900Bn64Bz94nx9+pgFhAtZi -JWdqyb9gwTP3adelLBxXd8xGIfpHKWs+u50WkNQtCIlMLQ6Kmi5hY0R7AYHcBrjv -RXzu064Dax8IZTJ/rAzqF2KCsUcd8+26vltOtIMCgcBUJL1o+s4b85+O3A8kan5n -GllfgPj15pEJ4xAp4fqVYHc3RR9NzuYh+w+W+vumKrAen/jU2qYXEl/RQpStCYy3 -WPsZ/SQiYKaUdou2iqUXPb30mf4iAnscVnOAJYIDI6PBLzbbkhc7tbc0qM0mtBuf -zRY8ZG9FOnDKnkZjmpdZteXfwp+NO5UF3Dek8QXQ/Ouu3H/1kGckRjRjRtgi64Zj -k49TvVOeilr//AXRLlJt4rlyrJfypmyY+toNIVB1BBsCgcEA5IYJrpO5qGVWlfnX -70deEyhKUhEXs91b6Vcf8KJNtxBao3H2B8uGtPrx0nCtxgI7XPYDiqIZ3cQDrjct -4cLTah0hwaxnoKsB0aGbRWccpn6uDpqa5TVMBIVwUiyWVd+spAxxRDNIcSWn8lYM -pK6Hc54XEJbaXJXTrAPGj8r4eCScRvJDqJnSzVDTztu1EoHvHrFVFkTMELFhIEmf -duSuLGNMweNghh8yN5ipOSVp3qog2/hv3l79HIPhVHf3G17j ------END RSA PRIVATE KEY----- |