systemd/0511-test-test-tpm2-add-tes...

364 lines
16 KiB
Diff

From cfaacedcf9e263f8291f13f2dde187a46e8a3f31 Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
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);