You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
systemd/SOURCES/0613-tpm2-add-tpm2_serializ...

161 lines
6.2 KiB

From ea5fd9eabda73184a151d93520ed0ded9283b778 Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
Date: Fri, 30 Jun 2023 13:42:25 -0400
Subject: [PATCH] tpm2: add tpm2_serialize() and tpm2_deserialize()
Add functions to perform serialization and deserialization of ESYS_TR objects.
(cherry picked from commit 1eff4242958ca355e2cee459a7436450900b7941)
Related: RHEL-16182
---
src/shared/tpm2-util.c | 101 ++++++++++++++++++++++++++++-------------
1 file changed, 70 insertions(+), 31 deletions(-)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index afa3db9c07..131356538e 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -3761,6 +3761,65 @@ int tpm2_unmarshal_blob(
return 0;
}
+/* Serialize a handle. This produces a binary object that can be later deserialized (by the same TPM), even
+ * across restarts of the TPM or reboots (assuming the handle is persistent). */
+static int tpm2_serialize(
+ Tpm2Context *c,
+ const Tpm2Handle *handle,
+ void **ret_serialized,
+ size_t *ret_serialized_size) {
+
+ TSS2_RC rc;
+
+ assert(c);
+ assert(handle);
+ assert(ret_serialized);
+ assert(ret_serialized_size);
+
+ _cleanup_(Esys_Freep) unsigned char *serialized = NULL;
+ size_t size = 0;
+ rc = sym_Esys_TR_Serialize(c->esys_context, handle->esys_handle, &serialized, &size);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to serialize: %s", sym_Tss2_RC_Decode(rc));
+
+ *ret_serialized = TAKE_PTR(serialized);
+ *ret_serialized_size = size;
+
+ return 0;
+}
+
+static int tpm2_deserialize(
+ Tpm2Context *c,
+ const void *serialized,
+ size_t serialized_size,
+ Tpm2Handle **ret_handle) {
+
+ TSS2_RC rc;
+ int r;
+
+ assert(c);
+ assert(serialized);
+ assert(ret_handle);
+
+ _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+ r = tpm2_handle_new(c, &handle);
+ if (r < 0)
+ return r;
+
+ /* Since this is an existing handle in the TPM we should not implicitly flush it. */
+ handle->flush = false;
+
+ rc = sym_Esys_TR_Deserialize(c->esys_context, serialized, serialized_size, &handle->esys_handle);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to deserialize: %s", sym_Tss2_RC_Decode(rc));
+
+ *ret_handle = TAKE_PTR(handle);
+
+ return 0;
+}
+
int tpm2_seal(Tpm2Context *c,
const TPM2B_DIGEST *policy,
const char *pin,
@@ -3773,7 +3832,6 @@ int tpm2_seal(Tpm2Context *c,
size_t *ret_srk_buf_size) {
uint16_t primary_alg = 0;
- TSS2_RC rc;
int r;
assert(ret_secret);
@@ -3903,34 +3961,27 @@ int tpm2_seal(Tpm2Context *c,
if (r < 0)
return log_error_errno(r, "Could not create sealed blob: %m");
- /* serialize the key for storage in the LUKS header. A deserialized ESYS_TR provides both
- * the raw TPM handle as well as the object name. The object name is used to verify that
- * the key we use later is the key we expect to establish the session with.
- */
- _cleanup_(Esys_Freep) uint8_t *srk_buf = NULL;
- size_t srk_buf_size = 0;
- if (ret_srk_buf) {
- log_debug("Serializing SRK ESYS_TR reference");
- rc = sym_Esys_TR_Serialize(c->esys_context, primary_handle->esys_handle, &srk_buf, &srk_buf_size);
- if (rc != TSS2_RC_SUCCESS)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to serialize primary key: %s", sym_Tss2_RC_Decode(rc));
- }
-
if (DEBUG_LOGGING)
log_debug("Completed TPM2 key sealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
+ _cleanup_free_ void *srk_buf = NULL;
+ size_t srk_buf_size = 0;
if (ret_srk_buf) {
+ _cleanup_(Esys_Freep) void *tmp = NULL;
+ r = tpm2_serialize(c, primary_handle, &tmp, &srk_buf_size);
+ if (r < 0)
+ return r;
+
/*
* make a copy since we don't want the caller to understand that
* ESYS allocated the pointer. It would make tracking what deallocator
* to use for srk_buf in which context a PITA.
*/
- void *tmp = memdup(srk_buf, srk_buf_size);
- if (!tmp)
+ srk_buf = memdup(tmp, srk_buf_size);
+ if (!srk_buf)
return log_oom();
- *ret_srk_buf = TAKE_PTR(tmp);
+ *ret_srk_buf = TAKE_PTR(srk_buf);
*ret_srk_buf_size = srk_buf_size;
}
@@ -4005,21 +4056,9 @@ int tpm2_unseal(const char *device,
_cleanup_(tpm2_handle_freep) Tpm2Handle *primary_handle = NULL;
if (srk_buf) {
- r = tpm2_handle_new(c, &primary_handle);
+ r = tpm2_deserialize(c, srk_buf, srk_buf_size, &primary_handle);
if (r < 0)
return r;
-
- primary_handle->flush = false;
-
- log_debug("Found existing SRK key to use, deserializing ESYS_TR");
- rc = sym_Esys_TR_Deserialize(
- c->esys_context,
- srk_buf,
- srk_buf_size,
- &primary_handle->esys_handle);
- if (rc != TSS2_RC_SUCCESS)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to deserialize primary key: %s", sym_Tss2_RC_Decode(rc));
} else if (primary_alg != 0) {
TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
r = tpm2_get_legacy_template(primary_alg, &template.publicArea);