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