diff options
-rw-r--r-- | board/cr50/tpm2/platform.c | 6 | ||||
-rw-r--r-- | common/ccd_config.c | 110 | ||||
-rw-r--r-- | include/ccd_config.h | 6 | ||||
-rw-r--r-- | include/tpm_vendor_cmds.h | 2 |
4 files changed, 120 insertions, 4 deletions
diff --git a/board/cr50/tpm2/platform.c b/board/cr50/tpm2/platform.c index 7c98c353a0..e380d8afe1 100644 --- a/board/cr50/tpm2/platform.c +++ b/board/cr50/tpm2/platform.c @@ -6,6 +6,7 @@ #include "Platform.h" #include "TPM_Types.h" +#include "ccd_config.h" #include "trng.h" #include "util.h" #include "version.h" @@ -60,3 +61,8 @@ void _plat__GetFwVersion(uint32_t *firmwareV1, uint32_t *firmwareV2) *firmwareV2 = strtoi(ver_str, NULL, 16); } + +void _plat__ResetCallback(void) +{ + ccd_tpm_reset_callback(); +} diff --git a/common/ccd_config.c b/common/ccd_config.c index b2453b8fdf..73f6bb0246 100644 --- a/common/ccd_config.c +++ b/common/ccd_config.c @@ -1127,6 +1127,104 @@ DECLARE_SAFE_CONSOLE_COMMAND(ccd, command_ccd, "Configure case-closed debugging"); /* + * Password handling on Cr50 passes the following states: + * + * - password setting is not allowed after Cr50 reset until an upstart (as + * opposed to resume) TPM startup happens, as signalled by the TPM callback. + * After the proper TPM reset the state changes to 'POST_RESET_STATE' which + * means that the device was just reset/rebooted (not resumed) and no user + * logged in yet. + * + * - if the owner logs in in this state, the state changes to + * 'PASSWORD_ALLOWED_STATE'. The owner can open crosh session and set the + * password. + * + * - when the owner logs out or any user but the owner logs in, the state + * changes to PASSWORD_NOT_ALLOWED_STATE and does not change until TPM is + * reset. This makes sure that password can be set only by the owner and + * only before anybody else logged in. + */ +enum password_reset_phase { + POST_RESET_STATE, + PASSWORD_ALLOWED_STATE, + PASSWORD_NOT_ALLOWED_STATE +}; + +static uint8_t password_state = PASSWORD_NOT_ALLOWED_STATE; + +void ccd_tpm_reset_callback(void) +{ + CPRINTS("%s: TPM Startup processed", __func__); + password_state = POST_RESET_STATE; +} + +/* + * Handle the VENDOR_CC_MANAGE_CCD_PASSWORD command. + * + * The payload of the command is a single byte Boolean which sets the controls + * if CCD password can be set or not. + * + * After reset the pasword can not be set using VENDOR_CC_CCD_PASSWORD; once + * this command is received with value of True, the phase stars when the + * password can be set. As soon as this command is received with a value of + * False, the password can not be set any more until device is rebooted, even + * if this command is re-sent with the value of True. + */ +static enum vendor_cmd_rc manage_ccd_password(enum vendor_cmd_cc code, + void *buf, + size_t input_size, + size_t *response_size) +{ + uint8_t prev_state = password_state; + /* The vendor command status code. */ + enum vendor_cmd_rc rv = VENDOR_RC_SUCCESS; + /* Actual error code. */ + uint8_t error_code = EC_SUCCESS; + + do { + int value; + + if (input_size != 1) { + rv = VENDOR_RC_INTERNAL_ERROR; + error_code = EC_ERROR_PARAM1; + break; + } + + value = *((uint8_t *)buf); + + if (!value) { + /* No more password setting allowed. */ + password_state = PASSWORD_NOT_ALLOWED_STATE; + break; + } + + if (password_state == POST_RESET_STATE) { + /* The only way to allow password setting. */ + password_state = PASSWORD_ALLOWED_STATE; + break; + } + + password_state = PASSWORD_NOT_ALLOWED_STATE; + rv = VENDOR_RC_BOGUS_ARGS; + error_code = EC_ERROR_INVAL; + } while (0); + + if (prev_state != password_state) + CPRINTF("%s: state change from %d to %d\n", + __func__, prev_state, password_state); + + if (rv == VENDOR_RC_SUCCESS) { + *response_size = 0; + } else { + *response_size = 1; + ((uint8_t *)buf)[0] = error_code; + } + + return rv; +} +DECLARE_VENDOR_COMMAND(VENDOR_CC_MANAGE_CCD_PWD, manage_ccd_password); + +/* * Handle the VENDOR_CC_CCD_PASSWORD command. * * The payload of the command is a text string to use to set the password. The @@ -1140,21 +1238,25 @@ static enum vendor_cmd_rc ccd_password(enum vendor_cmd_cc code, { int rv = EC_SUCCESS; char password[CCD_MAX_PASSWORD_SIZE + 1]; + char *response = buf; + + if (password_state != PASSWORD_ALLOWED_STATE) { + *response_size = 1; + *response = EC_ERROR_ACCESS_DENIED; + return VENDOR_RC_NOT_ALLOWED; + } if (!input_size || (input_size >= sizeof(password))) { rv = EC_ERROR_PARAM1; } else { memcpy(password, buf, input_size); password[input_size] = '\0'; - } - - if (rv == EC_SUCCESS) { rv = do_ccd_password(password); always_memset(password, 0, input_size); } if (rv != EC_SUCCESS) { - ((uint8_t *)buf)[0] = (uint8_t)rv; + *response = rv; *response_size = 1; return VENDOR_RC_INTERNAL_ERROR; } diff --git a/include/ccd_config.h b/include/ccd_config.h index 075cb53502..5319f9a045 100644 --- a/include/ccd_config.h +++ b/include/ccd_config.h @@ -176,4 +176,10 @@ enum ccd_reset_config_flags { */ 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); + #endif /* __CROS_EC_CCD_CONFIG_H */ diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h index 1a9682be69..830678ee0c 100644 --- a/include/tpm_vendor_cmds.h +++ b/include/tpm_vendor_cmds.h @@ -46,6 +46,7 @@ enum vendor_cmd_cc { VENDOR_CC_RMA_CHALLENGE_RESPONSE = 30, VENDOR_CC_CCD_PASSWORD = 31, VENDOR_CC_DISABLE_RMA = 32, + VENDOR_CC_MANAGE_CCD_PWD = 33, LAST_VENDOR_COMMAND = 65535, }; @@ -67,6 +68,7 @@ enum vendor_cmd_rc { VENDOR_RC_REQUEST_TOO_BIG = 4, VENDOR_RC_RESPONSE_TOO_BIG = 5, VENDOR_RC_INTERNAL_ERROR = 6, + VENDOR_RC_NOT_ALLOWED = 7, /* Only 7 bits available; max is 127 */ VENDOR_RC_NO_SUCH_COMMAND = 127, }; |