diff --git a/common/ccd_config.c b/common/ccd_config.c index 73f6bb0246..6d19d972d2 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -64,6 +64,15 @@ enum ccd_capability_state { CCD_CAP_STATE_COUNT }; +/* + * 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; + 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 @@ -796,7 +805,7 @@ static int do_ccd_password(char *password) static int command_ccd_password(int argc, char **argv) { - struct tpm_cmd_header *tpmh; + struct ccd_vendor_cmd_header *vch; int rv; size_t password_size; size_t command_size; @@ -812,32 +821,33 @@ static int command_ccd_password(int argc, char **argv) return EC_ERROR_PARAM1; } - command_size = sizeof(struct tpm_cmd_header) + password_size; - rv = shared_mem_acquire(command_size, (char **)&tpmh); + command_size = sizeof(*vch) + password_size; + rv = shared_mem_acquire(command_size, (char **)&vch); if (rv != EC_SUCCESS) return rv; /* Build the extension command to set/clear CCD password. */ - tpmh->tag = htobe16(0x8001); /* TPM_ST_NO_SESSIONS */ - tpmh->size = htobe32(command_size); - tpmh->command_code = htobe32(TPM_CC_VENDOR_BIT_MASK); - tpmh->subcommand_code = htobe16(VENDOR_CC_CCD_PASSWORD); - memcpy(tpmh + 1, argv[1], password_size); - tpm_alt_extension(tpmh, command_size); + vch->tpm_header.tag = htobe16(0x8001); /* TPM_ST_NO_SESSIONS */ + vch->tpm_header.size = htobe32(command_size); + vch->tpm_header.command_code = htobe32(TPM_CC_VENDOR_BIT_MASK); + vch->tpm_header.subcommand_code = htobe16(VENDOR_CC_CCD); + vch->ccd_subcommand = CCDV_PASSWORD; + + memcpy(vch + 1, argv[1], password_size); + tpm_alt_extension(&vch->tpm_header, command_size); /* * Return status in the command code field now, in case of error, * error code is the first byte after the header. */ - if (tpmh->command_code) { - ccprintf("Password setting error %d\n", - ((uint8_t *)(tpmh + 1))[0]); + if (vch->tpm_header.command_code) { + ccprintf("Password setting error %d\n", vch->ccd_subcommand); rv = EC_ERROR_UNKNOWN; } else { rv = EC_SUCCESS; } - shared_mem_release(tpmh); + shared_mem_release(vch); return EC_SUCCESS; } @@ -1225,14 +1235,12 @@ static enum vendor_cmd_rc manage_ccd_password(enum vendor_cmd_cc code, DECLARE_VENDOR_COMMAND(VENDOR_CC_MANAGE_CCD_PWD, manage_ccd_password); /* - * Handle the VENDOR_CC_CCD_PASSWORD command. + * Handle the CCVD_PASSWORD subcommand. * - * The payload of the command is a text string to use to set the password. The - * text string set to 'clear' has a special effect though, it clears the - * password instead of setting it. + * The payload of the command is a text string to use to set or clear the + * password. */ -static enum vendor_cmd_rc ccd_password(enum vendor_cmd_cc code, - void *buf, +static enum vendor_cmd_rc ccd_password(void *buf, size_t input_size, size_t *response_size) { @@ -1264,8 +1272,54 @@ static enum vendor_cmd_rc ccd_password(enum vendor_cmd_cc code, *response_size = 0; return VENDOR_RC_SUCCESS; } -DECLARE_VENDOR_COMMAND(VENDOR_CC_CCD_PASSWORD, ccd_password); +/* + * 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(enum vendor_cmd_cc code, + void *buf, + size_t input_size, + size_t *response_size) +{ + enum vendor_cmd_rc (*handler)(void *x, size_t y, size_t *t); + char *buffer; + enum vendor_cmd_rc rc; + + /* + * buf 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. + */ + buffer = buf; + + /* Pick what to do based on subcommand. */ + switch (buffer[0]) { + case CCDV_PASSWORD: + handler = ccd_password; + break; + + default: + CPRINTS("%s:%d - unknown subcommand\n", __func__, __LINE__); + break; + } + + if (handler) { + rc = handler(buf + 1, input_size - 1, response_size); + + /* + * Move response up for the master to see it in the right + * place in the response buffer. + */ + memmove(buf, buf + 1, *response_size); + } else { + rc = VENDOR_RC_NO_SUCH_SUBCOMMAND; + *response_size = 0; + } + + return rc; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_CCD, ccd_vendor); static enum vendor_cmd_rc ccd_disable_rma(enum vendor_cmd_cc code, void *buf, diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c index 205983e198..2dc0b6568c 100644 --- a/extra/usb_updater/gsctool.c +++ b/extra/usb_updater/gsctool.c @@ -27,6 +27,7 @@ #include "config.h" +#include "ccd_config.h" #include "compile_time_macros.h" #include "misc_util.h" #include "signed_header.h" @@ -1585,12 +1586,13 @@ static void process_password(struct transfer_descriptor *td) } /* - * Ok, we have a password, let's drop the newline in the end and send - * it down. + * 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. */ - password[--len] = '\0'; + memmove(password + 1, password, len - 1); + password[0] = CCDV_PASSWORD; response_size = sizeof(response); - rv = send_vendor_command(td, VENDOR_CC_CCD_PASSWORD, + rv = send_vendor_command(td, VENDOR_CC_CCD, password, len, &response, &response_size); free(password); diff --git a/include/ccd_config.h b/include/ccd_config.h index 5319f9a045..5a1cb5add9 100644 --- a/include/ccd_config.h +++ b/include/ccd_config.h @@ -98,6 +98,17 @@ enum ccd_capability { CCD_CAP_COUNT }; +/* + * 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, +}; + /** * Initialize CCD configuration at boot. * diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h index 830678ee0c..390097a45c 100644 --- a/include/tpm_vendor_cmds.h +++ b/include/tpm_vendor_cmds.h @@ -44,9 +44,12 @@ enum vendor_cmd_cc { VENDOR_CC_POP_LOG_ENTRY = 28, VENDOR_CC_GET_REC_BTN = 29, VENDOR_CC_RMA_CHALLENGE_RESPONSE = 30, - VENDOR_CC_CCD_PASSWORD = 31, + + /* A gap left for the no longer supported CCD password command. */ + VENDOR_CC_DISABLE_RMA = 32, VENDOR_CC_MANAGE_CCD_PWD = 33, + VENDOR_CC_CCD = 34, LAST_VENDOR_COMMAND = 65535, }; @@ -69,6 +72,7 @@ enum vendor_cmd_rc { VENDOR_RC_RESPONSE_TOO_BIG = 5, VENDOR_RC_INTERNAL_ERROR = 6, VENDOR_RC_NOT_ALLOWED = 7, + VENDOR_RC_NO_SUCH_SUBCOMMAND = 8, /* Only 7 bits available; max is 127 */ VENDOR_RC_NO_SUCH_COMMAND = 127, };