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 16 static int do_tpm2_startup(cmd_tbl_t *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 41 static int do_tpm2_self_test(cmd_tbl_t *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 66 static int do_tpm2_clear(cmd_tbl_t *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 95 static int do_tpm2_pcr_extend(cmd_tbl_t *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 127 static int do_tpm_pcr_read(cmd_tbl_t *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 166 static int do_tpm_get_capability(cmd_tbl_t *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 203 unmap_data: 204 unmap_sysmem(data); 205 206 return report_return_code(rc); 207 } 208 209 static int do_tpm_dam_reset(cmd_tbl_t *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 230 static int do_tpm_dam_parameters(cmd_tbl_t *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 274 static int do_tpm_change_auth(cmd_tbl_t *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 310 static int do_tpm_pcr_setauthpolicy(cmd_tbl_t *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 334 static int do_tpm_pcr_setauthvalue(cmd_tbl_t *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 359 static cmd_tbl_t 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(pcr_setauthpolicy, 0, 1, 374 do_tpm_pcr_setauthpolicy, "", ""), 375 U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1, 376 do_tpm_pcr_setauthvalue, "", ""), 377 }; 378 379 cmd_tbl_t *get_tpm2_commands(unsigned int *size) 380 { 381 *size = ARRAY_SIZE(tpm2_commands); 382 383 return tpm2_commands; 384 } 385 386 U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", 387 "<command> [<arguments>]\n" 388 "\n" 389 "device [num device]\n" 390 " Show all devices or set the specified device\n" 391 "info\n" 392 " Show information about the TPM.\n" 393 "state\n" 394 " Show internal state from the TPM (if available)\n" 395 "init\n" 396 " Initialize the software stack. Always the first command to issue.\n" 397 "startup <mode>\n" 398 " Issue a TPM2_Startup command.\n" 399 " <mode> is one of:\n" 400 " * TPM2_SU_CLEAR (reset state)\n" 401 " * TPM2_SU_STATE (preserved state)\n" 402 "self_test <type>\n" 403 " Test the TPM capabilities.\n" 404 " <type> is one of:\n" 405 " * full (perform all tests)\n" 406 " * continue (only check untested tests)\n" 407 "clear <hierarchy>\n" 408 " Issue a TPM2_Clear command.\n" 409 " <hierarchy> is one of:\n" 410 " * TPM2_RH_LOCKOUT\n" 411 " * TPM2_RH_PLATFORM\n" 412 "pcr_extend <pcr> <digest_addr>\n" 413 " Extend PCR #<pcr> with digest at <digest_addr>.\n" 414 " <pcr>: index of the PCR\n" 415 " <digest_addr>: address of a 32-byte SHA256 digest\n" 416 "pcr_read <pcr> <digest_addr>\n" 417 " Read PCR #<pcr> to memory address <digest_addr>.\n" 418 " <pcr>: index of the PCR\n" 419 " <digest_addr>: address to store the a 32-byte SHA256 digest\n" 420 "get_capability <capability> <property> <addr> <count>\n" 421 " Read and display <count> entries indexed by <capability>/<property>.\n" 422 " Values are 4 bytes long and are written at <addr>.\n" 423 " <capability>: capability\n" 424 " <property>: property\n" 425 " <addr>: address to store <count> entries of 4 bytes\n" 426 " <count>: number of entries to retrieve\n" 427 "dam_reset [<password>]\n" 428 " If the TPM is not in a LOCKOUT state, reset the internal error counter.\n" 429 " <password>: optional password\n" 430 "dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]\n" 431 " If the TPM is not in a LOCKOUT state, set the DAM parameters\n" 432 " <maxTries>: maximum number of failures before lockout,\n" 433 " 0 means always locking\n" 434 " <recoveryTime>: time before decrement of the error counter,\n" 435 " 0 means no lockout\n" 436 " <lockoutRecovery>: time of a lockout (before the next try),\n" 437 " 0 means a reboot is needed\n" 438 " <password>: optional password of the LOCKOUT hierarchy\n" 439 "change_auth <hierarchy> <new_pw> [<old_pw>]\n" 440 " <hierarchy>: the hierarchy\n" 441 " <new_pw>: new password for <hierarchy>\n" 442 " <old_pw>: optional previous password of <hierarchy>\n" 443 "pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n" 444 " Change the <key> to access PCR #<pcr>.\n" 445 " hierarchy and may be empty.\n" 446 " /!\\WARNING: untested function, use at your own risks !\n" 447 " <pcr>: index of the PCR\n" 448 " <key>: secret to protect the access of PCR #<pcr>\n" 449 " <password>: optional password of the PLATFORM hierarchy\n" 450 ); 451