summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/usb_updater/gsctool.c182
-rw-r--r--include/ccd_config.h3
-rw-r--r--include/tpm_vendor_cmds.h3
3 files changed, 179 insertions, 9 deletions
diff --git a/extra/usb_updater/gsctool.c b/extra/usb_updater/gsctool.c
index 0492bc309a..611d8754d2 100644
--- a/extra/usb_updater/gsctool.c
+++ b/extra/usb_updater/gsctool.c
@@ -98,7 +98,7 @@ static const struct ccd_capability_info ti50_cap_info[] = {
{"OpenFromUSB", CCD_CAP_STATE_IF_OPENED},
{"OverrideBatt", CCD_CAP_STATE_IF_OPENED},
/* The below capability is presently set to 'never' in ccd.rs. */
- {"BootUnverifiedRo", CCD_CAP_STATE_IF_OPENED},
+ {"AllowUnverifiedRo", CCD_CAP_STATE_IF_OPENED},
};
#define CR50_CCD_CAP_COUNT CCD_CAP_COUNT
@@ -458,18 +458,19 @@ static const struct option_container cmd_line_options[] = {
"VID:PID%USB device (default 18d1:5014 or 18d1:504a based on image)"},
{{"endorsement_seed", optional_argument, NULL, 'e'},
"[state]%get/set the endorsement key seed"},
- {{"fwver", no_argument, NULL, 'f'},
- "Report running Cr50 firmware versions"},
{{"factory", required_argument, NULL, 'F'},
"[enable|disable]%Control factory mode"},
+ {{"fwver", no_argument, NULL, 'f'},
+ "Report running Cr50 firmware versions"},
{{"getbootmode", no_argument, NULL, 'g'},
"Get the system boot mode"},
{{"help", no_argument, NULL, 'h'},
"Show this message"},
{{"erase_ap_ro_hash", no_argument, NULL, 'H'},
"Erase AP RO hash (possible only if Board ID is not set)"},
- {{"ccd_info", no_argument, NULL, 'I'},
- "Get information about CCD state"},
+ {{"ccd_info", optional_argument, NULL, 'I'},
+ "[capability:value]%Get information about CCD state or set capability"
+ " value if allowed"},
{{"board_id", optional_argument, NULL, 'i'},
"[ID[:FLAGS]]%Get or set Info1 board ID fields. ID could be 32 bit "
"hex or 4 character string."},
@@ -1718,6 +1719,156 @@ static void invalidate_inactive_rw(struct transfer_descriptor *td)
exit(update_error);
}
+/*
+ * Try setting CCD capability.
+ *
+ * The 'parameter' string includes capability and desired new state separated
+ * by a ':', both parts could be abbreviated and checked for the match as case
+ * insensitive.
+ *
+ * The result of the attempt depends on the policies installed on
+ * Ti50. The result could be on of the following:
+ *
+ * - success (capability is successfully changed, or is already at the
+ * requested level),
+ * - various errors if setting the capability is not allowed or something
+ * goes wrong on Ti50
+ * - request for physical presence confirmation
+ */
+static enum exit_values process_set_capabililty(struct transfer_descriptor *td,
+ const char *parameter)
+{
+ const char *colon;
+ size_t len;
+ size_t cap_index;
+ size_t i;
+ uint8_t rc;
+ const char *error_text;
+ const char *cr50_err =
+ "Note: setting capabilities not available on Cr50\n";
+ /*
+ * The payload is three bytes, command version, capability, and
+ * desired state, all expressed as u8.
+ */
+ struct __attribute__((__packed__)) {
+ uint8_t version;
+ uint8_t cap;
+ uint8_t value;
+ } command;
+ /*
+ * Translation table of possible desired capabilities, Cr50 values
+ * and duplicated in common/syscalls/src/ccd.rs::CcdCapState.
+ */
+ struct {
+ const char *state_name;
+ enum ccd_capability_state desired_state;
+ } states[] = {
+ {"default", CCD_CAP_STATE_DEFAULT},
+ {"always", CCD_CAP_STATE_ALWAYS},
+ {"if_opened", CCD_CAP_STATE_IF_OPENED},
+ };
+
+ /*
+ * Possible responses from Ti50 when trying to modify AlloUnverifiedRo
+ * capability. The values come from
+ * common/libs/tpm2/extension/src/lib.rs::TpmvReturnCode.
+ */
+ enum set_allow_unverified_ro_responses {
+ AUR_SUCCESS = 0,
+ AUR_BOGUS_ARGS = 1,
+ AUR_INTERNAL_ERROR = 6,
+ AUR_NOT_ALLOWED = 7,
+ AUR_IN_PROGRESS = 9,
+ };
+
+ /*
+ * Validate the parameter, for starters make sure that the colon
+ * symbol is present and is neither the first nor the last character
+ * in the string.
+ */
+ colon = strchr(parameter, ':');
+ if (!colon || (colon == parameter) || (colon[1] == '\0')) {
+ fprintf(stderr, "Misformatted capability parameter: %s\n",
+ parameter);
+ exit(update_error);
+ }
+
+ /*
+ * Find the capability index in the table, reject ambiguous
+ * abbreviations.
+ */
+ len = colon - parameter;
+ for (i = 0, cap_index = ARRAY_SIZE(ti50_cap_info);
+ i < ARRAY_SIZE(ti50_cap_info); i++) {
+ if (!strncasecmp(ti50_cap_info[i].name, parameter, len)) {
+ if (cap_index != ARRAY_SIZE(ti50_cap_info)) {
+ fprintf(stderr, "Ambiguous capability name\n");
+ exit(update_error);
+ }
+ cap_index = i;
+ }
+ }
+ if (cap_index == ARRAY_SIZE(ti50_cap_info)) {
+ fprintf(stderr, "Unknown capability name\n%s", cr50_err);
+ exit(update_error);
+ }
+
+ /* Calculate length of the desired value. */
+ len = strlen(parameter) - len - 1;
+
+ /* Find the value index in the table. */
+ for (i = 0; i < ARRAY_SIZE(states); i++) {
+ if (!strncasecmp(states[i].state_name, colon + 1, len))
+ break;
+ }
+ if (i == ARRAY_SIZE(states)) {
+ fprintf(stderr, "Unsupported capability value\n");
+ return update_error;
+ }
+
+ /* Prepare and send vendor command to request setting capability. */
+ command.version = CCD_VERSION;
+ command.cap = (uint8_t)cap_index;
+ command.value = (uint8_t)states[i].desired_state;
+
+ i = 0;
+ len = 1;
+ send_vendor_command(td, VENDOR_CC_SET_CAPABILITY,
+ &command, sizeof(command), &rc, &len);
+
+ if (len != 1) {
+ fprintf(stderr, "Unexpected return message size %zd\n", len);
+ if (len == 0)
+ fprintf(stderr, "%s", cr50_err);
+ return update_error;
+ }
+
+ switch (rc) {
+ case AUR_IN_PROGRESS:
+ /*
+ * Physical presence poll is required, note fall through to
+ * the next case.
+ */
+ poll_for_pp(td, VENDOR_CC_CCD, CCDV_PP_POLL_SET_CAPABILITY);
+ case AUR_SUCCESS:
+ return noop; /* All is well, no need to do anything. */
+ case AUR_BOGUS_ARGS:
+ error_text = "BogusArgs";
+ break;
+ case AUR_INTERNAL_ERROR:
+ error_text = "InternalError";
+ break;
+ case AUR_NOT_ALLOWED:
+ error_text = "NotAllowed";
+ break;
+ default:
+ error_text = "Unknown";
+ break;
+ }
+ fprintf(stderr, "Got error %d(%s)\n", rc, error_text);
+ return update_error;
+}
+
static void process_erase_ap_ro_hash(struct transfer_descriptor *td)
{
/* Try erasing AP RO hash, could fail if board ID is programmed. */
@@ -3744,6 +3895,8 @@ int main(int argc, char *argv[])
uint8_t sn_inc_rma_arg = 0;
int erase_ap_ro_hash = 0;
int is_dauntless = 0;
+ int set_capability = 0;
+ const char *capability_parameter = "";
/*
* All options which result in setting a Boolean flag to True, along
@@ -3756,7 +3909,6 @@ int main(int argc, char *argv[])
{ 'f', &show_fw_ver },
{ 'g', &get_boot_mode},
{ 'H', &erase_ap_ro_hash},
- { 'I', &ccd_info },
{ 'k', &ccd_lock },
{ 'o', &ccd_open },
{ 'P', &password },
@@ -3874,6 +4026,16 @@ int main(int argc, char *argv[])
case 'h':
usage(errorcnt);
break;
+ case 'I':
+ if (optarg) {
+ set_capability = 1;
+ capability_parameter = optarg;
+ /* Supported on Dauntless only. */
+ is_dauntless = 1;
+ } else {
+ ccd_info = 1;
+ }
+ break;
case 'i':
if (!parse_bid(optarg, &bid, &bid_action)) {
fprintf(stderr,
@@ -4014,6 +4176,7 @@ int main(int argc, char *argv[])
!erase_ap_ro_hash &&
!password &&
!rma &&
+ !set_capability &&
!show_fw_ver &&
!sn_bits &&
!sn_inc_rma &&
@@ -4059,9 +4222,9 @@ int main(int argc, char *argv[])
!!ccd_unlock + !!ccd_lock + !!ccd_info + !!get_flog +
!!get_boot_mode + !!openbox_desc_file + !!factory_mode +
(wp != WP_NONE) + !!get_endorsement_seed +
- !!erase_ap_ro_hash) > 1) {
+ !!erase_ap_ro_hash + !!set_capability) > 1) {
fprintf(stderr,
- "ERROR: options"
+ "ERROR: options "
"-e, -F, -g, -H, -I, -i, -k, -L, -O, -o, -P, -r, -U"
" and -w are mutually exclusive\n");
exit(update_error);
@@ -4090,6 +4253,9 @@ int main(int argc, char *argv[])
process_ccd_state(&td, ccd_unlock, ccd_open,
ccd_lock, ccd_info);
+ if (set_capability)
+ exit(process_set_capabililty(&td, capability_parameter));
+
if (password)
process_password(&td);
diff --git a/include/ccd_config.h b/include/ccd_config.h
index 13762c5b5e..61c0a44809 100644
--- a/include/ccd_config.h
+++ b/include/ccd_config.h
@@ -219,7 +219,8 @@ enum ccd_vendor_subcommands {
CCDV_LOCK = 3,
CCDV_PP_POLL_UNLOCK = 4,
CCDV_PP_POLL_OPEN = 5,
- CCDV_GET_INFO = 6
+ CCDV_GET_INFO = 6,
+ CCDV_PP_POLL_SET_CAPABILITY = 7,
};
enum ccd_pp_state {
diff --git a/include/tpm_vendor_cmds.h b/include/tpm_vendor_cmds.h
index 2be888c6a3..51f5143120 100644
--- a/include/tpm_vendor_cmds.h
+++ b/include/tpm_vendor_cmds.h
@@ -192,6 +192,9 @@ enum vendor_cmd_cc {
VENDOR_CC_GET_AP_RO_VERIFY_SETTING = 62,
VENDOR_CC_SET_AP_RO_VERIFY_SETTING = 63,
+ /* Ti50 only. */
+ VENDOR_CC_SET_CAPABILITY = 64,
+
LAST_VENDOR_COMMAND = 65535,
};