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.
161 lines
6.2 KiB
161 lines
6.2 KiB
8 months ago
|
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);
|