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