systemd/0542-tpm2-add-tpm2_create.p...

194 lines
7.9 KiB
Diff

From 4d7527b3da486e260cb6fa94a03d9d3e58584ab8 Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
Date: Mon, 12 Dec 2022 09:46:04 -0500
Subject: [PATCH] tpm2: add tpm2_create()
This allows creating a new object (e.g. sealed secret) or key using the TPM.
Note that the new object/key is not loaded in the TPM after creation.
(cherry picked from commit e3f1f210761de31d262cb701335f4da194ca4ec7)
Related: RHEL-16182
---
src/shared/tpm2-util.c | 125 ++++++++++++++++++++++++++++-------------
1 file changed, 86 insertions(+), 39 deletions(-)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index f7940bcf2e..4759430cb2 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -1484,6 +1484,75 @@ static int tpm2_get_policy_digest(
return 0;
}
+static 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) {
+
+ usec_t ts;
+ TSS2_RC rc;
+
+ assert(c);
+ assert(template);
+
+ log_debug("Creating object on TPM.");
+
+ ts = now(CLOCK_MONOTONIC);
+
+ TPM2B_PUBLIC tpm2b_public = {
+ .size = sizeof(*template) - sizeof(template->unique),
+ .publicArea = *template,
+ };
+
+ /* Zero the unique area. */
+ zero(tpm2b_public.publicArea.unique);
+
+ TPM2B_SENSITIVE_CREATE tpm2b_sensitive;
+ if (sensitive)
+ tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {
+ .size = sizeof(*sensitive),
+ .sensitive = *sensitive,
+ };
+ else
+ tpm2b_sensitive = (TPM2B_SENSITIVE_CREATE) {};
+
+ _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
+ _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
+ rc = sym_Esys_Create(
+ c->esys_context,
+ parent ? parent->esys_handle : ESYS_TR_RH_OWNER,
+ session ? session->esys_handle : ESYS_TR_PASSWORD,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ &tpm2b_sensitive,
+ &tpm2b_public,
+ /* outsideInfo= */ NULL,
+ &(TPML_PCR_SELECTION) {},
+ &private,
+ &public,
+ /* creationData= */ NULL,
+ /* creationHash= */ NULL,
+ /* creationTicket= */ NULL);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to generate object in TPM: %s",
+ sym_Tss2_RC_Decode(rc));
+
+ log_debug("Successfully created object on TPM in %s.",
+ FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
+
+ if (ret_public)
+ *ret_public = TAKE_PTR(public);
+ if (ret_private)
+ *ret_private = TAKE_PTR(private);
+
+ return 0;
+}
+
static int tpm2_load(
Tpm2Context *c,
const Tpm2Handle *parent,
@@ -2950,38 +3019,34 @@ int tpm2_seal(const char *device,
/* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the
* LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it
* because it's a key type that is universally supported and suitable for symmetric binary blobs. */
- TPM2B_PUBLIC hmac_template = {
- .size = sizeof(TPMT_PUBLIC),
- .publicArea = {
- .type = TPM2_ALG_KEYEDHASH,
- .nameAlg = TPM2_ALG_SHA256,
- .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
- .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
- .unique.keyedHash.size = SHA256_DIGEST_SIZE,
- .authPolicy = policy_digest,
- },
+ TPMT_PUBLIC hmac_template = {
+ .type = TPM2_ALG_KEYEDHASH,
+ .nameAlg = TPM2_ALG_SHA256,
+ .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
+ .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
+ .unique.keyedHash.size = SHA256_DIGEST_SIZE,
+ .authPolicy = policy_digest,
};
- TPM2B_SENSITIVE_CREATE hmac_sensitive = {
- .size = sizeof(hmac_sensitive.sensitive),
- .sensitive.data.size = hmac_template.publicArea.unique.keyedHash.size,
+ TPMS_SENSITIVE_CREATE hmac_sensitive = {
+ .data.size = hmac_template.unique.keyedHash.size,
};
CLEANUP_ERASE(hmac_sensitive);
if (pin) {
- r = tpm2_digest_buffer(TPM2_ALG_SHA256, &hmac_sensitive.sensitive.userAuth, pin, strlen(pin), /* extend= */ false);
+ r = tpm2_digest_buffer(TPM2_ALG_SHA256, &hmac_sensitive.userAuth, pin, strlen(pin), /* extend= */ false);
if (r < 0)
return r;
}
- assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size);
+ assert(sizeof(hmac_sensitive.data.buffer) >= hmac_sensitive.data.size);
(void) tpm2_credit_random(c);
log_debug("Generating secret key data.");
- r = crypto_random_bytes(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size);
+ r = crypto_random_bytes(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
if (r < 0)
return log_error_errno(r, "Failed to generate secret key: %m");
@@ -2996,32 +3061,14 @@ int tpm2_seal(const char *device,
if (r < 0)
return r;
- log_debug("Creating HMAC key.");
-
- static const TPML_PCR_SELECTION creation_pcr = {};
_cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
_cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
- rc = sym_Esys_Create(
- c->esys_context,
- primary_handle->esys_handle,
- encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &hmac_sensitive,
- &hmac_template,
- NULL,
- &creation_pcr,
- &private,
- &public,
- NULL,
- NULL,
- NULL);
- if (rc != TSS2_RC_SUCCESS)
- return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
+ r = tpm2_create(c, primary_handle, encryption_session, &hmac_template, &hmac_sensitive, &public, &private);
+ if (r < 0)
+ return r;
_cleanup_(erase_and_freep) void *secret = NULL;
- secret = memdup(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size);
+ secret = memdup(hmac_sensitive.data.buffer, hmac_sensitive.data.size);
if (!secret)
return log_oom();
@@ -3081,7 +3128,7 @@ int tpm2_seal(const char *device,
}
*ret_secret = TAKE_PTR(secret);
- *ret_secret_size = hmac_sensitive.sensitive.data.size;
+ *ret_secret_size = hmac_sensitive.data.size;
*ret_blob = TAKE_PTR(blob);
*ret_blob_size = blob_size;
*ret_pcr_hash = TAKE_PTR(hash);