summaryrefslogtreecommitdiff
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
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>
-rw-r--r--board/cr50/tpm2/platform.c6
-rw-r--r--common/ccd_config.c110
-rw-r--r--include/ccd_config.h6
-rw-r--r--include/tpm_vendor_cmds.h2
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 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;
}
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,
};