uboot/cmd/tpm_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 */
   5
   6#include <common.h>
   7#include <command.h>
   8#include <environment.h>
   9#include <tpm.h>
  10
  11/* Prints error and returns on failure */
  12#define TPM_CHECK(tpm_command) do { \
  13        uint32_t result; \
  14        \
  15        result = (tpm_command); \
  16        if (result != TPM_SUCCESS) { \
  17                printf("TEST FAILED: line %d: " #tpm_command ": 0x%x\n", \
  18                        __LINE__, result); \
  19                return result; \
  20        } \
  21} while (0)
  22
  23#define INDEX0                  0xda70
  24#define INDEX1                  0xda71
  25#define INDEX2                  0xda72
  26#define INDEX3                  0xda73
  27#define INDEX_INITIALISED       0xda80
  28#define PHYS_PRESENCE           4
  29#define PRESENCE                8
  30
  31static uint32_t TlclStartupIfNeeded(void)
  32{
  33        uint32_t result = tpm_startup(TPM_ST_CLEAR);
  34
  35        return result == TPM_INVALID_POSTINIT ? TPM_SUCCESS : result;
  36}
  37
  38static int test_timer(void)
  39{
  40        printf("get_timer(0) = %lu\n", get_timer(0));
  41        return 0;
  42}
  43
  44static uint32_t tpm_get_flags(uint8_t *disable, uint8_t *deactivated,
  45                              uint8_t *nvlocked)
  46{
  47        struct tpm_permanent_flags pflags;
  48        uint32_t result;
  49
  50        result = tpm_get_permanent_flags(&pflags);
  51        if (result)
  52                return result;
  53        if (disable)
  54                *disable = pflags.disable;
  55        if (deactivated)
  56                *deactivated = pflags.deactivated;
  57        if (nvlocked)
  58                *nvlocked = pflags.nv_locked;
  59        debug("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n",
  60              pflags.disable, pflags.deactivated, pflags.nv_locked);
  61
  62        return 0;
  63}
  64
  65static uint32_t tpm_set_global_lock(void)
  66{
  67        uint32_t x;
  68
  69        debug("TPM: Set global lock\n");
  70        return tpm_nv_write_value(INDEX0, (uint8_t *)&x, 0);
  71}
  72
  73static uint32_t tpm_nv_write_value_lock(uint32_t index)
  74{
  75        debug("TPM: Write lock 0x%x\n", index);
  76
  77        return tpm_nv_write_value(index, NULL, 0);
  78}
  79
  80static uint32_t tpm_nv_set_locked(void)
  81{
  82        debug("TPM: Set NV locked\n");
  83
  84        return tpm_nv_define_space(TPM_NV_INDEX_LOCK, 0, 0);
  85}
  86
  87static int tpm_is_owned(void)
  88{
  89        uint8_t response[TPM_PUBEK_SIZE];
  90        uint32_t result;
  91
  92        result = tpm_read_pubek(response, sizeof(response));
  93
  94        return result != TPM_SUCCESS;
  95}
  96
  97static int test_early_extend(void)
  98{
  99        uint8_t value_in[20];
 100        uint8_t value_out[20];
 101
 102        printf("Testing earlyextend ...");
 103        tpm_init();
 104        TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
 105        TPM_CHECK(tpm_continue_self_test());
 106        TPM_CHECK(tpm_extend(1, value_in, value_out));
 107        printf("done\n");
 108        return 0;
 109}
 110
 111static int test_early_nvram(void)
 112{
 113        uint32_t x;
 114
 115        printf("Testing earlynvram ...");
 116        tpm_init();
 117        TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
 118        TPM_CHECK(tpm_continue_self_test());
 119        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 120        TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
 121        printf("done\n");
 122        return 0;
 123}
 124
 125static int test_early_nvram2(void)
 126{
 127        uint32_t x;
 128
 129        printf("Testing earlynvram2 ...");
 130        tpm_init();
 131        TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
 132        TPM_CHECK(tpm_continue_self_test());
 133        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 134        TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)));
 135        printf("done\n");
 136        return 0;
 137}
 138
 139static int test_enable(void)
 140{
 141        uint8_t disable = 0, deactivated = 0;
 142
 143        printf("Testing enable ...\n");
 144        tpm_init();
 145        TPM_CHECK(TlclStartupIfNeeded());
 146        TPM_CHECK(tpm_self_test_full());
 147        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 148        TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
 149        printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
 150        TPM_CHECK(tpm_physical_enable());
 151        TPM_CHECK(tpm_physical_set_deactivated(0));
 152        TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
 153        printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
 154        if (disable == 1 || deactivated == 1)
 155                printf("\tfailed to enable or activate\n");
 156        printf("\tdone\n");
 157        return 0;
 158}
 159
 160#define reboot() do { \
 161        printf("\trebooting...\n"); \
 162        reset_cpu(0); \
 163} while (0)
 164
 165static int test_fast_enable(void)
 166{
 167        uint8_t disable = 0, deactivated = 0;
 168        int i;
 169
 170        printf("Testing fastenable ...\n");
 171        tpm_init();
 172        TPM_CHECK(TlclStartupIfNeeded());
 173        TPM_CHECK(tpm_self_test_full());
 174        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 175        TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
 176        printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
 177        for (i = 0; i < 2; i++) {
 178                TPM_CHECK(tpm_force_clear());
 179                TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
 180                printf("\tdisable is %d, deactivated is %d\n", disable,
 181                       deactivated);
 182                assert(disable == 1 && deactivated == 1);
 183                TPM_CHECK(tpm_physical_enable());
 184                TPM_CHECK(tpm_physical_set_deactivated(0));
 185                TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
 186                printf("\tdisable is %d, deactivated is %d\n", disable,
 187                       deactivated);
 188                assert(disable == 0 && deactivated == 0);
 189        }
 190        printf("\tdone\n");
 191        return 0;
 192}
 193
 194static int test_global_lock(void)
 195{
 196        uint32_t zero = 0;
 197        uint32_t result;
 198        uint32_t x;
 199
 200        printf("Testing globallock ...\n");
 201        tpm_init();
 202        TPM_CHECK(TlclStartupIfNeeded());
 203        TPM_CHECK(tpm_self_test_full());
 204        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 205        TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
 206        TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&zero,
 207                                     sizeof(uint32_t)));
 208        TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
 209        TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&zero,
 210                                     sizeof(uint32_t)));
 211        TPM_CHECK(tpm_set_global_lock());
 212        /* Verifies that write to index0 fails */
 213        x = 1;
 214        result = tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x));
 215        assert(result == TPM_AREA_LOCKED);
 216        TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
 217        assert(x == 0);
 218        /* Verifies that write to index1 is still possible */
 219        x = 2;
 220        TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x)));
 221        TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
 222        assert(x == 2);
 223        /* Turns off PP */
 224        tpm_tsc_physical_presence(PHYS_PRESENCE);
 225        /* Verifies that write to index1 fails */
 226        x = 3;
 227        result = tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x));
 228        assert(result == TPM_BAD_PRESENCE);
 229        TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
 230        assert(x == 2);
 231        printf("\tdone\n");
 232        return 0;
 233}
 234
 235static int test_lock(void)
 236{
 237        printf("Testing lock ...\n");
 238        tpm_init();
 239        tpm_startup(TPM_ST_CLEAR);
 240        tpm_self_test_full();
 241        tpm_tsc_physical_presence(PRESENCE);
 242        tpm_nv_write_value_lock(INDEX0);
 243        printf("\tLocked 0x%x\n", INDEX0);
 244        printf("\tdone\n");
 245        return 0;
 246}
 247
 248static void initialise_spaces(void)
 249{
 250        uint32_t zero = 0;
 251        uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
 252
 253        printf("\tInitialising spaces\n");
 254        tpm_nv_set_locked();  /* useful only the first time */
 255        tpm_nv_define_space(INDEX0, perm, 4);
 256        tpm_nv_write_value(INDEX0, (uint8_t *)&zero, 4);
 257        tpm_nv_define_space(INDEX1, perm, 4);
 258        tpm_nv_write_value(INDEX1, (uint8_t *)&zero, 4);
 259        tpm_nv_define_space(INDEX2, perm, 4);
 260        tpm_nv_write_value(INDEX2, (uint8_t *)&zero, 4);
 261        tpm_nv_define_space(INDEX3, perm, 4);
 262        tpm_nv_write_value(INDEX3, (uint8_t *)&zero, 4);
 263        perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
 264                TPM_NV_PER_PPWRITE;
 265        tpm_nv_define_space(INDEX_INITIALISED, perm, 1);
 266}
 267
 268static int test_readonly(void)
 269{
 270        uint8_t c;
 271        uint32_t index_0, index_1, index_2, index_3;
 272        int read0, read1, read2, read3;
 273
 274        printf("Testing readonly ...\n");
 275        tpm_init();
 276        tpm_startup(TPM_ST_CLEAR);
 277        tpm_self_test_full();
 278        tpm_tsc_physical_presence(PRESENCE);
 279        /*
 280         * Checks if initialisation has completed by trying to read-lock a
 281         * space that's created at the end of initialisation
 282         */
 283        if (tpm_nv_read_value(INDEX_INITIALISED, &c, 0) == TPM_BADINDEX) {
 284                /* The initialisation did not complete */
 285                initialise_spaces();
 286        }
 287
 288        /* Checks if spaces are OK or messed up */
 289        read0 = tpm_nv_read_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0));
 290        read1 = tpm_nv_read_value(INDEX1, (uint8_t *)&index_1, sizeof(index_1));
 291        read2 = tpm_nv_read_value(INDEX2, (uint8_t *)&index_2, sizeof(index_2));
 292        read3 = tpm_nv_read_value(INDEX3, (uint8_t *)&index_3, sizeof(index_3));
 293        if (read0 || read1 || read2 || read3) {
 294                printf("Invalid contents\n");
 295                return 0;
 296        }
 297
 298        /*
 299         * Writes space, and locks it.  Then attempts to write again.
 300         * I really wish I could use the imperative.
 301         */
 302        index_0 += 1;
 303        if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0) !=
 304                TPM_SUCCESS)) {
 305                pr_err("\tcould not write index 0\n");
 306        }
 307        tpm_nv_write_value_lock(INDEX0);
 308        if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0)) ==
 309                        TPM_SUCCESS)
 310                pr_err("\tindex 0 is not locked\n");
 311
 312        printf("\tdone\n");
 313        return 0;
 314}
 315
 316static int test_redefine_unowned(void)
 317{
 318        uint32_t perm;
 319        uint32_t result;
 320        uint32_t x;
 321
 322        printf("Testing redefine_unowned ...");
 323        tpm_init();
 324        TPM_CHECK(TlclStartupIfNeeded());
 325        TPM_CHECK(tpm_self_test_full());
 326        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 327        assert(!tpm_is_owned());
 328
 329        /* Ensures spaces exist. */
 330        TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
 331        TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
 332
 333        /* Redefines spaces a couple of times. */
 334        perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK;
 335        TPM_CHECK(tpm_nv_define_space(INDEX0, perm, 2 * sizeof(uint32_t)));
 336        TPM_CHECK(tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t)));
 337        perm = TPM_NV_PER_PPWRITE;
 338        TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
 339        TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
 340
 341        /* Sets the global lock */
 342        tpm_set_global_lock();
 343
 344        /* Verifies that index0 cannot be redefined */
 345        result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
 346        assert(result == TPM_AREA_LOCKED);
 347
 348        /* Checks that index1 can */
 349        TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
 350        TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
 351
 352        /* Turns off PP */
 353        tpm_tsc_physical_presence(PHYS_PRESENCE);
 354
 355        /* Verifies that neither index0 nor index1 can be redefined */
 356        result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
 357        assert(result == TPM_BAD_PRESENCE);
 358        result = tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t));
 359        assert(result == TPM_BAD_PRESENCE);
 360
 361        printf("done\n");
 362        return 0;
 363}
 364
 365#define PERMPPGL (TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK)
 366#define PERMPP TPM_NV_PER_PPWRITE
 367
 368static int test_space_perm(void)
 369{
 370        uint32_t perm;
 371
 372        printf("Testing spaceperm ...");
 373        tpm_init();
 374        TPM_CHECK(TlclStartupIfNeeded());
 375        TPM_CHECK(tpm_continue_self_test());
 376        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 377        TPM_CHECK(tpm_get_permissions(INDEX0, &perm));
 378        assert((perm & PERMPPGL) == PERMPPGL);
 379        TPM_CHECK(tpm_get_permissions(INDEX1, &perm));
 380        assert((perm & PERMPP) == PERMPP);
 381        printf("done\n");
 382        return 0;
 383}
 384
 385static int test_startup(void)
 386{
 387        uint32_t result;
 388        printf("Testing startup ...\n");
 389
 390        tpm_init();
 391        result = tpm_startup(TPM_ST_CLEAR);
 392        if (result != 0 && result != TPM_INVALID_POSTINIT)
 393                printf("\ttpm startup failed with 0x%x\n", result);
 394        result = tpm_get_flags(NULL, NULL, NULL);
 395        if (result != 0)
 396                printf("\ttpm getflags failed with 0x%x\n", result);
 397        printf("\texecuting SelfTestFull\n");
 398        tpm_self_test_full();
 399        result = tpm_get_flags(NULL, NULL, NULL);
 400        if (result != 0)
 401                printf("\ttpm getflags failed with 0x%x\n", result);
 402        printf("\tdone\n");
 403        return 0;
 404}
 405
 406/*
 407 * Runs [op] and ensures it returns success and doesn't run longer than
 408 * [time_limit] in milliseconds.
 409 */
 410#define TTPM_CHECK(op, time_limit) do { \
 411        ulong start, time; \
 412        uint32_t __result; \
 413        \
 414        start = get_timer(0); \
 415        __result = op; \
 416        if (__result != TPM_SUCCESS) { \
 417                printf("\t" #op ": error 0x%x\n", __result); \
 418                return -1; \
 419        } \
 420        time = get_timer(start); \
 421        printf("\t" #op ": %lu ms\n", time); \
 422        if (time > (ulong)time_limit) { \
 423                printf("\t" #op " exceeded " #time_limit " ms\n"); \
 424        } \
 425} while (0)
 426
 427
 428static int test_timing(void)
 429{
 430        uint32_t x;
 431        uint8_t in[20], out[20];
 432
 433        printf("Testing timing ...");
 434        tpm_init();
 435        TTPM_CHECK(TlclStartupIfNeeded(), 50);
 436        TTPM_CHECK(tpm_continue_self_test(), 100);
 437        TTPM_CHECK(tpm_self_test_full(), 1000);
 438        TTPM_CHECK(tpm_tsc_physical_presence(PRESENCE), 100);
 439        TTPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
 440        TTPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
 441        TTPM_CHECK(tpm_extend(0, in, out), 200);
 442        TTPM_CHECK(tpm_set_global_lock(), 50);
 443        TTPM_CHECK(tpm_tsc_physical_presence(PHYS_PRESENCE), 100);
 444        printf("done\n");
 445        return 0;
 446}
 447
 448#define TPM_MAX_NV_WRITES_NOOWNER 64
 449
 450static int test_write_limit(void)
 451{
 452        printf("Testing writelimit ...\n");
 453        int i;
 454        uint32_t result;
 455
 456        tpm_init();
 457        TPM_CHECK(TlclStartupIfNeeded());
 458        TPM_CHECK(tpm_self_test_full());
 459        TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
 460        TPM_CHECK(tpm_force_clear());
 461        TPM_CHECK(tpm_physical_enable());
 462        TPM_CHECK(tpm_physical_set_deactivated(0));
 463
 464        for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) {
 465                printf("\twriting %d\n", i);
 466                result = tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i));
 467                switch (result) {
 468                case TPM_SUCCESS:
 469                        break;
 470                case TPM_MAXNVWRITES:
 471                        assert(i >= TPM_MAX_NV_WRITES_NOOWNER);
 472                default:
 473                        pr_err("\tunexpected error code %d (0x%x)\n",
 474                              result, result);
 475                }
 476        }
 477
 478        /* Reset write count */
 479        TPM_CHECK(tpm_force_clear());
 480        TPM_CHECK(tpm_physical_enable());
 481        TPM_CHECK(tpm_physical_set_deactivated(0));
 482
 483        /* Try writing again. */
 484        TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i)));
 485        printf("\tdone\n");
 486        return 0;
 487}
 488
 489#define VOIDTEST(XFUNC) \
 490        int do_test_##XFUNC(cmd_tbl_t *cmd_tbl, int flag, int argc, \
 491        char * const argv[]) \
 492        { \
 493                return test_##XFUNC(); \
 494        }
 495
 496#define VOIDENT(XNAME) \
 497        U_BOOT_CMD_MKENT(XNAME, 0, 1, do_test_##XNAME, "", ""),
 498
 499VOIDTEST(early_extend)
 500VOIDTEST(early_nvram)
 501VOIDTEST(early_nvram2)
 502VOIDTEST(enable)
 503VOIDTEST(fast_enable)
 504VOIDTEST(global_lock)
 505VOIDTEST(lock)
 506VOIDTEST(readonly)
 507VOIDTEST(redefine_unowned)
 508VOIDTEST(space_perm)
 509VOIDTEST(startup)
 510VOIDTEST(timing)
 511VOIDTEST(write_limit)
 512VOIDTEST(timer)
 513
 514static cmd_tbl_t cmd_cros_tpm_sub[] = {
 515        VOIDENT(early_extend)
 516        VOIDENT(early_nvram)
 517        VOIDENT(early_nvram2)
 518        VOIDENT(enable)
 519        VOIDENT(fast_enable)
 520        VOIDENT(global_lock)
 521        VOIDENT(lock)
 522        VOIDENT(readonly)
 523        VOIDENT(redefine_unowned)
 524        VOIDENT(space_perm)
 525        VOIDENT(startup)
 526        VOIDENT(timing)
 527        VOIDENT(write_limit)
 528        VOIDENT(timer)
 529};
 530
 531static int do_tpmtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 532{
 533        cmd_tbl_t *c;
 534        int i;
 535
 536        printf("argc = %d, argv = ", argc);
 537
 538        for (i = 0; i < argc; i++)
 539                printf(" %s", argv[i]);
 540
 541        printf("\n------\n");
 542
 543        argc--;
 544        argv++;
 545        c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub,
 546                         ARRAY_SIZE(cmd_cros_tpm_sub));
 547        return c ? c->cmd(cmdtp, flag, argc, argv) : cmd_usage(cmdtp);
 548}
 549
 550U_BOOT_CMD(tpmtest, 2, 1, do_tpmtest, "TPM tests",
 551        "\n\tearly_extend\n"
 552        "\tearly_nvram\n"
 553        "\tearly_nvram2\n"
 554        "\tenable\n"
 555        "\tfast_enable\n"
 556        "\tglobal_lock\n"
 557        "\tlock\n"
 558        "\treadonly\n"
 559        "\tredefine_unowned\n"
 560        "\tspace_perm\n"
 561        "\tstartup\n"
 562        "\ttiming\n"
 563        "\twrite_limit\n");
 564