273 lines
15 KiB
Diff
273 lines
15 KiB
Diff
From 9ffb6893d40f23d0a1fd59176270892c21b7bda3 Mon Sep 17 00:00:00 2001
|
|
From: Dan Streetman <ddstreet@ieee.org>
|
|
Date: Thu, 8 Dec 2022 17:56:11 -0500
|
|
Subject: [PATCH] tpm2: add tpm2_policy_pcr()
|
|
|
|
This adds functions to get the digest for a PolicyPCR operation. For building
|
|
a policy hash, this provides a function to calculate the hash; and for building
|
|
a policy hash to satisfy the authPolicy for an existing object, this provides a
|
|
function to perform PolicyPCR with an existing session.
|
|
|
|
(cherry picked from commit dcbc4674e3daea2d34d02de5a76d4a19bca7545f)
|
|
|
|
Related: RHEL-16182
|
|
---
|
|
src/shared/tpm2-util.c | 119 +++++++++++++++++++++++++++++++----------
|
|
src/shared/tpm2-util.h | 3 ++
|
|
src/test/test-tpm2.c | 48 +++++++++++++++++
|
|
3 files changed, 143 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
|
|
index a6fab45898..1aa49a7232 100644
|
|
--- a/src/shared/tpm2-util.c
|
|
+++ b/src/shared/tpm2-util.c
|
|
@@ -61,10 +61,12 @@ TSS2_RC (*sym_Esys_VerifySignature)(ESYS_CONTEXT *esysContext, ESYS_TR keyHandle
|
|
|
|
const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL;
|
|
|
|
+TSS2_RC (*sym_Tss2_MU_TPM2_CC_Marshal)(TPM2_CC src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal)(TPM2B_PRIVATE const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PRIVATE *dest) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest) = NULL;
|
|
+TSS2_RC (*sym_Tss2_MU_TPML_PCR_SELECTION_Marshal)(TPML_PCR_SELECTION const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPMT_HA_Marshal)(TPMT_HA const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
TSS2_RC (*sym_Tss2_MU_TPMT_PUBLIC_Marshal)(TPMT_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL;
|
|
|
|
@@ -113,10 +115,12 @@ int dlopen_tpm2(void) {
|
|
|
|
return dlopen_many_sym_or_warn(
|
|
&libtss2_mu_dl, "libtss2-mu.so.0", LOG_DEBUG,
|
|
+ DLSYM_ARG(Tss2_MU_TPM2_CC_Marshal),
|
|
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal),
|
|
DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal),
|
|
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal),
|
|
DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal),
|
|
+ DLSYM_ARG(Tss2_MU_TPML_PCR_SELECTION_Marshal),
|
|
DLSYM_ARG(Tss2_MU_TPMT_HA_Marshal),
|
|
DLSYM_ARG(Tss2_MU_TPMT_PUBLIC_Marshal));
|
|
}
|
|
@@ -1918,6 +1922,90 @@ static int tpm2_get_name(
|
|
return 0;
|
|
}
|
|
|
|
+/* Extend 'digest' with the PolicyPCR calculated hash. */
|
|
+int tpm2_calculate_policy_pcr(
|
|
+ const TPML_PCR_SELECTION *pcr_selection,
|
|
+ const TPM2B_DIGEST pcr_values[],
|
|
+ size_t n_pcr_values,
|
|
+ TPM2B_DIGEST *digest) {
|
|
+
|
|
+ TPM2_CC command = TPM2_CC_PolicyPCR;
|
|
+ TSS2_RC rc;
|
|
+ int r;
|
|
+
|
|
+ assert(pcr_selection);
|
|
+ assert(pcr_values || n_pcr_values == 0);
|
|
+ assert(digest);
|
|
+ assert(digest->size == SHA256_DIGEST_SIZE);
|
|
+
|
|
+ r = dlopen_tpm2();
|
|
+ if (r < 0)
|
|
+ return log_error_errno(r, "TPM2 support not installed: %m");
|
|
+
|
|
+ TPM2B_DIGEST hash = {};
|
|
+ r = tpm2_digest_many_digests(TPM2_ALG_SHA256, &hash, pcr_values, n_pcr_values, /* extend= */ false);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ _cleanup_free_ uint8_t *buf = NULL;
|
|
+ size_t size = 0, maxsize = sizeof(command) + sizeof(*pcr_selection);
|
|
+
|
|
+ buf = malloc(maxsize);
|
|
+ if (!buf)
|
|
+ return log_oom();
|
|
+
|
|
+ rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, maxsize, &size);
|
|
+ if (rc != TSS2_RC_SUCCESS)
|
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
+ "Failed to marshal PolicyPCR command: %s", sym_Tss2_RC_Decode(rc));
|
|
+
|
|
+ rc = sym_Tss2_MU_TPML_PCR_SELECTION_Marshal(pcr_selection, buf, maxsize, &size);
|
|
+ if (rc != TSS2_RC_SUCCESS)
|
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
+ "Failed to marshal PCR selection: %s", sym_Tss2_RC_Decode(rc));
|
|
+
|
|
+ struct iovec data[] = {
|
|
+ IOVEC_MAKE(buf, size),
|
|
+ IOVEC_MAKE(hash.buffer, hash.size),
|
|
+ };
|
|
+ r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+
|
|
+ tpm2_log_debug_digest(digest, "PolicyPCR calculated digest");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int tpm2_policy_pcr(
|
|
+ Tpm2Context *c,
|
|
+ const Tpm2Handle *session,
|
|
+ const TPML_PCR_SELECTION *pcr_selection,
|
|
+ TPM2B_DIGEST **ret_policy_digest) {
|
|
+
|
|
+ TSS2_RC rc;
|
|
+
|
|
+ assert(c);
|
|
+ assert(session);
|
|
+ assert(pcr_selection);
|
|
+
|
|
+ log_debug("Adding PCR hash policy.");
|
|
+
|
|
+ rc = sym_Esys_PolicyPCR(
|
|
+ c->esys_context,
|
|
+ session->esys_handle,
|
|
+ ESYS_TR_NONE,
|
|
+ ESYS_TR_NONE,
|
|
+ ESYS_TR_NONE,
|
|
+ NULL,
|
|
+ pcr_selection);
|
|
+ if (rc != TSS2_RC_SUCCESS)
|
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
+ "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
|
|
+
|
|
+ return tpm2_get_policy_digest(c, session, ret_policy_digest);
|
|
+}
|
|
+
|
|
static int tpm2_build_sealing_policy(
|
|
Tpm2Context *c,
|
|
const Tpm2Handle *session,
|
|
@@ -1993,21 +2081,8 @@ static int tpm2_build_sealing_policy(
|
|
/* Put together the PCR policy we want to use */
|
|
TPML_PCR_SELECTION pcr_selection;
|
|
tpm2_tpml_pcr_selection_from_mask(pubkey_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
|
|
- rc = sym_Esys_PolicyPCR(
|
|
- c->esys_context,
|
|
- session->esys_handle,
|
|
- ESYS_TR_NONE,
|
|
- ESYS_TR_NONE,
|
|
- ESYS_TR_NONE,
|
|
- NULL,
|
|
- &pcr_selection);
|
|
- if (rc != TSS2_RC_SUCCESS)
|
|
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
- "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
|
|
-
|
|
- /* Get the policy hash of the PCR policy */
|
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *approved_policy = NULL;
|
|
- r = tpm2_get_policy_digest(c, session, &approved_policy);
|
|
+ r = tpm2_policy_pcr(c, session, &pcr_selection, &approved_policy);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
@@ -2087,21 +2162,11 @@ static int tpm2_build_sealing_policy(
|
|
}
|
|
|
|
if (hash_pcr_mask != 0) {
|
|
- log_debug("Configuring hash-based PCR policy.");
|
|
-
|
|
TPML_PCR_SELECTION pcr_selection;
|
|
tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, (TPMI_ALG_HASH)pcr_bank, &pcr_selection);
|
|
- rc = sym_Esys_PolicyPCR(
|
|
- c->esys_context,
|
|
- session->esys_handle,
|
|
- ESYS_TR_NONE,
|
|
- ESYS_TR_NONE,
|
|
- ESYS_TR_NONE,
|
|
- NULL,
|
|
- &pcr_selection);
|
|
- if (rc != TSS2_RC_SUCCESS)
|
|
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
- "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
|
|
+ r = tpm2_policy_pcr(c, session, &pcr_selection, NULL);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
}
|
|
|
|
if (use_pin) {
|
|
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
|
|
index a23f383e5a..80c00af141 100644
|
|
--- a/src/shared/tpm2-util.h
|
|
+++ b/src/shared/tpm2-util.h
|
|
@@ -66,10 +66,12 @@ extern TSS2_RC (*sym_Esys_VerifySignature)(ESYS_CONTEXT *esysContext, ESYS_TR ke
|
|
|
|
extern const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc);
|
|
|
|
+extern TSS2_RC (*sym_Tss2_MU_TPM2_CC_Marshal)(TPM2_CC src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal)(TPM2B_PRIVATE const *src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PRIVATE *dest);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest);
|
|
+extern TSS2_RC (*sym_Tss2_MU_TPML_PCR_SELECTION_Marshal)(TPML_PCR_SELECTION const *src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPMT_HA_Marshal)(TPMT_HA const *src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
extern TSS2_RC (*sym_Tss2_MU_TPMT_PUBLIC_Marshal)(TPMT_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset);
|
|
|
|
@@ -88,6 +90,7 @@ static inline int tpm2_digest_init(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest) {
|
|
}
|
|
|
|
int tpm2_calculate_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name);
|
|
+int tpm2_calculate_policy_pcr(const TPML_PCR_SELECTION *pcr_selection, const TPM2B_DIGEST pcr_values[], size_t pcr_values_count, TPM2B_DIGEST *digest);
|
|
|
|
int tpm2_seal(const char *device, uint32_t hash_pcr_mask, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
|
|
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
|
|
diff --git a/src/test/test-tpm2.c b/src/test/test-tpm2.c
|
|
index 2515f79e57..c2e074b5f9 100644
|
|
--- a/src/test/test-tpm2.c
|
|
+++ b/src/test/test-tpm2.c
|
|
@@ -643,6 +643,54 @@ TEST(calculate_name) {
|
|
assert_se(streq(expect, h));
|
|
}
|
|
|
|
+TEST(calculate_policy_pcr) {
|
|
+ TPML_PCR_SELECTION pcr_selection;
|
|
+ TPM2B_DIGEST pcr_values[16];
|
|
+ TPM2B_DIGEST d;
|
|
+ uint32_t pcr_mask;
|
|
+
|
|
+ digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
|
+ pcr_mask = (1<<4) | (1<<7) | (1<<8);
|
|
+ tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
|
+ digest_init_sha256(&pcr_values[0], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
|
+ digest_init_sha256(&pcr_values[1], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
|
+ digest_init_sha256(&pcr_values[2], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
|
+ assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 3, &d) == 0);
|
|
+ assert_se(digest_check(&d, "76532a0e16f7e6bf6b02918c11f75d99d729fab0cc81d0df2c4284a2c4fe6e05"));
|
|
+
|
|
+ pcr_mask = (1<<4) | (1<<7) | (1<<8);
|
|
+ tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
|
+ digest_init_sha256(&pcr_values[0], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
|
+ digest_init_sha256(&pcr_values[1], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
|
+ digest_init_sha256(&pcr_values[2], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
|
+ assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 3, &d) == 0);
|
|
+ assert_se(digest_check(&d, "97e64bcabb64c1fa4b726528644926c8029f5b4458b0575c98c04fe225629a0b"));
|
|
+
|
|
+ digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
|
+ pcr_mask = 0xffff;
|
|
+ tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
|
+ digest_init_sha256(&pcr_values[ 0], "2124793cbbe60c3a8637d3b84a5d054e87c351e1469a285acc04755e8b204dec");
|
|
+ digest_init_sha256(&pcr_values[ 1], "bf7592f18adcfdc549fc0b94939f5069a24697f9cff4a0dca29014767b97559d");
|
|
+ digest_init_sha256(&pcr_values[ 2], "4b00cff9dee3a364979b2dc241b34568a8ad49fcf2713df259e47dff8875feed");
|
|
+ digest_init_sha256(&pcr_values[ 3], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
|
+ digest_init_sha256(&pcr_values[ 4], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
|
+ digest_init_sha256(&pcr_values[ 5], "c97c40369691c8e4aa78fb3a52655cd193b780a838b8e23f5f476576919db5e5");
|
|
+ digest_init_sha256(&pcr_values[ 6], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
|
+ digest_init_sha256(&pcr_values[ 7], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
|
+ digest_init_sha256(&pcr_values[ 8], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
|
+ digest_init_sha256(&pcr_values[ 9], "9c2bac22ef5ec84fcdb71c3ebf776cba1247e5da980e5ee08e45666a2edf0b8b");
|
|
+ digest_init_sha256(&pcr_values[10], "9885873f4d7348199ad286f8f2476d4f866940950f6f9fb9f945ed352dbdcbd2");
|
|
+ digest_init_sha256(&pcr_values[11], "42400ab950d21aa79d12cc4fdef67d1087a39ad64900619831c0974dbae54e44");
|
|
+ digest_init_sha256(&pcr_values[12], "767d064382e56ca1ad3bdcc6bc596112e6c2008b593d3570d24c2bfa64c4628c");
|
|
+ digest_init_sha256(&pcr_values[13], "30c16133175959408c9745d8dafadef5daf4b39cb2be04df0d60089bd46d3cc4");
|
|
+ digest_init_sha256(&pcr_values[14], "e3991b7ddd47be7e92726a832d6874c5349b52b789fa0db8b558c69fea29574e");
|
|
+ digest_init_sha256(&pcr_values[15], "852dae3ecb992bdeb13d6002fefeeffdd90feca8b378d56681ef2c885d0e5137");
|
|
+ assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 16, &d) == 0);
|
|
+ assert_se(digest_check(&d, "22be4f1674f792d6345cea9427701068f0e8d9f42755dcc0e927e545a68f9c13"));
|
|
+ assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 16, &d) == 0);
|
|
+ assert_se(digest_check(&d, "7481fd1b116078eb3ac2456e4ad542c9b46b9b8eb891335771ca8e7c8f8e4415"));
|
|
+}
|
|
+
|
|
#endif /* HAVE_TPM2 */
|
|
|
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|