systemd/0551-tpm2-use-CreatePrimary...

247 lines
11 KiB
Diff

From 41ed51e6fd011244875680580abb892c4cf1fecf Mon Sep 17 00:00:00 2001
From: Dan Streetman <ddstreet@ieee.org>
Date: Thu, 3 Aug 2023 14:44:57 -0400
Subject: [PATCH] tpm2: use CreatePrimary() to create primary keys instead of
Create()
Older versions used CreatePrimary() to create a transient primary key to use
when creating a sealed data object. That was changed in v254 to use Create()
instead, which should result in the same transient key, but it seems some
hardware TPMs refuse to allow using Create() to generate primary keys.
This reverts to using CreatePrimary() to create primary key.
Fixes: #28654
(cherry picked from commit aff853f8ea29f22b28e3b584807893c528227769)
Related: RHEL-16182
---
src/shared/tpm2-util.c | 102 +++++++++++++++++++++++++++++++----------
src/shared/tpm2-util.h | 4 ++
2 files changed, 81 insertions(+), 25 deletions(-)
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
index 320261afb6..e889d4c0fe 100644
--- a/src/shared/tpm2-util.c
+++ b/src/shared/tpm2-util.c
@@ -1144,8 +1144,6 @@ static int tpm2_get_srk(
return 1;
}
-static 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);
-
/* Get the SRK, creating one if needed. Returns 0 on success, or < 0 on error. */
static int tpm2_get_or_create_srk(
Tpm2Context *c,
@@ -1164,20 +1162,18 @@ static int tpm2_get_or_create_srk(
return 0;
/* No SRK, create and persist one */
- TPMT_PUBLIC template;
- r = tpm2_get_best_srk_template(c, &template);
+ TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
+ r = tpm2_get_best_srk_template(c, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get best SRK template: %m");
_cleanup_(tpm2_handle_freep) Tpm2Handle *transient_handle = NULL;
- r = tpm2_create_loaded(
+ r = tpm2_create_primary(
c,
- /* parent= */ NULL,
session,
&template,
/* sensitive= */ NULL,
/* ret_public= */ NULL,
- /* ret_private= */ NULL,
&transient_handle);
if (r < 0)
return r;
@@ -1547,8 +1543,65 @@ static int tpm2_get_policy_digest(
return 0;
}
-static int tpm2_create(
+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) {
+
+ usec_t ts;
+ TSS2_RC rc;
+ int r;
+
+ assert(c);
+ assert(template);
+
+ log_debug("Creating primary key on TPM.");
+
+ ts = now(CLOCK_MONOTONIC);
+
+ _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+ r = tpm2_handle_new(c, &handle);
+ if (r < 0)
+ return r;
+
+ _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
+ rc = sym_Esys_CreatePrimary(
+ c->esys_context,
+ ESYS_TR_RH_OWNER,
+ session ? session->esys_handle : ESYS_TR_PASSWORD,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ sensitive ? sensitive : &(TPM2B_SENSITIVE_CREATE) {},
+ template,
+ /* outsideInfo= */ NULL,
+ &(TPML_PCR_SELECTION) {},
+ &handle->esys_handle,
+ &public,
+ /* creationData= */ NULL,
+ /* creationHash= */ NULL,
+ /* creationTicket= */ NULL);
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to generate primary key in TPM: %s",
+ sym_Tss2_RC_Decode(rc));
+
+ log_debug("Successfully created primary key on TPM in %s.",
+ FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
+
+ if (ret_public)
+ *ret_public = TAKE_PTR(public);
+ if (ret_handle)
+ *ret_handle = TAKE_PTR(handle);
+
+ return 0;
+}
+
+/* Create a TPM object. Do not use this to create primary keys, because some HW TPMs refuse to allow that;
+ * instead use tpm2_create_primary(). */
+int tpm2_create(Tpm2Context *c,
const Tpm2Handle *parent,
const Tpm2Handle *session,
const TPMT_PUBLIC *template,
@@ -1560,6 +1613,7 @@ static int tpm2_create(
TSS2_RC rc;
assert(c);
+ assert(parent);
assert(template);
log_debug("Creating object on TPM.");
@@ -1587,7 +1641,7 @@ static int tpm2_create(
_cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
rc = sym_Esys_Create(
c->esys_context,
- parent ? parent->esys_handle : ESYS_TR_RH_OWNER,
+ parent->esys_handle,
session ? session->esys_handle : ESYS_TR_PASSWORD,
ESYS_TR_NONE,
ESYS_TR_NONE,
@@ -1721,6 +1775,7 @@ static int _tpm2_create_loaded(
int r;
assert(c);
+ assert(parent);
assert(template);
log_debug("Creating loaded object on TPM.");
@@ -1762,7 +1817,7 @@ static int _tpm2_create_loaded(
_cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
rc = sym_Esys_CreateLoaded(
c->esys_context,
- parent ? parent->esys_handle : ESYS_TR_RH_OWNER,
+ parent->esys_handle,
session ? session->esys_handle : ESYS_TR_PASSWORD,
ESYS_TR_NONE,
ESYS_TR_NONE,
@@ -1790,8 +1845,9 @@ static int _tpm2_create_loaded(
}
/* This calls TPM2_CreateLoaded() if the TPM supports it, otherwise it calls TPM2_Create() and TPM2_Load()
- * separately. */
-static int tpm2_create_loaded(
+ * separately. Do not use this to create primary keys, because some HW TPMs refuse to allow that; instead use
+ * tpm2_create_primary(). */
+int tpm2_create_loaded(
Tpm2Context *c,
const Tpm2Handle *parent,
const Tpm2Handle *session,
@@ -3242,29 +3298,27 @@ int tpm2_seal(const char *device,
return r;
} else {
/* TODO: force all callers to provide ret_srk_buf, so we can stop sealing with the legacy templates. */
- TPMT_PUBLIC template;
- r = tpm2_get_legacy_template(TPM2_ALG_ECC, &template);
+ TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
+ r = tpm2_get_legacy_template(TPM2_ALG_ECC, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get legacy ECC template: %m");
- if (!tpm2_supports_tpmt_public(c, &template)) {
- r = tpm2_get_legacy_template(TPM2_ALG_RSA, &template);
+ if (!tpm2_supports_tpmt_public(c, &template.publicArea)) {
+ r = tpm2_get_legacy_template(TPM2_ALG_RSA, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get legacy RSA template: %m");
- if (!tpm2_supports_tpmt_public(c, &template))
+ if (!tpm2_supports_tpmt_public(c, &template.publicArea))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"TPM does not support either ECC or RSA legacy template.");
}
- r = tpm2_create_loaded(
+ r = tpm2_create_primary(
c,
- /* parent= */ NULL,
/* session= */ NULL,
&template,
/* sensitive= */ NULL,
&primary_public,
- /* ret_private= */ NULL,
&primary_handle);
if (r < 0)
return r;
@@ -3440,19 +3494,17 @@ int tpm2_unseal(const char *device,
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to deserialize primary key: %s", sym_Tss2_RC_Decode(rc));
} else if (primary_alg != 0) {
- TPMT_PUBLIC template;
- r = tpm2_get_legacy_template(primary_alg, &template);
+ TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
+ r = tpm2_get_legacy_template(primary_alg, &template.publicArea);
if (r < 0)
return log_error_errno(r, "Could not get legacy template: %m");
- r = tpm2_create_loaded(
+ r = tpm2_create_primary(
c,
- /* parent= */ NULL,
/* session= */ NULL,
&template,
/* sensitive= */ NULL,
/* ret_public= */ NULL,
- /* ret_private= */ NULL,
&primary_handle);
if (r < 0)
return r;
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
index 64a2fd3677..e059f95790 100644
--- a/src/shared/tpm2-util.h
+++ b/src/shared/tpm2-util.h
@@ -88,6 +88,10 @@ int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle);
Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle);
DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free);
+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);
+
bool tpm2_supports_alg(Tpm2Context *c, TPM2_ALG_ID alg);
bool tpm2_supports_command(Tpm2Context *c, TPM2_CC command);