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 algo = TPM2_ALG_SHA256; 103 int algo_len; 104 int ret; 105 u32 rc; 106 107 if (argc < 3 || argc > 4) 108 return CMD_RET_USAGE; 109 if (argc == 4) { 110 algo = tpm2_name_to_algorithm(argv[3]); 111 if (algo < 0) 112 return CMD_RET_FAILURE; 113 } 114 algo_len = tpm2_algorithm_to_len(algo); 115 116 ret = get_tpm(&dev); 117 if (ret) 118 return ret; 119 120 priv = dev_get_uclass_priv(dev); 121 if (!priv) 122 return -EINVAL; 123 124 if (index >= priv->pcr_count) 125 return -EINVAL; 126 127 rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len); 128 if (!rc) { 129 printf("PCR #%u extended with %d byte %s digest\n", index, 130 algo_len, tpm2_algorithm_name(algo)); 131 print_byte_string(digest, algo_len); 132 } 133 134 unmap_sysmem(digest); 135 136 return report_return_code(rc); 137} 138 139static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc, 140 char *const argv[]) 141{ 142 enum tpm2_algorithms algo = TPM2_ALG_SHA256; 143 struct udevice *dev; 144 struct tpm_chip_priv *priv; 145 u32 index, rc; 146 int algo_len; 147 unsigned int updates; 148 void *data; 149 int ret; 150 151 if (argc < 3 || argc > 4) 152 return CMD_RET_USAGE; 153 if (argc == 4) { 154 algo = tpm2_name_to_algorithm(argv[3]); 155 if (algo < 0) 156 return CMD_RET_FAILURE; 157 } 158 algo_len = tpm2_algorithm_to_len(algo); 159 160 ret = get_tpm(&dev); 161 if (ret) 162 return ret; 163 164 priv = dev_get_uclass_priv(dev); 165 if (!priv) 166 return -EINVAL; 167 168 index = simple_strtoul(argv[1], NULL, 0); 169 if (index >= priv->pcr_count) 170 return -EINVAL; 171 172 data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0); 173 174 rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo, 175 data, algo_len, &updates); 176 if (!rc) { 177 printf("PCR #%u %s %d byte content (%u known updates):\n", index, 178 tpm2_algorithm_name(algo), algo_len, updates); 179 print_byte_string(data, algo_len); 180 } 181 182 unmap_sysmem(data); 183 184 return report_return_code(rc); 185} 186 187static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc, 188 char *const argv[]) 189{ 190 u32 capability, property, rc; 191 u8 *data; 192 size_t count; 193 int i, j; 194 struct udevice *dev; 195 int ret; 196 197 ret = get_tpm(&dev); 198 if (ret) 199 return ret; 200 201 if (argc != 5) 202 return CMD_RET_USAGE; 203 204 capability = simple_strtoul(argv[1], NULL, 0); 205 property = simple_strtoul(argv[2], NULL, 0); 206 data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0); 207 count = simple_strtoul(argv[4], NULL, 0); 208 209 rc = tpm2_get_capability(dev, capability, property, data, count); 210 if (rc) 211 goto unmap_data; 212 213 printf("Capabilities read from TPM:\n"); 214 for (i = 0; i < count; i++) { 215 printf("Property 0x"); 216 for (j = 0; j < 4; j++) 217 printf("%02x", data[(i * 8) + j + sizeof(u32)]); 218 printf(": 0x"); 219 for (j = 4; j < 8; j++) 220 printf("%02x", data[(i * 8) + j + sizeof(u32)]); 221 printf("\n"); 222 } 223 224unmap_data: 225 unmap_sysmem(data); 226 227 return report_return_code(rc); 228} 229 230static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc, 231 char *const argv[]) 232{ 233 const char *pw = (argc < 2) ? NULL : argv[1]; 234 const ssize_t pw_sz = pw ? strlen(pw) : 0; 235 struct udevice *dev; 236 int ret; 237 238 ret = get_tpm(&dev); 239 if (ret) 240 return ret; 241 242 if (argc > 2) 243 return CMD_RET_USAGE; 244 245 if (pw_sz > TPM2_DIGEST_LEN) 246 return -EINVAL; 247 248 return report_return_code(tpm2_dam_reset(dev, pw, pw_sz)); 249} 250 251static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc, 252 char *const argv[]) 253{ 254 const char *pw = (argc < 5) ? NULL : argv[4]; 255 const ssize_t pw_sz = pw ? strlen(pw) : 0; 256 /* 257 * No Dictionary Attack Mitigation (DAM) means: 258 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0 259 */ 260 unsigned long int max_tries; 261 unsigned long int recovery_time; 262 unsigned long int lockout_recovery; 263 struct udevice *dev; 264 int ret; 265 266 ret = get_tpm(&dev); 267 if (ret) 268 return ret; 269 270 if (argc < 4 || argc > 5) 271 return CMD_RET_USAGE; 272 273 if (pw_sz > TPM2_DIGEST_LEN) 274 return -EINVAL; 275 276 if (strict_strtoul(argv[1], 0, &max_tries)) 277 return CMD_RET_USAGE; 278 279 if (strict_strtoul(argv[2], 0, &recovery_time)) 280 return CMD_RET_USAGE; 281 282 if (strict_strtoul(argv[3], 0, &lockout_recovery)) 283 return CMD_RET_USAGE; 284 285 log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n"); 286 log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries); 287 log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time); 288 log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery); 289 290 return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries, 291 recovery_time, 292 lockout_recovery)); 293} 294 295static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc, 296 char *const argv[]) 297{ 298 u32 handle; 299 const char *newpw = argv[2]; 300 const char *oldpw = (argc == 3) ? NULL : argv[3]; 301 const ssize_t newpw_sz = strlen(newpw); 302 const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0; 303 struct udevice *dev; 304 int ret; 305 306 ret = get_tpm(&dev); 307 if (ret) 308 return ret; 309 310 if (argc < 3 || argc > 4) 311 return CMD_RET_USAGE; 312 313 if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN) 314 return -EINVAL; 315 316 if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1])) 317 handle = TPM2_RH_LOCKOUT; 318 else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1])) 319 handle = TPM2_RH_ENDORSEMENT; 320 else if (!strcasecmp("TPM2_RH_OWNER", argv[1])) 321 handle = TPM2_RH_OWNER; 322 else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1])) 323 handle = TPM2_RH_PLATFORM; 324 else 325 return CMD_RET_USAGE; 326 327 return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz, 328 oldpw, oldpw_sz)); 329} 330 331static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc, 332 char *const argv[]) 333{ 334 u32 index = simple_strtoul(argv[1], NULL, 0); 335 char *key = argv[2]; 336 const char *pw = (argc < 4) ? NULL : argv[3]; 337 const ssize_t pw_sz = pw ? strlen(pw) : 0; 338 struct udevice *dev; 339 int ret; 340 341 ret = get_tpm(&dev); 342 if (ret) 343 return ret; 344 345 if (strlen(key) != TPM2_DIGEST_LEN) 346 return -EINVAL; 347 348 if (argc < 3 || argc > 4) 349 return CMD_RET_USAGE; 350 351 return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index, 352 key)); 353} 354 355static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, 356 int argc, char *const argv[]) 357{ 358 u32 index = simple_strtoul(argv[1], NULL, 0); 359 char *key = argv[2]; 360 const ssize_t key_sz = strlen(key); 361 const char *pw = (argc < 4) ? NULL : argv[3]; 362 const ssize_t pw_sz = pw ? strlen(pw) : 0; 363 struct udevice *dev; 364 int ret; 365 366 ret = get_tpm(&dev); 367 if (ret) 368 return ret; 369 370 if (strlen(key) != TPM2_DIGEST_LEN) 371 return -EINVAL; 372 373 if (argc < 3 || argc > 4) 374 return CMD_RET_USAGE; 375 376 return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index, 377 key, key_sz)); 378} 379 380static struct cmd_tbl tpm2_commands[] = { 381 U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""), 382 U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), 383 U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""), 384 U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), 385 U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""), 386 U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""), 387 U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""), 388 U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""), 389 U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""), 390 U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""), 391 U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""), 392 U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""), 393 U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""), 394 U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""), 395 U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1, 396 do_tpm_pcr_setauthpolicy, "", ""), 397 U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, 398 do_tpm_pcr_setauthvalue, "", ""), 399}; 400 401struct cmd_tbl *get_tpm2_commands(unsigned int *size) 402{ 403 *size = ARRAY_SIZE(tpm2_commands); 404 405 return tpm2_commands; 406} 407 408U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", 409"<command> [<arguments>]\n" 410"\n" 411"device [num device]\n" 412" Show all devices or set the specified device\n" 413"info\n" 414" Show information about the TPM.\n" 415"state\n" 416" Show internal state from the TPM (if available)\n" 417"autostart\n" 418" Initalize the tpm, perform a Startup(clear) and run a full selftest\n" 419" sequence\n" 420"init\n" 421" Initialize the software stack. Always the first command to issue.\n" 422" 'tpm startup' is the only acceptable command after a 'tpm init' has been\n" 423" issued\n" 424"startup <mode>\n" 425" Issue a TPM2_Startup command.\n" 426" <mode> is one of:\n" 427" * TPM2_SU_CLEAR (reset state)\n" 428" * TPM2_SU_STATE (preserved state)\n" 429"self_test <type>\n" 430" Test the TPM capabilities.\n" 431" <type> is one of:\n" 432" * full (perform all tests)\n" 433" * continue (only check untested tests)\n" 434"clear <hierarchy>\n" 435" Issue a TPM2_Clear command.\n" 436" <hierarchy> is one of:\n" 437" * TPM2_RH_LOCKOUT\n" 438" * TPM2_RH_PLATFORM\n" 439"pcr_extend <pcr> <digest_addr> [<digest_algo>]\n" 440" Extend PCR #<pcr> with digest at <digest_addr> with digest_algo.\n" 441" <pcr>: index of the PCR\n" 442" <digest_addr>: address of digest of digest_algo type (defaults to SHA256)\n" 443"pcr_read <pcr> <digest_addr> [<digest_algo>]\n" 444" Read PCR #<pcr> to memory address <digest_addr> with <digest_algo>.\n" 445" <pcr>: index of the PCR\n" 446" <digest_addr>: address of digest of digest_algo type (defaults to SHA256)\n" 447"get_capability <capability> <property> <addr> <count>\n" 448" Read and display <count> entries indexed by <capability>/<property>.\n" 449" Values are 4 bytes long and are written at <addr>.\n" 450" <capability>: capability\n" 451" <property>: property\n" 452" <addr>: address to store <count> entries of 4 bytes\n" 453" <count>: number of entries to retrieve\n" 454"dam_reset [<password>]\n" 455" If the TPM is not in a LOCKOUT state, reset the internal error counter.\n" 456" <password>: optional password\n" 457"dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]\n" 458" If the TPM is not in a LOCKOUT state, set the DAM parameters\n" 459" <maxTries>: maximum number of failures before lockout,\n" 460" 0 means always locking\n" 461" <recoveryTime>: time before decrement of the error counter,\n" 462" 0 means no lockout\n" 463" <lockoutRecovery>: time of a lockout (before the next try),\n" 464" 0 means a reboot is needed\n" 465" <password>: optional password of the LOCKOUT hierarchy\n" 466"change_auth <hierarchy> <new_pw> [<old_pw>]\n" 467" <hierarchy>: the hierarchy\n" 468" <new_pw>: new password for <hierarchy>\n" 469" <old_pw>: optional previous password of <hierarchy>\n" 470"pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n" 471" Change the <key> to access PCR #<pcr>.\n" 472" hierarchy and may be empty.\n" 473" /!\\WARNING: untested function, use at your own risks !\n" 474" <pcr>: index of the PCR\n" 475" <key>: secret to protect the access of PCR #<pcr>\n" 476" <password>: optional password of the PLATFORM hierarchy\n" 477); 478