summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2017-12-01 09:25:14 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-12-05 00:35:35 +0000
commit0ad146dec526f3606c5dfb6ee59a734a6f66c5f4 (patch)
tree226d31f3e99f85e62d0f6ac47bfb1edf864305b0 /common
parentff2d4ee2714bf26c9febc0d1ae5b4349705050d5 (diff)
downloadchrome-ec-0ad146dec526f3606c5dfb6ee59a734a6f66c5f4.tar.gz
ccd: restrict password setting to allowed states
Setting password should be allowed only after the owner logged in for the first time and before they log out or someone else logs in. Once any other user but the owner logs in, it should become impossible to set password until the device is reset. As proposed here, this would apply to both attempts to set password through crosh and Cr50 console. 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. Separate changes to the TPM library code make sure that TPM reset is reported through the platform layer, so that POST_RESET_STATE is entered. BRANCH=cr50 BUG=b:67007578 TEST=with the rest of the infrastructure in place verified that password can be set only when the owner logged in for the first time before anybody else logs in or the owner logs out. Change-Id: Ieaa3dc8ff9d2e43ae11151eb31173220f5c75b58 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/804141 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Andrey Pronin <apronin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/1358180 Reviewed-by: Chia-Hsiu Chang <chia-hsiu.chang@quanta.corp-partner.google.com> Reviewed-by: Marco Chen <marcochen@chromium.org> Commit-Queue: Chia-Hsiu Chang <chia-hsiu.chang@quanta.corp-partner.google.com> Tested-by: Chia-Hsiu Chang <chia-hsiu.chang@quanta.corp-partner.google.com>
Diffstat (limited to 'common')
-rw-r--r--common/ccd_config.c110
1 files changed, 106 insertions, 4 deletions
diff --git a/common/ccd_config.c b/common/ccd_config.c
index dd46b1b1db..4a2002b785 100644
--- a/common/ccd_config.c
+++ b/common/ccd_config.c
@@ -1117,6 +1117,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
@@ -1130,21 +1228,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;
}