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 <tpm-v2.h> 10 #include <asm/state.h> 11 #include <asm/unaligned.h> 12 #include <linux/crc8.h> 13 14 /* Hierarchies */ 15 enum tpm2_hierarchy { 16 TPM2_HIERARCHY_LOCKOUT = 0, 17 TPM2_HIERARCHY_ENDORSEMENT, 18 TPM2_HIERARCHY_PLATFORM, 19 TPM2_HIERARCHY_NB, 20 }; 21 22 /* Subset of supported capabilities */ 23 enum tpm2_capability { 24 TPM_CAP_TPM_PROPERTIES = 0x6, 25 }; 26 27 /* Subset of supported properties */ 28 #define TPM2_PROPERTIES_OFFSET 0x0000020E 29 30 enum tpm2_cap_tpm_property { 31 TPM2_FAIL_COUNTER = 0, 32 TPM2_PROP_MAX_TRIES, 33 TPM2_RECOVERY_TIME, 34 TPM2_LOCKOUT_RECOVERY, 35 TPM2_PROPERTY_NB, 36 }; 37 38 #define SANDBOX_TPM_PCR_NB 1 39 40 static const u8 sandbox_extended_once_pcr[] = { 41 0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30, 42 0x27, 0x98, 0xef, 0x6e, 0xd3, 0x09, 0x97, 0x9b, 43 0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8, 44 0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b, 45 }; 46 47 struct sandbox_tpm2 { 48 /* TPM internal states */ 49 bool init_done; 50 bool startup_done; 51 bool tests_done; 52 /* TPM password per hierarchy */ 53 char pw[TPM2_HIERARCHY_NB][TPM2_DIGEST_LEN + 1]; 54 int pw_sz[TPM2_HIERARCHY_NB]; 55 /* TPM properties */ 56 u32 properties[TPM2_PROPERTY_NB]; 57 /* TPM PCRs */ 58 u8 pcr[SANDBOX_TPM_PCR_NB][TPM2_DIGEST_LEN]; 59 /* TPM PCR extensions */ 60 u32 pcr_extensions[SANDBOX_TPM_PCR_NB]; 61 }; 62 63 /* 64 * Check the tag validity depending on the command (authentication required or 65 * not). If authentication is required, check it is valid. Update the auth 66 * pointer to point to the next chunk of data to process if needed. 67 */ 68 static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag, 69 const u8 **auth, 70 enum tpm2_hierarchy *hierarchy) 71 { 72 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 73 u32 handle, auth_sz, session_handle; 74 u16 nonce_sz, pw_sz; 75 const char *pw; 76 77 switch (command) { 78 case TPM2_CC_STARTUP: 79 case TPM2_CC_SELF_TEST: 80 case TPM2_CC_GET_CAPABILITY: 81 case TPM2_CC_PCR_READ: 82 if (tag != TPM2_ST_NO_SESSIONS) { 83 printf("No session required for command 0x%x\n", 84 command); 85 return TPM2_RC_BAD_TAG; 86 } 87 88 return 0; 89 90 case TPM2_CC_CLEAR: 91 case TPM2_CC_HIERCHANGEAUTH: 92 case TPM2_CC_DAM_RESET: 93 case TPM2_CC_DAM_PARAMETERS: 94 case TPM2_CC_PCR_EXTEND: 95 if (tag != TPM2_ST_SESSIONS) { 96 printf("Session required for command 0x%x\n", command); 97 return TPM2_RC_AUTH_CONTEXT; 98 } 99 100 handle = get_unaligned_be32(*auth); 101 *auth += sizeof(handle); 102 103 /* 104 * PCR_Extend had a different protection mechanism and does not 105 * use the same standards as other commands. 106 */ 107 if (command == TPM2_CC_PCR_EXTEND) 108 break; 109 110 switch (handle) { 111 case TPM2_RH_LOCKOUT: 112 *hierarchy = TPM2_HIERARCHY_LOCKOUT; 113 break; 114 case TPM2_RH_ENDORSEMENT: 115 if (command == TPM2_CC_CLEAR) { 116 printf("Endorsement hierarchy unsupported\n"); 117 return TPM2_RC_AUTH_MISSING; 118 } 119 *hierarchy = TPM2_HIERARCHY_ENDORSEMENT; 120 break; 121 case TPM2_RH_PLATFORM: 122 *hierarchy = TPM2_HIERARCHY_PLATFORM; 123 break; 124 default: 125 printf("Wrong handle 0x%x\n", handle); 126 return TPM2_RC_VALUE; 127 } 128 129 break; 130 131 default: 132 printf("Command code not recognized: 0x%x\n", command); 133 return TPM2_RC_COMMAND_CODE; 134 } 135 136 auth_sz = get_unaligned_be32(*auth); 137 *auth += sizeof(auth_sz); 138 139 session_handle = get_unaligned_be32(*auth); 140 *auth += sizeof(session_handle); 141 if (session_handle != TPM2_RS_PW) { 142 printf("Wrong session handle 0x%x\n", session_handle); 143 return TPM2_RC_VALUE; 144 } 145 146 nonce_sz = get_unaligned_be16(*auth); 147 *auth += sizeof(nonce_sz); 148 if (nonce_sz) { 149 printf("Nonces not supported in Sandbox, aborting\n"); 150 return TPM2_RC_HANDLE; 151 } 152 153 /* Ignore attributes */ 154 *auth += sizeof(u8); 155 156 pw_sz = get_unaligned_be16(*auth); 157 *auth += sizeof(pw_sz); 158 if (auth_sz != (9 + nonce_sz + pw_sz)) { 159 printf("Authentication size (%d) do not match %d\n", 160 auth_sz, 9 + nonce_sz + pw_sz); 161 return TPM2_RC_SIZE; 162 } 163 164 /* No passwork is acceptable */ 165 if (!pw_sz && !tpm->pw_sz[*hierarchy]) 166 return TPM2_RC_SUCCESS; 167 168 /* Password is too long */ 169 if (pw_sz > TPM2_DIGEST_LEN) { 170 printf("Password should not be more than %dB\n", 171 TPM2_DIGEST_LEN); 172 return TPM2_RC_AUTHSIZE; 173 } 174 175 pw = (const char *)*auth; 176 *auth += pw_sz; 177 178 /* Password is wrong */ 179 if (pw_sz != tpm->pw_sz[*hierarchy] || 180 strncmp(pw, tpm->pw[*hierarchy], tpm->pw_sz[*hierarchy])) { 181 printf("Authentication failed: wrong password.\n"); 182 return TPM2_RC_BAD_AUTH; 183 } 184 185 return TPM2_RC_SUCCESS; 186 } 187 188 static int sandbox_tpm2_check_readyness(struct udevice *dev, int command) 189 { 190 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 191 192 switch (command) { 193 case TPM2_CC_STARTUP: 194 if (!tpm->init_done || tpm->startup_done) 195 return TPM2_RC_INITIALIZE; 196 197 break; 198 case TPM2_CC_GET_CAPABILITY: 199 if (!tpm->init_done || !tpm->startup_done) 200 return TPM2_RC_INITIALIZE; 201 202 break; 203 case TPM2_CC_SELF_TEST: 204 if (!tpm->startup_done) 205 return TPM2_RC_INITIALIZE; 206 207 break; 208 default: 209 if (!tpm->tests_done) 210 return TPM2_RC_NEEDS_TEST; 211 212 break; 213 } 214 215 return 0; 216 } 217 218 static int sandbox_tpm2_fill_buf(u8 **recv, size_t *recv_len, u16 tag, u32 rc) 219 { 220 *recv_len = sizeof(tag) + sizeof(u32) + sizeof(rc); 221 222 /* Write tag */ 223 put_unaligned_be16(tag, *recv); 224 *recv += sizeof(tag); 225 226 /* Write length */ 227 put_unaligned_be32(*recv_len, *recv); 228 *recv += sizeof(u32); 229 230 /* Write return code */ 231 put_unaligned_be32(rc, *recv); 232 *recv += sizeof(rc); 233 234 /* Add trailing \0 */ 235 *recv = NULL; 236 237 return 0; 238 } 239 240 static int sandbox_tpm2_extend(struct udevice *dev, int pcr_index, 241 const u8 *extension) 242 { 243 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 244 int i; 245 246 /* Only simulate the first extensions from all '0' with only '0' */ 247 for (i = 0; i < TPM2_DIGEST_LEN; i++) 248 if (tpm->pcr[pcr_index][i] || extension[i]) 249 return TPM2_RC_FAILURE; 250 251 memcpy(tpm->pcr[pcr_index], sandbox_extended_once_pcr, 252 TPM2_DIGEST_LEN); 253 tpm->pcr_extensions[pcr_index]++; 254 255 return 0; 256 }; 257 258 static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf, 259 size_t send_size, u8 *recvbuf, 260 size_t *recv_len) 261 { 262 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 263 enum tpm2_hierarchy hierarchy = 0; 264 const u8 *sent = sendbuf; 265 u8 *recv = recvbuf; 266 u32 length, command, rc = 0; 267 u16 tag, mode, new_pw_sz; 268 u8 yes_no; 269 int i, j; 270 271 /* TPM2_GetProperty */ 272 u32 capability, property, property_count; 273 274 /* TPM2_PCR_Read/Extend variables */ 275 int pcr_index; 276 u64 pcr_map = 0; 277 u32 selections, pcr_nb; 278 u16 alg; 279 u8 pcr_array_sz; 280 281 tag = get_unaligned_be16(sent); 282 sent += sizeof(tag); 283 284 length = get_unaligned_be32(sent); 285 sent += sizeof(length); 286 if (length != send_size) { 287 printf("TPM2: Unmatching length, received: %ld, expected: %d\n", 288 send_size, length); 289 rc = TPM2_RC_SIZE; 290 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 291 return 0; 292 } 293 294 command = get_unaligned_be32(sent); 295 sent += sizeof(command); 296 rc = sandbox_tpm2_check_readyness(dev, command); 297 if (rc) { 298 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 299 return 0; 300 } 301 302 rc = sandbox_tpm2_check_session(dev, command, tag, &sent, &hierarchy); 303 if (rc) { 304 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 305 return 0; 306 } 307 308 switch (command) { 309 case TPM2_CC_STARTUP: 310 mode = get_unaligned_be16(sent); 311 sent += sizeof(mode); 312 switch (mode) { 313 case TPM2_SU_CLEAR: 314 case TPM2_SU_STATE: 315 break; 316 default: 317 rc = TPM2_RC_VALUE; 318 } 319 320 tpm->startup_done = true; 321 322 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 323 break; 324 325 case TPM2_CC_SELF_TEST: 326 yes_no = *sent; 327 sent += sizeof(yes_no); 328 switch (yes_no) { 329 case TPMI_YES: 330 case TPMI_NO: 331 break; 332 default: 333 rc = TPM2_RC_VALUE; 334 } 335 336 tpm->tests_done = true; 337 338 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 339 break; 340 341 case TPM2_CC_CLEAR: 342 /* Reset this hierarchy password */ 343 tpm->pw_sz[hierarchy] = 0; 344 345 /* Reset all password if thisis the PLATFORM hierarchy */ 346 if (hierarchy == TPM2_HIERARCHY_PLATFORM) 347 for (i = 0; i < TPM2_HIERARCHY_NB; i++) 348 tpm->pw_sz[i] = 0; 349 350 /* Reset the properties */ 351 for (i = 0; i < TPM2_PROPERTY_NB; i++) 352 tpm->properties[i] = 0; 353 354 /* Reset the PCRs and their number of extensions */ 355 for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) { 356 tpm->pcr_extensions[i] = 0; 357 for (j = 0; j < TPM2_DIGEST_LEN; j++) 358 tpm->pcr[i][j] = 0; 359 } 360 361 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 362 break; 363 364 case TPM2_CC_HIERCHANGEAUTH: 365 new_pw_sz = get_unaligned_be16(sent); 366 sent += sizeof(new_pw_sz); 367 if (new_pw_sz > TPM2_DIGEST_LEN) { 368 rc = TPM2_RC_SIZE; 369 } else if (new_pw_sz) { 370 tpm->pw_sz[hierarchy] = new_pw_sz; 371 memcpy(tpm->pw[hierarchy], sent, new_pw_sz); 372 sent += new_pw_sz; 373 } 374 375 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 376 break; 377 378 case TPM2_CC_GET_CAPABILITY: 379 capability = get_unaligned_be32(sent); 380 sent += sizeof(capability); 381 if (capability != TPM_CAP_TPM_PROPERTIES) { 382 printf("Sandbox TPM only support TPM_CAPABILITIES\n"); 383 return TPM2_RC_HANDLE; 384 } 385 386 property = get_unaligned_be32(sent); 387 sent += sizeof(property); 388 property -= TPM2_PROPERTIES_OFFSET; 389 390 property_count = get_unaligned_be32(sent); 391 sent += sizeof(property_count); 392 if (!property_count || 393 property + property_count > TPM2_PROPERTY_NB) { 394 rc = TPM2_RC_HANDLE; 395 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 396 } 397 398 /* Write tag */ 399 put_unaligned_be16(tag, recv); 400 recv += sizeof(tag); 401 402 /* Ignore length for now */ 403 recv += sizeof(u32); 404 405 /* Write return code */ 406 put_unaligned_be32(rc, recv); 407 recv += sizeof(rc); 408 409 /* Tell there is more data to read */ 410 *recv = TPMI_YES; 411 recv += sizeof(yes_no); 412 413 /* Repeat the capability */ 414 put_unaligned_be32(capability, recv); 415 recv += sizeof(capability); 416 417 /* Give the number of properties that follow */ 418 put_unaligned_be32(property_count, recv); 419 recv += sizeof(property_count); 420 421 /* Fill with the properties */ 422 for (i = 0; i < property_count; i++) { 423 put_unaligned_be32(TPM2_PROPERTIES_OFFSET + property + 424 i, recv); 425 recv += sizeof(property); 426 put_unaligned_be32(tpm->properties[property + i], 427 recv); 428 recv += sizeof(property); 429 } 430 431 /* Add trailing \0 */ 432 *recv = '\0'; 433 434 /* Write response length */ 435 *recv_len = recv - recvbuf; 436 put_unaligned_be32(*recv_len, recvbuf + sizeof(tag)); 437 438 break; 439 440 case TPM2_CC_DAM_PARAMETERS: 441 tpm->properties[TPM2_PROP_MAX_TRIES] = get_unaligned_be32(sent); 442 sent += sizeof(*tpm->properties); 443 tpm->properties[TPM2_RECOVERY_TIME] = get_unaligned_be32(sent); 444 sent += sizeof(*tpm->properties); 445 tpm->properties[TPM2_LOCKOUT_RECOVERY] = get_unaligned_be32(sent); 446 sent += sizeof(*tpm->properties); 447 448 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 449 break; 450 451 case TPM2_CC_PCR_READ: 452 selections = get_unaligned_be32(sent); 453 sent += sizeof(selections); 454 if (selections != 1) { 455 printf("Sandbox cannot handle more than one PCR\n"); 456 rc = TPM2_RC_VALUE; 457 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 458 } 459 460 alg = get_unaligned_be16(sent); 461 sent += sizeof(alg); 462 if (alg != TPM2_ALG_SHA256) { 463 printf("Sandbox TPM only handle SHA256 algorithm\n"); 464 rc = TPM2_RC_VALUE; 465 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 466 } 467 468 pcr_array_sz = *sent; 469 sent += sizeof(pcr_array_sz); 470 if (!pcr_array_sz || pcr_array_sz > 8) { 471 printf("Sandbox TPM cannot handle so much PCRs\n"); 472 rc = TPM2_RC_VALUE; 473 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 474 } 475 476 for (i = 0; i < pcr_array_sz; i++) 477 pcr_map += (u64)sent[i] << (i * 8); 478 479 if (pcr_map >> SANDBOX_TPM_PCR_NB) { 480 printf("Sandbox TPM handles up to %d PCR(s)\n", 481 SANDBOX_TPM_PCR_NB); 482 rc = TPM2_RC_VALUE; 483 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 484 } 485 486 if (pcr_map >> SANDBOX_TPM_PCR_NB) { 487 printf("Wrong PCR map.\n"); 488 rc = TPM2_RC_VALUE; 489 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 490 } 491 492 for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) 493 if (pcr_map & BIT(i)) 494 pcr_index = i; 495 496 /* Write tag */ 497 put_unaligned_be16(tag, recv); 498 recv += sizeof(tag); 499 500 /* Ignore length for now */ 501 recv += sizeof(u32); 502 503 /* Write return code */ 504 put_unaligned_be32(rc, recv); 505 recv += sizeof(rc); 506 507 /* Number of extensions */ 508 put_unaligned_be32(tpm->pcr_extensions[pcr_index], recv); 509 recv += sizeof(u32); 510 511 /* Copy the PCR */ 512 memcpy(recv, tpm->pcr[pcr_index], TPM2_DIGEST_LEN); 513 recv += TPM2_DIGEST_LEN; 514 515 /* Add trailing \0 */ 516 *recv = '\0'; 517 518 /* Write response length */ 519 *recv_len = recv - recvbuf; 520 put_unaligned_be32(*recv_len, recvbuf + sizeof(tag)); 521 522 break; 523 524 case TPM2_CC_PCR_EXTEND: 525 /* Get the PCR index */ 526 pcr_index = get_unaligned_be32(sendbuf + sizeof(tag) + 527 sizeof(length) + 528 sizeof(command)); 529 if (pcr_index > SANDBOX_TPM_PCR_NB) { 530 printf("Sandbox TPM handles up to %d PCR(s)\n", 531 SANDBOX_TPM_PCR_NB); 532 rc = TPM2_RC_VALUE; 533 } 534 535 /* Check the number of hashes */ 536 pcr_nb = get_unaligned_be32(sent); 537 sent += sizeof(pcr_nb); 538 if (pcr_nb != 1) { 539 printf("Sandbox cannot handle more than one PCR\n"); 540 rc = TPM2_RC_VALUE; 541 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 542 } 543 544 /* Check the hash algorithm */ 545 alg = get_unaligned_be16(sent); 546 sent += sizeof(alg); 547 if (alg != TPM2_ALG_SHA256) { 548 printf("Sandbox TPM only handle SHA256 algorithm\n"); 549 rc = TPM2_RC_VALUE; 550 return sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 551 } 552 553 /* Extend the PCR */ 554 rc = sandbox_tpm2_extend(dev, pcr_index, sent); 555 556 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 557 break; 558 559 default: 560 printf("TPM2 command %02x unknown in Sandbox\n", command); 561 rc = TPM2_RC_COMMAND_CODE; 562 sandbox_tpm2_fill_buf(&recv, recv_len, tag, rc); 563 } 564 565 return 0; 566 } 567 568 static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size) 569 { 570 if (size < 15) 571 return -ENOSPC; 572 573 return snprintf(buf, size, "Sandbox TPM2.x"); 574 } 575 576 static int sandbox_tpm2_open(struct udevice *dev) 577 { 578 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 579 580 if (tpm->init_done) 581 return -EIO; 582 583 tpm->init_done = true; 584 585 return 0; 586 } 587 588 static int sandbox_tpm2_probe(struct udevice *dev) 589 { 590 struct sandbox_tpm2 *tpm = dev_get_priv(dev); 591 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); 592 593 /* Use the TPM v2 stack */ 594 priv->version = TPM_V2; 595 596 memset(tpm, 0, sizeof(*tpm)); 597 598 priv->pcr_count = 32; 599 priv->pcr_select_min = 2; 600 601 return 0; 602 } 603 604 static int sandbox_tpm2_close(struct udevice *dev) 605 { 606 return 0; 607 } 608 609 static const struct tpm_ops sandbox_tpm2_ops = { 610 .open = sandbox_tpm2_open, 611 .close = sandbox_tpm2_close, 612 .get_desc = sandbox_tpm2_get_desc, 613 .xfer = sandbox_tpm2_xfer, 614 }; 615 616 static const struct udevice_id sandbox_tpm2_ids[] = { 617 { .compatible = "sandbox,tpm2" }, 618 { } 619 }; 620 621 U_BOOT_DRIVER(sandbox_tpm2) = { 622 .name = "sandbox_tpm2", 623 .id = UCLASS_TPM, 624 .of_match = sandbox_tpm2_ids, 625 .ops = &sandbox_tpm2_ops, 626 .probe = sandbox_tpm2_probe, 627 .priv_auto_alloc_size = sizeof(struct sandbox_tpm2), 628 }; 629