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-11-13 00:18:59 +0000
commita6987e28e610b263dfbfd578bb4cd4e52bc275d1 (patch)
tree4c9222ecb21d5357e2516a6ec6507b3ea31433a3
parent51eefac583d345034cf5018ae12c93896f6a0881 (diff)
downloadchrome-ec-a6987e28e610b263dfbfd578bb4cd4e52bc275d1.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/1332612 Reviewed-by: Marco Chen <marcochen@chromium.org> Commit-Queue: Marco Chen <marcochen@chromium.org> Tested-by: Marco Chen <marcochen@chromium.org>
-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 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,
};