1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2018 Bootlin 4 * Author: Miquel Raynal <miquel.raynal@bootlin.com> 5 */ 6 7#include <common.h> 8#include <command.h> 9#include <dm.h> 10#include <log.h> 11#include <mapmem.h> 12#include <tpm-common.h> 13#include <tpm-v2.h> 14#include "tpm-user-utils.h" 15 16static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, 17 char *const argv[]) 18{ 19 enum tpm2_startup_types mode; 20 struct udevice *dev; 21 int ret; 22 23 ret = get_tpm(&dev); 24 if (ret) 25 return ret; 26 if (argc != 2) 27 return CMD_RET_USAGE; 28 29 if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) { 30 mode = TPM2_SU_CLEAR; 31 } else if (!strcasecmp("TPM2_SU_STATE", argv[1])) { 32 mode = TPM2_SU_STATE; 33 } else { 34 printf("Couldn't recognize mode string: %s\n", argv[1]); 35 return CMD_RET_FAILURE; 36 } 37 38 return report_return_code(tpm2_startup(dev, mode)); 39} 40 41static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc, 42 char *const argv[]) 43{ 44 enum tpm2_yes_no full_test; 45 struct udevice *dev; 46 int ret; 47 48 ret = get_tpm(&dev); 49 if (ret) 50 return ret; 51 if (argc != 2) 52 return CMD_RET_USAGE; 53 54 if (!strcasecmp("full", argv[1])) { 55 full_test = TPMI_YES; 56 } else if (!strcasecmp("continue", argv[1])) { 57 full_test = TPMI_NO; 58 } else { 59 printf("Couldn't recognize test mode: %s\n", argv[1]); 60 return CMD_RET_FAILURE; 61 } 62 63 return report_return_code(tpm2_self_test(dev, full_test)); 64} 65 66static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc, 67 char *const argv[]) 68{ 69 u32 handle = 0; 70 const char *pw = (argc < 3) ? NULL : argv[2]; 71 const ssize_t pw_sz = pw ? strlen(pw) : 0; 72 struct udevice *dev; 73 int ret; 74 75 ret = get_tpm(&dev); 76 if (ret) 77 return ret; 78 79 if (argc < 2 || argc > 3) 80 return CMD_RET_USAGE; 81 82 if (pw_sz > TPM2_DIGEST_LEN) 83 return -EINVAL; 84 85 if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) 86 handle = TPM2_RH_LOCKOUT; 87 else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) 88 handle = TPM2_RH_PLATFORM; 89 else 90 return CMD_RET_USAGE; 91 92 return report_return_code(tpm2_clear(dev, handle, pw, pw_sz)); 93} 94 95static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc, 96 char *const argv[]) 97{ 98 struct udevice *dev; 99 struct tpm_chip_priv *priv; 100 u32 index = simple_strtoul(argv[1], NULL, 0); 101 void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); 102 int ret; 103 u32 rc; 104 105 if (argc != 3) 106 return CMD_RET_USAGE; 107 108 ret = get_tpm(&dev); 109 if (ret) 110 return ret; 111 112 priv = dev_get_uclass_priv(dev); 113 if (!priv) 114 return -EINVAL; 115 116 if (index >= priv->pcr_count) 117 return -EINVAL; 118 119 rc = tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, digest, 120 TPM2_DIGEST_LEN); 121 122 unmap_sysmem(digest); 123 124 return report_return_code(rc); 125} 126 127static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc, 128 char *const argv[]) 129{ 130 struct udevice *dev; 131 struct tpm_chip_priv *priv; 132 u32 index, rc; 133 unsigned int updates; 134 void *data; 135 int ret; 136 137 if (argc != 3) 138 return CMD_RET_USAGE; 139 140 ret = get_tpm(&dev); 141 if (ret) 142 return ret; 143 144 priv = dev_get_uclass_priv(dev); 145 if (!priv) 146 return -EINVAL; 147 148 index = simple_strtoul(argv[1], NULL, 0); 149 if (index >= priv->pcr_count) 150 return -EINVAL; 151 152 data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); 153 154 rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, TPM2_ALG_SHA256, 155 data, TPM2_DIGEST_LEN, &updates); 156 if (!rc) { 157 printf("PCR #%u content (%u known updates):\n", index, updates); 158 print_byte_string(data, TPM2_DIGEST_LEN); 159 } 160 161 unmap_sysmem(data); 162 163 return report_return_code(rc); 164} 165 166static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc, 167 char *const argv[]) 168{ 169 u32 capability, property, rc; 170 u8 *data; 171 size_t count; 172 int i, j; 173 struct udevice *dev; 174 int ret; 175 176 ret = get_tpm(&dev); 177 if (ret) 178 return ret; 179 180 if (argc != 5) 181 return CMD_RET_USAGE; 182 183 capability = simple_strtoul(argv[1], NULL, 0); 184 property = simple_strtoul(argv[2], NULL, 0); 185 data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); 186 count = simple_strtoul(argv[4], NULL, 0); 187 188 rc = tpm2_get_capability(dev, capability, property, data, count); 189 if (rc) 190 goto unmap_data; 191 192 printf("Capabilities read from TPM:\n"); 193 for (i = 0; i < count; i++) { 194 printf("Property 0x"); 195 for (j = 0; j < 4; j++) 196 printf("%02x", data[(i * 8) + j + sizeof(u32)]); 197 printf(": 0x"); 198 for (j = 4; j < 8; j++) 199 printf("%02x", data[(i * 8) + j + sizeof(u32)]); 200 printf("\n"); 201 } 202 203unmap_data: 204 unmap_sysmem(data); 205 206 return report_return_code(rc); 207} 208 209static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc, 210 char *const argv[]) 211{ 212 const char *pw = (argc < 2) ? NULL : argv[1]; 213 const ssize_t pw_sz = pw ? strlen(pw) : 0; 214 struct udevice *dev; 215 int ret; 216 217 ret = get_tpm(&dev); 218 if (ret) 219 return ret; 220 221 if (argc > 2) 222 return CMD_RET_USAGE; 223 224 if (pw_sz > TPM2_DIGEST_LEN) 225 return -EINVAL; 226 227 return report_return_code(tpm2_dam_reset(dev, pw, pw_sz)); 228} 229 230static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc, 231 char *const argv[]) 232{ 233 const char *pw = (argc < 5) ? NULL : argv[4]; 234 const ssize_t pw_sz = pw ? strlen(pw) : 0; 235 /* 236 * No Dictionary Attack Mitigation (DAM) means: 237 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0 238 */ 239 unsigned long int max_tries; 240 unsigned long int recovery_time; 241 unsigned long int lockout_recovery; 242 struct udevice *dev; 243 int ret; 244 245 ret = get_tpm(&dev); 246 if (ret) 247 return ret; 248 249 if (argc < 4 || argc > 5) 250 return CMD_RET_USAGE; 251 252 if (pw_sz > TPM2_DIGEST_LEN) 253 return -EINVAL; 254 255 if (strict_strtoul(argv[1], 0, &max_tries)) 256 return CMD_RET_USAGE; 257 258 if (strict_strtoul(argv[2], 0, &recovery_time)) 259 return CMD_RET_USAGE; 260 261 if (strict_strtoul(argv[3], 0, &lockout_recovery)) 262 return CMD_RET_USAGE; 263 264 log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n"); 265 log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries); 266 log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time); 267 log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery); 268 269 return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries, 270 recovery_time, 271 lockout_recovery)); 272} 273 274static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc, 275 char *const argv[]) 276{ 277 u32 handle; 278 const char *newpw = argv[2]; 279 const char *oldpw = (argc == 3) ? NULL : argv[3]; 280 const ssize_t newpw_sz = strlen(newpw); 281 const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; 282 struct udevice *dev; 283 int ret; 284 285 ret = get_tpm(&dev); 286 if (ret) 287 return ret; 288 289 if (argc < 3 || argc > 4) 290 return CMD_RET_USAGE; 291 292 if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN) 293 return -EINVAL; 294 295 if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) 296 handle = TPM2_RH_LOCKOUT; 297 else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1])) 298 handle = TPM2_RH_ENDORSEMENT; 299 else if (!strcasecmp("TPM2_RH_OWNER", argv[1])) 300 handle = TPM2_RH_OWNER; 301 else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) 302 handle = TPM2_RH_PLATFORM; 303 else 304 return CMD_RET_USAGE; 305 306 return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz, 307 oldpw, oldpw_sz)); 308} 309 310static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc, 311 char *const argv[]) 312{ 313 u32 index = simple_strtoul(argv[1], NULL, 0); 314 char *key = argv[2]; 315 const char *pw = (argc < 4) ? NULL : argv[3]; 316 const ssize_t pw_sz = pw ? strlen(pw) : 0; 317 struct udevice *dev; 318 int ret; 319 320 ret = get_tpm(&dev); 321 if (ret) 322 return ret; 323 324 if (strlen(key) != TPM2_DIGEST_LEN) 325 return -EINVAL; 326 327 if (argc < 3 || argc > 4) 328 return CMD_RET_USAGE; 329 330 return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index, 331 key)); 332} 333 334static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, 335 int argc, char *const argv[]) 336{ 337 u32 index = simple_strtoul(argv[1], NULL, 0); 338 char *key = argv[2]; 339 const ssize_t key_sz = strlen(key); 340 const char *pw = (argc < 4) ? NULL : argv[3]; 341 const ssize_t pw_sz = pw ? strlen(pw) : 0; 342 struct udevice *dev; 343 int ret; 344 345 ret = get_tpm(&dev); 346 if (ret) 347 return ret; 348 349 if (strlen(key) != TPM2_DIGEST_LEN) 350 return -EINVAL; 351 352 if (argc < 3 || argc > 4) 353 return CMD_RET_USAGE; 354 355 return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index, 356 key, key_sz)); 357} 358 359static struct cmd_tbl tpm2_commands[] = { 360 U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), 361 U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), 362 U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""), 363 U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), 364 U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), 365 U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), 366 U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""), 367 U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""), 368 U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""), 369 U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""), 370 U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""), 371 U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""), 372 U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""), 373 U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""), 374 U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1, 375 do_tpm_pcr_setauthpolicy, "", ""), 376 U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, 377 do_tpm_pcr_setauthvalue, "", ""), 378}; 379 380struct cmd_tbl *get_tpm2_commands(unsigned int *size) 381{ 382 *size = ARRAY_SIZE(tpm2_commands); 383 384 return tpm2_commands; 385} 386 387U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", 388"<command> [<arguments>]\n" 389"\n" 390"device [num device]\n" 391" Show all devices or set the specified device\n" 392"info\n" 393" Show information about the TPM.\n" 394"state\n" 395" Show internal state from the TPM (if available)\n" 396"autostart\n" 397" Initalize the tpm, perform a Startup(clear) and run a full selftest\n" 398" sequence\n" 399"init\n" 400" Initialize the software stack. Always the first command to issue.\n" 401" 'tpm startup' is the only acceptable command after a 'tpm init' has been\n" 402" issued\n" 403"startup <mode>\n" 404" Issue a TPM2_Startup command.\n" 405" <mode> is one of:\n" 406" * TPM2_SU_CLEAR (reset state)\n" 407" * TPM2_SU_STATE (preserved state)\n" 408"self_test <type>\n" 409" Test the TPM capabilities.\n" 410" <type> is one of:\n" 411" * full (perform all tests)\n" 412" * continue (only check untested tests)\n" 413"clear <hierarchy>\n" 414" Issue a TPM2_Clear command.\n" 415" <hierarchy> is one of:\n" 416" * TPM2_RH_LOCKOUT\n" 417" * TPM2_RH_PLATFORM\n" 418"pcr_extend <pcr> <digest_addr>\n" 419" Extend PCR #<pcr> with digest at <digest_addr>.\n" 420" <pcr>: index of the PCR\n" 421" <digest_addr>: address of a 32-byte SHA256 digest\n" 422"pcr_read <pcr> <digest_addr>\n" 423" Read PCR #<pcr> to memory address <digest_addr>.\n" 424" <pcr>: index of the PCR\n" 425" <digest_addr>: address to store the a 32-byte SHA256 digest\n" 426"get_capability <capability> <property> <addr> <count>\n" 427" Read and display <count> entries indexed by <capability>/<property>.\n" 428" Values are 4 bytes long and are written at <addr>.\n" 429" <capability>: capability\n" 430" <property>: property\n" 431" <addr>: address to store <count> entries of 4 bytes\n" 432" <count>: number of entries to retrieve\n" 433"dam_reset [<password>]\n" 434" If the TPM is not in a LOCKOUT state, reset the internal error counter.\n" 435" <password>: optional password\n" 436"dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]\n" 437" If the TPM is not in a LOCKOUT state, set the DAM parameters\n" 438" <maxTries>: maximum number of failures before lockout,\n" 439" 0 means always locking\n" 440" <recoveryTime>: time before decrement of the error counter,\n" 441" 0 means no lockout\n" 442" <lockoutRecovery>: time of a lockout (before the next try),\n" 443" 0 means a reboot is needed\n" 444" <password>: optional password of the LOCKOUT hierarchy\n" 445"change_auth <hierarchy> <new_pw> [<old_pw>]\n" 446" <hierarchy>: the hierarchy\n" 447" <new_pw>: new password for <hierarchy>\n" 448" <old_pw>: optional previous password of <hierarchy>\n" 449"pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n" 450" Change the <key> to access PCR #<pcr>.\n" 451" hierarchy and may be empty.\n" 452" /!\\WARNING: untested function, use at your own risks !\n" 453" <pcr>: index of the PCR\n" 454" <key>: secret to protect the access of PCR #<pcr>\n" 455" <password>: optional password of the PLATFORM hierarchy\n" 456); 457