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