summaryrefslogtreecommitdiff
path: root/common/ccd_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/ccd_config.c')
-rw-r--r--common/ccd_config.c1553
1 files changed, 0 insertions, 1553 deletions
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);