diff --git a/board/cr50/wp.c b/board/cr50/wp.c index 823abdf145..d667ecc74e 100644 --- a/board/cr50/wp.c +++ b/board/cr50/wp.c @@ -5,6 +5,7 @@ #include "common.h" #include "console.h" +#include "extension.h" #include "gpio.h" #include "hooks.h" #include "nvmem.h" @@ -49,6 +50,19 @@ static int console_restricted_state; static int console_restricted_state = 1; #endif +static void lock_the_console(void) +{ + CPRINTS("The console is locked"); + console_restricted_state = 1; +} + +static void unlock_the_console(void) +{ + nvmem_wipe_or_reboot(); + CPRINTS("TPM is erased, console is unlocked"); + console_restricted_state = 0; +} + int console_is_restricted(void) { return console_restricted_state; @@ -90,9 +104,7 @@ static void unlock_sequence_is_over(void) } else { /* The last poke was after the final deadline, so we're done */ CPRINTS("Unlock process completed successfully"); - nvmem_wipe_or_reboot(); - console_restricted_state = 0; - CPRINTS("TPM is erased, console is unlocked."); + unlock_the_console(); } unlock_in_progress = 0; @@ -145,6 +157,59 @@ static void start_unlock_process(int total_poking_time, int max_poke_interval) hook_call_deferred(&unlock_sequence_is_over_data, unlock_beat); } +/****************************************************************************/ +/* TPM vendor-specific commands */ + +static enum vendor_cmd_rc vc_lock(enum vendor_cmd_cc code, + void *buf, + size_t input_size, + size_t *response_size) +{ + uint8_t *buffer = buf; + + if (code == VENDOR_CC_GET_LOCK) { + /* + * Get the state of the console lock. + * + * Args: none + * Returns: one byte; true (locked) or false (unlocked) + */ + if (input_size != 0) { + *response_size = 0; + return VENDOR_RC_BOGUS_ARGS; + } + + buffer[0] = console_is_restricted() ? 0x01 : 0x00; + *response_size = 1; + return VENDOR_RC_SUCCESS; + } + + if (code == VENDOR_CC_SET_LOCK) { + /* + * Lock the console if it isn't already. Note that there + * intentionally isn't an unlock command. At most, we may want + * to call start_unlock_process(), but we haven't yet decided. + * + * Args: none + * Returns: none + */ + if (input_size != 0) { + *response_size = 0; + return VENDOR_RC_BOGUS_ARGS; + } + + lock_the_console(); + *response_size = 0; + return VENDOR_RC_SUCCESS; + } + + /* I have no idea what you're talking about */ + *response_size = 0; + return VENDOR_RC_NO_SUCH_COMMAND; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_GET_LOCK, vc_lock); +DECLARE_VENDOR_COMMAND(VENDOR_CC_SET_LOCK, vc_lock); + /****************************************************************************/ static const char warning[] = "\n\t!!! WARNING !!!\n\n" "\tThe AP will be impolitely shut down and the TPM persistent memory\n" @@ -161,12 +226,12 @@ static int command_lock(int argc, char **argv) return EC_ERROR_PARAM1; /* Changing nothing does nothing */ - if (enabled == console_restricted_state) + if (enabled == console_is_restricted()) goto out; /* Locking the console is always allowed */ if (enabled) { - console_restricted_state = 1; + lock_the_console(); goto out; } diff --git a/common/extension.c b/common/extension.c index a588ce892e..d28bfad337 100644 --- a/common/extension.c +++ b/common/extension.c @@ -10,10 +10,10 @@ #define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args) -void extension_route_command(uint16_t command_code, - void *buffer, - size_t in_size, - size_t *out_size) +uint32_t extension_route_command(uint16_t command_code, + void *buffer, + size_t in_size, + size_t *out_size) { struct extension_command *cmd_p; struct extension_command *end_p; @@ -22,10 +22,9 @@ void extension_route_command(uint16_t command_code, end_p = (struct extension_command *)&__extension_cmds_end; while (cmd_p != end_p) { - if (cmd_p->command_code == command_code) { - cmd_p->handler(buffer, in_size, out_size); - return; - } + if (cmd_p->command_code == command_code) + return cmd_p->handler(command_code, buffer, + in_size, out_size); cmd_p++; } @@ -33,4 +32,5 @@ void extension_route_command(uint16_t command_code, /* This covers the case of the handler not found. */ *out_size = 0; + return VENDOR_RC_NO_SUCH_COMMAND; } diff --git a/common/tpm_registers.c b/common/tpm_registers.c index 444ed52e20..b5c5f8b7e5 100644 --- a/common/tpm_registers.c +++ b/common/tpm_registers.c @@ -569,10 +569,21 @@ size_t tpm_get_burst_size(void) #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) + size_t *total_size) { 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)) { @@ -582,14 +593,18 @@ static void call_extension_command(struct tpm_cmd_header *tpmh, *total_size -= sizeof(struct tpm_cmd_header); subcommand_code = be16toh(tpmh->subcommand_code); - extension_route_command(subcommand_code, - tpmh + 1, - command_size - - sizeof(struct tpm_cmd_header), - total_size); + rc = extension_route_command(subcommand_code, + tpmh + 1, + command_size - + sizeof(struct tpm_cmd_header), + total_size); /* Add the header size back. */ *total_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; } @@ -689,7 +704,7 @@ void tpm_task(void) watchdog_reload(); #ifdef CONFIG_EXTENSION_COMMAND - if (command_code == CONFIG_EXTENSION_COMMAND) { + if (IS_CUSTOM_CODE(command_code)) { response_size = sizeof(tpm_.regs.data_fifo); call_extension_command(tpmh, &response_size); } else @@ -711,7 +726,7 @@ void tpm_task(void) if (command_code == TPM2_PCR_Read) system_process_retry_counter(); #ifdef CONFIG_EXTENSION_COMMAND - if (command_code != CONFIG_EXTENSION_COMMAND) + if (!IS_CUSTOM_CODE(command_code)) #endif { /* diff --git a/include/extension.h b/include/extension.h index d3001934da..225ca87239 100644 --- a/include/extension.h +++ b/include/extension.h @@ -11,6 +11,43 @@ #include "common.h" +/* 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, + + LAST_VENDOR_COMMAND = 65535, +}; + +/* Error codes reported by extension and vendor commands. */ +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, + /* Only 7 bits available; max is 127 */ + VENDOR_RC_NO_SUCH_COMMAND = 127, +}; + /* * Type of function handling extension commands. * @@ -20,12 +57,13 @@ * @param response_size On input - max size of the buffer, on output - actual * number of data returned by the handler. */ -typedef void (*extension_handler)(void *buffer, - size_t command_size, - size_t *response_size); +typedef enum vendor_cmd_rc (*extension_handler)(enum vendor_cmd_cc code, + void *buffer, + size_t command_size, + size_t *response_size); + /* * Find handler for an extension command. - * * @param command_code Code associated with a extension command handler. * @param buffer Data to be processd by the handler, the same space * is used for data returned by the handler. @@ -34,42 +72,59 @@ typedef void (*extension_handler)(void *buffer, * data returned by the handler. A single byte return * usually indicates an error and contains the error code. */ -void extension_route_command(uint16_t command_code, - void *buffer, - size_t command_size, - size_t *size); +uint32_t extension_route_command(uint16_t command_code, + void *buffer, + size_t command_size, + size_t *size); +/* + * 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 + +/* + * The TPM response code is all zero for success. + * 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 + */ +#define VENDOR_RC_ERR 0x00000500 + +/* Pointer table */ struct extension_command { uint16_t command_code; extension_handler handler; } __packed; -/* Values for different extension subcommands. */ -enum { - 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, -}; +#define DECLARE_EXTENSION_COMMAND(code, func) \ + static enum vendor_cmd_rc func##_wrap(enum vendor_cmd_cc code, \ + void *cmd_body, \ + size_t cmd_size, \ + size_t *response_size) { \ + func(cmd_body, cmd_size, response_size); \ + return 0; \ + } \ + const struct extension_command __keep __extension_cmd_##code \ + __attribute__((section(".rodata.extensioncmds"))) \ + = {.command_code = code, .handler = func##_wrap } - -/* Error codes reported by extension commands. */ -enum { - /* 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 -}; - -#define DECLARE_EXTENSION_COMMAND(code, handler) \ - const struct extension_command __keep __extension_cmd_##code \ - __attribute__((section(".rodata.extensioncmds"))) \ - = {code, handler} +#define DECLARE_VENDOR_COMMAND(code, func) \ + const struct extension_command __keep __vendor_cmd_##code \ + __attribute__((section(".rodata.extensioncmds"))) \ + = {.command_code = code, .handler = func} #endif /* __EC_INCLUDE_EXTENSION_H */