From cfaacedcf9e263f8291f13f2dde187a46e8a3f31 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 28 Feb 2023 17:16:43 -0500 Subject: [PATCH] test/test-tpm2: add tests for pcr selection functions (cherry picked from commit e067a49fd1180ff1104b3978c92d11784c67800f) Related: RHEL-16182 --- src/test/test-tpm2.c | 342 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c index 23277449b5..20baa0f261 100644 --- a/src/test/test-tpm2.c +++ b/src/test/test-tpm2.c @@ -69,4 +69,346 @@ TEST(tpm2_util_pbkdf2_hmac_sha256) { } } +#if HAVE_TPM2 + +#define POISON(type) \ + ({ \ + type _p; \ + memset(&_p, 0xaa, sizeof(_p)); \ + _p; \ + }) +#define POISON_TPML POISON(TPML_PCR_SELECTION) +#define POISON_TPMS POISON(TPMS_PCR_SELECTION) +#define POISON_U32 POISON(uint32_t) + +static void assert_tpms_pcr_selection_eq(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b) { + assert_se(a); + assert_se(b); + + assert_se(a->hash == b->hash); + assert_se(a->sizeofSelect == b->sizeofSelect); + + for (size_t i = 0; i < a->sizeofSelect; i++) + assert_se(a->pcrSelect[i] == b->pcrSelect[i]); +} + +static void assert_tpml_pcr_selection_eq(TPML_PCR_SELECTION *a, TPML_PCR_SELECTION *b) { + assert_se(a); + assert_se(b); + + assert_se(a->count == b->count); + for (size_t i = 0; i < a->count; i++) + assert_tpms_pcr_selection_eq(&a->pcrSelections[i], &b->pcrSelections[i]); +} + +static void verify_tpms_pcr_selection(TPMS_PCR_SELECTION *s, uint32_t mask, TPMI_ALG_HASH hash) { + assert_se(s->hash == hash); + assert_se(s->sizeofSelect == 3); + assert_se(s->pcrSelect[0] == (mask & 0xff)); + assert_se(s->pcrSelect[1] == ((mask >> 8) & 0xff)); + assert_se(s->pcrSelect[2] == ((mask >> 16) & 0xff)); + assert_se(s->pcrSelect[3] == 0); + + uint32_t m = POISON_U32; + tpm2_tpms_pcr_selection_to_mask(s, &m); + assert_se(m == mask); +} + +static void verify_tpml_pcr_selection(TPML_PCR_SELECTION *l, TPMS_PCR_SELECTION s[], size_t count) { + assert_se(l->count == count); + for (size_t i = 0; i < count; i++) { + assert_tpms_pcr_selection_eq(&s[i], &l->pcrSelections[i]); + + uint32_t mask = POISON_U32; + TPMI_ALG_HASH hash = l->pcrSelections[i].hash; + assert_se(tpm2_tpml_pcr_selection_to_mask(l, hash, &mask) == 0); + verify_tpms_pcr_selection(&l->pcrSelections[i], mask, hash); + } +} + +static void _test_pcr_selection_mask_hash(uint32_t mask, TPMI_ALG_HASH hash) { + TPMS_PCR_SELECTION s = POISON_TPMS; + tpm2_tpms_pcr_selection_from_mask(mask, hash, &s); + verify_tpms_pcr_selection(&s, mask, hash); + + TPML_PCR_SELECTION l = POISON_TPML; + tpm2_tpml_pcr_selection_from_mask(mask, hash, &l); + verify_tpml_pcr_selection(&l, &s, 1); + verify_tpms_pcr_selection(&l.pcrSelections[0], mask, hash); + + uint32_t test_masks[] = { + 0x0, 0x1, 0x100, 0x10000, 0xf0f0f0, 0xaaaaaa, 0xffffff, + }; + for (unsigned i = 0; i < ELEMENTSOF(test_masks); i++) { + uint32_t test_mask = test_masks[i]; + + TPMS_PCR_SELECTION a = POISON_TPMS, b = POISON_TPMS, test_s = POISON_TPMS; + tpm2_tpms_pcr_selection_from_mask(test_mask, hash, &test_s); + + a = s; + b = test_s; + tpm2_tpms_pcr_selection_add(&a, &b); + verify_tpms_pcr_selection(&a, UPDATE_FLAG(mask, test_mask, true), hash); + verify_tpms_pcr_selection(&b, test_mask, hash); + + a = s; + b = test_s; + tpm2_tpms_pcr_selection_sub(&a, &b); + verify_tpms_pcr_selection(&a, UPDATE_FLAG(mask, test_mask, false), hash); + verify_tpms_pcr_selection(&b, test_mask, hash); + + a = s; + b = test_s; + tpm2_tpms_pcr_selection_move(&a, &b); + verify_tpms_pcr_selection(&a, UPDATE_FLAG(mask, test_mask, true), hash); + verify_tpms_pcr_selection(&b, 0, hash); + } +} + +TEST(tpms_pcr_selection_mask_and_hash) { + TPMI_ALG_HASH HASH_ALGS[] = { TPM2_ALG_SHA1, TPM2_ALG_SHA256, }; + + for (unsigned i = 0; i < ELEMENTSOF(HASH_ALGS); i++) + for (uint32_t m2 = 0; m2 <= 0xffffff; m2 += 0x30000) + for (uint32_t m1 = 0; m1 <= 0xffff; m1 += 0x300) + for (uint32_t m0 = 0; m0 <= 0xff; m0 += 0x3) + _test_pcr_selection_mask_hash(m0 | m1 | m2, HASH_ALGS[i]); +} + +static void _test_tpms_sw( + TPMI_ALG_HASH hash, + uint32_t mask, + const char *expected_str, + size_t expected_weight) { + + TPMS_PCR_SELECTION s = POISON_TPMS; + tpm2_tpms_pcr_selection_from_mask(mask, hash, &s); + + _cleanup_free_ char *tpms_str = tpm2_tpms_pcr_selection_to_string(&s); + assert_se(streq(tpms_str, expected_str)); + + assert_se(tpm2_tpms_pcr_selection_weight(&s) == expected_weight); + assert_se(tpm2_tpms_pcr_selection_is_empty(&s) == (expected_weight == 0)); +} + +TEST(tpms_pcr_selection_string_and_weight) { + TPMI_ALG_HASH sha1 = TPM2_ALG_SHA1, sha256 = TPM2_ALG_SHA256; + + _test_tpms_sw(sha1, 0, "sha1()", 0); + _test_tpms_sw(sha1, 1, "sha1(0)", 1); + _test_tpms_sw(sha1, 0xf, "sha1(0+1+2+3)", 4); + _test_tpms_sw(sha1, 0x00ff00, "sha1(8+9+10+11+12+13+14+15)", 8); + _test_tpms_sw(sha1, 0xffffff, "sha1(0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23)", 24); + _test_tpms_sw(sha256, 0, "sha256()", 0); + _test_tpms_sw(sha256, 1, "sha256(0)", 1); + _test_tpms_sw(sha256, 7, "sha256(0+1+2)", 3); + _test_tpms_sw(sha256, 0xf00000, "sha256(20+21+22+23)", 4); + _test_tpms_sw(sha256, 0xffffff, "sha256(0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23)", 24); +} + +static void _tpml_pcr_selection_add_tpms(TPMS_PCR_SELECTION s[], size_t count, TPML_PCR_SELECTION *ret) { + for (size_t i = 0; i < count; i++) + tpm2_tpml_pcr_selection_add_tpms_pcr_selection(ret, &s[i]); +} + +static void _tpml_pcr_selection_sub_tpms(TPMS_PCR_SELECTION s[], size_t count, TPML_PCR_SELECTION *ret) { + for (size_t i = 0; i < count; i++) + tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(ret, &s[i]); +} + +static void _test_tpml_sw( + TPMS_PCR_SELECTION s[], + size_t count, + size_t expected_count, + const char *expected_str, + size_t expected_weight) { + + TPML_PCR_SELECTION l = {}; + _tpml_pcr_selection_add_tpms(s, count, &l); + assert_se(l.count == expected_count); + + _cleanup_free_ char *tpml_str = tpm2_tpml_pcr_selection_to_string(&l); + assert_se(streq(tpml_str, expected_str)); + + assert_se(tpm2_tpml_pcr_selection_weight(&l) == expected_weight); + assert_se(tpm2_tpml_pcr_selection_is_empty(&l) == (expected_weight == 0)); +} + +TEST(tpml_pcr_selection_string_and_weight) { + size_t size = 0xaa; + TPMI_ALG_HASH sha1 = TPM2_ALG_SHA1, + sha256 = TPM2_ALG_SHA256, + sha384 = TPM2_ALG_SHA384, + sha512 = TPM2_ALG_SHA512; + TPMS_PCR_SELECTION s[4] = { POISON_TPMS, POISON_TPMS, POISON_TPMS, POISON_TPMS, }; + + size = 0; + tpm2_tpms_pcr_selection_from_mask(0x000002, sha1 , &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x0080f0, sha384, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x010100, sha512, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0xff0000, sha256, &s[size++]); + _test_tpml_sw(s, + size, + /* expected_count= */ 4, + "[sha1(1),sha384(4+5+6+7+15),sha512(8+16),sha256(16+17+18+19+20+21+22+23)]", + /* expected_weight= */ 16); + + size = 0; + tpm2_tpms_pcr_selection_from_mask(0x0403aa, sha512, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x0080f0, sha256, &s[size++]); + _test_tpml_sw(s, + size, + /* expected_count= */ 2, + "[sha512(1+3+5+7+8+9+18),sha256(4+5+6+7+15)]", + /* expected_weight= */ 12); + + size = 0; + /* Empty hashes should be ignored */ + tpm2_tpms_pcr_selection_from_mask(0x0300ce, sha384, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0xffffff, sha512, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x000000, sha1 , &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x330010, sha256, &s[size++]); + _test_tpml_sw(s, + size, + /* expected_count= */ 3, + "[sha384(1+2+3+6+7+16+17),sha512(0+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23),sha256(4+16+17+20+21)]", + /* expected_weight= */ 36); + + size = 0; + /* Verify same-hash entries are properly combined. */ + tpm2_tpms_pcr_selection_from_mask(0x000001, sha1 , &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x000001, sha256, &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x000010, sha1 , &s[size++]); + tpm2_tpms_pcr_selection_from_mask(0x000010, sha256, &s[size++]); + _test_tpml_sw(s, + size, + /* expected_count= */ 2, + "[sha1(0+4),sha256(0+4)]", + /* expected_weight= */ 4); +} + +/* Test tpml add/sub by changing the tpms individually */ +static void _test_tpml_addsub_tpms( + TPML_PCR_SELECTION *start, + TPMS_PCR_SELECTION add[], + size_t add_count, + TPMS_PCR_SELECTION expected1[], + size_t expected1_count, + TPMS_PCR_SELECTION sub[], + size_t sub_count, + TPMS_PCR_SELECTION expected2[], + size_t expected2_count) { + + TPML_PCR_SELECTION l = *start; + + _tpml_pcr_selection_add_tpms(add, add_count, &l); + verify_tpml_pcr_selection(&l, expected1, expected1_count); + + _tpml_pcr_selection_sub_tpms(sub, sub_count, &l); + verify_tpml_pcr_selection(&l, expected2, expected2_count); +} + +/* Test tpml add/sub by creating new tpmls */ +static void _test_tpml_addsub_tpml( + TPML_PCR_SELECTION *start, + TPMS_PCR_SELECTION add[], + size_t add_count, + TPMS_PCR_SELECTION expected1[], + size_t expected1_count, + TPMS_PCR_SELECTION sub[], + size_t sub_count, + TPMS_PCR_SELECTION expected2[], + size_t expected2_count) { + + TPML_PCR_SELECTION l = {}; + tpm2_tpml_pcr_selection_add(&l, start); + assert_tpml_pcr_selection_eq(&l, start); + + TPML_PCR_SELECTION addl = {}; + _tpml_pcr_selection_add_tpms(add, add_count, &addl); + tpm2_tpml_pcr_selection_add(&l, &addl); + + TPML_PCR_SELECTION e1 = {}; + _tpml_pcr_selection_add_tpms(expected1, expected1_count, &e1); + assert_tpml_pcr_selection_eq(&l, &e1); + + TPML_PCR_SELECTION subl = {}; + _tpml_pcr_selection_add_tpms(sub, sub_count, &subl); + tpm2_tpml_pcr_selection_sub(&l, &subl); + + TPML_PCR_SELECTION e2 = {}; + _tpml_pcr_selection_add_tpms(expected2, expected2_count, &e2); + assert_tpml_pcr_selection_eq(&l, &e2); +} + +#define _test_tpml_addsub(...) \ + ({ \ + _test_tpml_addsub_tpms(__VA_ARGS__); \ + _test_tpml_addsub_tpml(__VA_ARGS__); \ + }) + +TEST(tpml_pcr_selection_add_sub) { + size_t add_count = 0xaa, expected1_count = 0xaa, sub_count = 0xaa, expected2_count = 0xaa; + TPMI_ALG_HASH sha1 = TPM2_ALG_SHA1, + sha256 = TPM2_ALG_SHA256, + sha384 = TPM2_ALG_SHA384, + sha512 = TPM2_ALG_SHA512; + TPML_PCR_SELECTION l = POISON_TPML; + TPMS_PCR_SELECTION add[4] = { POISON_TPMS, POISON_TPMS, POISON_TPMS, POISON_TPMS, }, + sub[4] = { POISON_TPMS, POISON_TPMS, POISON_TPMS, POISON_TPMS, }, + expected1[4] = { POISON_TPMS, POISON_TPMS, POISON_TPMS, POISON_TPMS, }, + expected2[4] = { POISON_TPMS, POISON_TPMS, POISON_TPMS, POISON_TPMS, }; + + l = (TPML_PCR_SELECTION){}; + add_count = 0; + expected1_count = 0; + sub_count = 0; + expected2_count = 0; + tpm2_tpms_pcr_selection_from_mask(0x010101, sha256, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0x101010, sha256, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0x111111, sha256, &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0x000001, sha256, &sub[sub_count++]); + tpm2_tpms_pcr_selection_from_mask(0xff0000, sha512, &sub[sub_count++]); + tpm2_tpms_pcr_selection_from_mask(0x111110, sha256, &expected2[expected2_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &expected2[expected2_count++]); + _test_tpml_addsub(&l, + add, add_count, + expected1, expected1_count, + sub, sub_count, + expected2, expected2_count); + + l = (TPML_PCR_SELECTION){ + .count = 1, + .pcrSelections[0].hash = sha1, + .pcrSelections[0].sizeofSelect = 3, + .pcrSelections[0].pcrSelect[0] = 0xf0, + }; + add_count = 0; + expected1_count = 0; + sub_count = 0; + expected2_count = 0; + tpm2_tpms_pcr_selection_from_mask(0xff0000, sha256, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0xffff00, sha384, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0xf00000, sha1 , &add[add_count++]); + tpm2_tpms_pcr_selection_from_mask(0xf000f0, sha1 , &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0xff0000, sha256, &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0xffff00, sha384, &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &expected1[expected1_count++]); + tpm2_tpms_pcr_selection_from_mask(0x00ffff, sha256, &sub[sub_count++]); + tpm2_tpms_pcr_selection_from_mask(0xf000f0, sha1 , &expected2[expected2_count++]); + tpm2_tpms_pcr_selection_from_mask(0xff0000, sha256, &expected2[expected2_count++]); + tpm2_tpms_pcr_selection_from_mask(0xffff00, sha384, &expected2[expected2_count++]); + tpm2_tpms_pcr_selection_from_mask(0x0000ff, sha512, &expected2[expected2_count++]); + _test_tpml_addsub(&l, + add, add_count, + expected1, expected1_count, + sub, sub_count, + expected2, expected2_count); +} + +#endif /* HAVE_TPM2 */ + DEFINE_TEST_MAIN(LOG_DEBUG);