From bbaf58dd3fc34556d552689f3f1b6c94860b3ffe Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 3 Oct 2023 10:25:19 -0400 Subject: [PATCH] tpm2: update test-tpm2 for tpm2_calculate_seal() Add testing for tpm2_calculate_seal(). (cherry picked from commit 65883f6c1060249c3cd2de34398a787be149138c) Related: RHEL-16182 --- src/shared/tpm2-util.c | 7 ++-- src/shared/tpm2-util.h | 2 + src/test/test-tpm2.c | 89 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index e5fc8a72a7..e334564159 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -3889,7 +3889,7 @@ int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *r * objects are required, while the seed is optional. This is not a (publicly) standard format, this is * specific to how we currently store the sealed object. This 'blob' can be unmarshalled by * tpm2_unmarshal_blob(). */ -static int tpm2_marshal_blob( +int tpm2_marshal_blob( const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, const TPM2B_ENCRYPTED_SECRET *seed, @@ -3939,7 +3939,7 @@ static int tpm2_marshal_blob( * in the 'blob', while the seed is optional. This is not a (publicly) standard format, this is specific to * how we currently store the sealed object. This expects the 'blob' to have been created by * tpm2_marshal_blob(). */ -static int tpm2_unmarshal_blob( +int tpm2_unmarshal_blob( const void *blob, size_t blob_size, TPM2B_PUBLIC *ret_public, @@ -4197,7 +4197,8 @@ static int tpm2_kdfe( void *end = mempcpy(mempcpy(stpcpy(info, label) + 1, context_u, context_u_size), context_v, context_v_size); /* assert we copied exactly the right amount that we allocated */ - assert(end > info && (uintptr_t) end - (uintptr_t) info == info_len); + /* Use assert_se() here to avoid emitting warning with -DNDEBUG */ + assert_se(end > info && (uintptr_t) end - (uintptr_t) info == info_len); _cleanup_free_ void *buf = NULL; r = kdf_ss_derive( diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index 1b84783660..34d4610383 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -118,6 +118,8 @@ int tpm2_tpml_pcr_selection_from_pcr_values(const Tpm2PCRValue *pcr_values, size int tpm2_create_primary(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_PUBLIC *template, const TPM2B_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, Tpm2Handle **ret_handle); int tpm2_create(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private); int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private, Tpm2Handle **ret_handle); +int tpm2_marshal_blob(const TPM2B_PUBLIC *public, const TPM2B_PRIVATE *private, const TPM2B_ENCRYPTED_SECRET *seed, void **ret_blob, size_t *ret_blob_size); +int tpm2_unmarshal_blob(const void *blob, size_t blob_size, TPM2B_PUBLIC *ret_public, TPM2B_PRIVATE *ret_private, TPM2B_ENCRYPTED_SECRET *ret_seed); bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg); bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command); diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c index ede08a39aa..44f8340451 100644 --- a/src/test/test-tpm2.c +++ b/src/test/test-tpm2.c @@ -1078,6 +1078,88 @@ static void check_get_or_create_srk(Tpm2Context *c) { assert_se(memcmp_nn(qname->name, qname->size, qname2->name, qname2->size) == 0); } +#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3 +static void calculate_seal_and_unseal( + Tpm2Context *c, + TPM2_HANDLE parent_index, + const TPM2B_PUBLIC *parent_public) { + + _cleanup_free_ char *secret_string = NULL; + assert_se(asprintf(&secret_string, "The classified documents are in room %x", parent_index) > 0); + size_t secret_size = strlen(secret_string) + 1; + + _cleanup_free_ void *blob = NULL; + size_t blob_size = 0; + _cleanup_free_ void *serialized_parent = NULL; + size_t serialized_parent_size; + assert_se(tpm2_calculate_seal( + parent_index, + parent_public, + /* attributes= */ NULL, + secret_string, secret_size, + /* policy= */ NULL, + /* pin= */ NULL, + /* ret_secret= */ NULL, /* ret_secret_size= */ 0, + &blob, &blob_size, + &serialized_parent, &serialized_parent_size) >= 0); + + _cleanup_free_ void *unsealed_secret = NULL; + size_t unsealed_secret_size; + assert_se(tpm2_unseal( + c, + /* hash_pcr_mask= */ 0, + /* pcr_bank= */ 0, + /* pubkey= */ NULL, /* pubkey_size= */ 0, + /* pubkey_pcr_mask= */ 0, + /* signature= */ NULL, + /* pin= */ NULL, + /* primary_alg= */ 0, + blob, blob_size, + /* known_policy_hash= */ NULL, /* known_policy_hash_size= */ 0, + serialized_parent, serialized_parent_size, + &unsealed_secret, &unsealed_secret_size) >= 0); + + assert_se(memcmp_nn(secret_string, secret_size, unsealed_secret, unsealed_secret_size) == 0); + + char unsealed_string[unsealed_secret_size]; + assert_se(snprintf(unsealed_string, unsealed_secret_size, "%s", (char*) unsealed_secret) == (int) unsealed_secret_size - 1); + log_debug("Unsealed secret is: %s", unsealed_string); +} + +static int check_calculate_seal(Tpm2Context *c) { + assert(c); + int r; + + _cleanup_free_ TPM2B_PUBLIC *srk_public = NULL; + assert_se(tpm2_get_srk(c, NULL, &srk_public, NULL, NULL, NULL) >= 0); + calculate_seal_and_unseal(c, TPM2_SRK_HANDLE, srk_public); + + TPMI_ALG_ASYM test_algs[] = { TPM2_ALG_RSA, TPM2_ALG_ECC, }; + for (unsigned i = 0; i < ELEMENTSOF(test_algs); i++) { + TPMI_ALG_ASYM alg = test_algs[i]; + + TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), }; + assert_se(tpm2_get_srk_template(alg, &template.publicArea) >= 0); + + _cleanup_free_ TPM2B_PUBLIC *public = NULL; + _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL; + assert_se(tpm2_create_primary(c, NULL, &template, NULL, &public, &handle) >= 0); + + /* Once our minimum libtss2-esys version is 2.4.0 or later, this can assume + * tpm2_index_from_handle() should always work. */ + TPM2_HANDLE index; + r = tpm2_index_from_handle(c, handle, &index); + if (r == -EOPNOTSUPP) + return log_tests_skipped("libtss2-esys version too old to support tpm2_index_from_handle()"); + assert_se(r >= 0); + + calculate_seal_and_unseal(c, index, public); + } + + return 0; +} +#endif /* HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3 */ + static void check_seal_unseal_for_handle(Tpm2Context *c, TPM2_HANDLE handle) { TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE); @@ -1151,6 +1233,7 @@ static void check_seal_unseal(Tpm2Context *c) { TEST_RET(tests_which_require_tpm) { _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL; + int r = 0; if (tpm2_context_new(NULL, &c) < 0) return log_tests_skipped("Could not find TPM"); @@ -1162,7 +1245,11 @@ TEST_RET(tests_which_require_tpm) { check_get_or_create_srk(c); check_seal_unseal(c); - return 0; +#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3 /* calculating sealed object requires openssl >= 3 */ + r = check_calculate_seal(c); +#endif + + return r; } #endif /* HAVE_TPM2 */