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.
1058 lines
49 KiB
1058 lines
49 KiB
6 months ago
|
From 3c05ed19e51be8220479e65c04308e7bd8d2a850 Mon Sep 17 00:00:00 2001
|
||
|
From: Dan Streetman <ddstreet@ieee.org>
|
||
|
Date: Tue, 24 Jan 2023 10:19:03 -0500
|
||
|
Subject: [PATCH] tpm2: add Tpm2Handle with automatic cleanup
|
||
|
|
||
|
This allows using _cleanup_ with the handles, which then allows removing the
|
||
|
use of goto in all functions that use the handles.
|
||
|
|
||
|
(cherry picked from commit 16e16b8c7b1621f3db96bfc357e5bba727c9dded)
|
||
|
|
||
|
Related: RHEL-16182
|
||
|
---
|
||
|
src/boot/measure.c | 119 +++++--------
|
||
|
src/shared/tpm2-util.c | 371 ++++++++++++++++++++---------------------
|
||
|
src/shared/tpm2-util.h | 14 +-
|
||
|
3 files changed, 237 insertions(+), 267 deletions(-)
|
||
|
|
||
|
diff --git a/src/boot/measure.c b/src/boot/measure.c
|
||
|
index 1bb35e5f76..65a48a01cd 100644
|
||
|
--- a/src/boot/measure.c
|
||
|
+++ b/src/boot/measure.c
|
||
|
@@ -718,7 +718,6 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
_cleanup_(pcr_state_free_all) PcrState *pcr_states = NULL;
|
||
|
_cleanup_(EVP_PKEY_freep) EVP_PKEY *privkey = NULL, *pubkey = NULL;
|
||
|
_cleanup_fclose_ FILE *privkeyf = NULL;
|
||
|
- ESYS_TR session_handle = ESYS_TR_NONE;
|
||
|
TSS2_RC rc;
|
||
|
size_t n;
|
||
|
int r;
|
||
|
@@ -811,6 +810,11 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
};
|
||
|
PcrState *p = pcr_states + i;
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
|
||
|
+ r = tpm2_handle_new(c, &session);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
rc = sym_Esys_StartAuthSession(
|
||
|
c->esys_context,
|
||
|
ESYS_TR_NONE,
|
||
|
@@ -822,12 +826,10 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
TPM2_SE_TRIAL,
|
||
|
&symmetric,
|
||
|
TPM2_ALG_SHA256,
|
||
|
- &session_handle);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ &session->esys_handle);
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
/* Generate a single hash value from the PCRs included in our policy. Given that that's
|
||
|
* exactly one, the calculation is trivial. */
|
||
|
@@ -838,94 +840,72 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
sha256_direct(p->value, p->value_size, intermediate_digest.buffer);
|
||
|
|
||
|
int tpmalg = tpm2_hash_alg_from_string(EVP_MD_name(p->md));
|
||
|
- if (tpmalg < 0) {
|
||
|
- log_error_errno(tpmalg, "Unsupported PCR bank");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (tpmalg < 0)
|
||
|
+ return log_error_errno(tpmalg, "Unsupported PCR bank");
|
||
|
|
||
|
TPML_PCR_SELECTION pcr_selection;
|
||
|
tpm2_pcr_mask_to_selection(1 << TPM_PCR_INDEX_KERNEL_IMAGE, tpmalg, &pcr_selection);
|
||
|
|
||
|
rc = sym_Esys_PolicyPCR(
|
||
|
c->esys_context,
|
||
|
- session_handle,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&intermediate_digest,
|
||
|
&pcr_selection);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to push PCR policy into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *pcr_policy_digest = NULL;
|
||
|
rc = sym_Esys_PolicyGetDigest(
|
||
|
c->esys_context,
|
||
|
- session_handle,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&pcr_policy_digest);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
-
|
||
|
- session_handle = tpm2_flush_context_verbose(c, session_handle);
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = NULL;
|
||
|
mdctx = EVP_MD_CTX_new();
|
||
|
- if (!mdctx) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!mdctx)
|
||
|
+ return log_oom();
|
||
|
|
||
|
- if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to initialize signature context.");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (EVP_DigestSignInit(mdctx, NULL, p->md, NULL, privkey) != 1)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to initialize signature context.");
|
||
|
|
||
|
- if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to sign data.");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (EVP_DigestSignUpdate(mdctx, pcr_policy_digest->buffer, pcr_policy_digest->size) != 1)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to sign data.");
|
||
|
|
||
|
size_t ss;
|
||
|
- if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to finalize signature");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (EVP_DigestSignFinal(mdctx, NULL, &ss) != 1)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to finalize signature");
|
||
|
|
||
|
_cleanup_free_ void *sig = malloc(ss);
|
||
|
- if (!sig) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!sig)
|
||
|
+ return log_oom();
|
||
|
|
||
|
- if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to acquire signature data");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (EVP_DigestSignFinal(mdctx, sig, &ss) != 1)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to acquire signature data");
|
||
|
|
||
|
_cleanup_free_ void *pubkey_fp = NULL;
|
||
|
size_t pubkey_fp_size = 0;
|
||
|
r = pubkey_fingerprint(pubkey, EVP_sha256(), &pubkey_fp, &pubkey_fp_size);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
_cleanup_(json_variant_unrefp) JsonVariant *a = NULL;
|
||
|
r = tpm2_make_pcr_json_array(UINT64_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE, &a);
|
||
|
- if (r < 0) {
|
||
|
- log_error_errno(r, "Failed to build JSON PCR mask array: %m");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Failed to build JSON PCR mask array: %m");
|
||
|
|
||
|
_cleanup_(json_variant_unrefp) JsonVariant *bv = NULL;
|
||
|
r = json_build(&bv, JSON_BUILD_OBJECT(
|
||
|
@@ -933,25 +913,19 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
JSON_BUILD_PAIR("pkfp", JSON_BUILD_HEX(pubkey_fp, pubkey_fp_size)), /* SHA256 fingerprint of public key (DER) used for the signature */
|
||
|
JSON_BUILD_PAIR("pol", JSON_BUILD_HEX(pcr_policy_digest->buffer, pcr_policy_digest->size)), /* TPM2 policy hash that is signed */
|
||
|
JSON_BUILD_PAIR("sig", JSON_BUILD_BASE64(sig, ss)))); /* signature data */
|
||
|
- if (r < 0) {
|
||
|
- log_error_errno(r, "Failed to build JSON object: %m");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Failed to build JSON object: %m");
|
||
|
|
||
|
_cleanup_(json_variant_unrefp) JsonVariant *av = NULL;
|
||
|
av = json_variant_ref(json_variant_by_key(v, p->bank));
|
||
|
|
||
|
r = json_variant_append_array(&av, bv);
|
||
|
- if (r < 0) {
|
||
|
- log_error_errno(r, "Failed to append JSON object: %m");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Failed to append JSON object: %m");
|
||
|
|
||
|
r = json_variant_set_field(&v, p->bank, av);
|
||
|
- if (r < 0) {
|
||
|
- log_error_errno(r, "Failed to add JSON field: %m");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Failed to add JSON field: %m");
|
||
|
}
|
||
|
|
||
|
/* Return to the original kernel measurement for the next phase calculation */
|
||
|
@@ -962,11 +936,8 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||
|
pager_open(arg_pager_flags);
|
||
|
|
||
|
json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
||
|
- r = 0;
|
||
|
|
||
|
-finish:
|
||
|
- session_handle = tpm2_flush_context_verbose(c, session_handle);
|
||
|
- return r;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static int compare_reported_pcr_nr(uint32_t pcr, const char *varname, const char *description) {
|
||
|
diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c
|
||
|
index 2111d0c638..a01c6537b5 100644
|
||
|
--- a/src/shared/tpm2-util.c
|
||
|
+++ b/src/shared/tpm2-util.c
|
||
|
@@ -118,23 +118,6 @@ static Tpm2Context *tpm2_context_free(Tpm2Context *c) {
|
||
|
|
||
|
DEFINE_TRIVIAL_REF_UNREF_FUNC(Tpm2Context, tpm2_context, tpm2_context_free);
|
||
|
|
||
|
-ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle) {
|
||
|
- TSS2_RC rc;
|
||
|
-
|
||
|
- if (!c || !c->esys_context || handle == ESYS_TR_NONE)
|
||
|
- return ESYS_TR_NONE;
|
||
|
-
|
||
|
- rc = sym_Esys_FlushContext(c->esys_context, handle);
|
||
|
- if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called
|
||
|
- * in error paths, where we cannot do anything about failures anymore. And
|
||
|
- * when it is called in successful codepaths by this time we already did
|
||
|
- * what we wanted to do, and got the results we wanted so there's no
|
||
|
- * reason to make this fail more loudly than necessary. */
|
||
|
- log_debug("Failed to get flush context of TPM, ignoring: %s", sym_Tss2_RC_Decode(rc));
|
||
|
-
|
||
|
- return ESYS_TR_NONE;
|
||
|
-}
|
||
|
-
|
||
|
int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
|
||
|
_cleanup_tpm2_context_ Tpm2Context *context = NULL;
|
||
|
TSS2_RC rc;
|
||
|
@@ -245,6 +228,47 @@ int tpm2_context_new(const char *device, Tpm2Context **ret_context) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static void tpm2_handle_flush(ESYS_CONTEXT *esys_context, ESYS_TR esys_handle) {
|
||
|
+ if (!esys_context || esys_handle == ESYS_TR_NONE)
|
||
|
+ return;
|
||
|
+
|
||
|
+ TSS2_RC rc = sym_Esys_FlushContext(esys_context, esys_handle);
|
||
|
+ if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called
|
||
|
+ * in error paths, where we cannot do anything about failures anymore. And
|
||
|
+ * when it is called in successful codepaths by this time we already did
|
||
|
+ * what we wanted to do, and got the results we wanted so there's no
|
||
|
+ * reason to make this fail more loudly than necessary. */
|
||
|
+ log_debug("Failed to flush TPM handle, ignoring: %s", sym_Tss2_RC_Decode(rc));
|
||
|
+}
|
||
|
+
|
||
|
+Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle) {
|
||
|
+ if (!handle)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ _cleanup_tpm2_context_ Tpm2Context *context = (Tpm2Context*)handle->tpm2_context;
|
||
|
+ if (context)
|
||
|
+ tpm2_handle_flush(context->esys_context, handle->esys_handle);
|
||
|
+
|
||
|
+ return mfree(handle);
|
||
|
+}
|
||
|
+
|
||
|
+int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle) {
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *handle = NULL;
|
||
|
+
|
||
|
+ assert(ret_handle);
|
||
|
+
|
||
|
+ handle = new0(Tpm2Handle, 1);
|
||
|
+ if (!handle)
|
||
|
+ return log_oom();
|
||
|
+
|
||
|
+ handle->tpm2_context = tpm2_context_ref(context);
|
||
|
+ handle->esys_handle = ESYS_TR_NONE;
|
||
|
+
|
||
|
+ *ret_handle = TAKE_PTR(handle);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
#define TPM2_CREDIT_RANDOM_FLAG_PATH "/run/systemd/tpm-rng-credited"
|
||
|
|
||
|
static int tpm2_credit_random(Tpm2Context *c) {
|
||
|
@@ -307,7 +331,7 @@ static int tpm2_credit_random(Tpm2Context *c) {
|
||
|
|
||
|
static int tpm2_make_primary(
|
||
|
Tpm2Context *c,
|
||
|
- ESYS_TR *ret_primary,
|
||
|
+ Tpm2Handle **ret_primary,
|
||
|
TPMI_ALG_PUBLIC alg,
|
||
|
TPMI_ALG_PUBLIC *ret_alg) {
|
||
|
|
||
|
@@ -349,9 +373,9 @@ static int tpm2_make_primary(
|
||
|
};
|
||
|
|
||
|
static const TPML_PCR_SELECTION creation_pcr = {};
|
||
|
- ESYS_TR primary = ESYS_TR_NONE;
|
||
|
TSS2_RC rc;
|
||
|
usec_t ts;
|
||
|
+ int r;
|
||
|
|
||
|
log_debug("Creating primary key on TPM.");
|
||
|
|
||
|
@@ -361,6 +385,11 @@ static int tpm2_make_primary(
|
||
|
|
||
|
ts = now(CLOCK_MONOTONIC);
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
|
||
|
+ r = tpm2_handle_new(c, &primary);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
if (IN_SET(alg, 0, TPM2_ALG_ECC)) {
|
||
|
rc = sym_Esys_CreatePrimary(
|
||
|
c->esys_context,
|
||
|
@@ -372,7 +401,7 @@ static int tpm2_make_primary(
|
||
|
&primary_template_ecc,
|
||
|
NULL,
|
||
|
&creation_pcr,
|
||
|
- &primary,
|
||
|
+ &primary->esys_handle,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
@@ -401,7 +430,7 @@ static int tpm2_make_primary(
|
||
|
&primary_template_rsa,
|
||
|
NULL,
|
||
|
&creation_pcr,
|
||
|
- &primary,
|
||
|
+ &primary->esys_handle,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
@@ -420,7 +449,8 @@ static int tpm2_make_primary(
|
||
|
|
||
|
log_debug("Generating primary key on TPM2 took %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - ts, USEC_PER_MSEC));
|
||
|
|
||
|
- *ret_primary = primary;
|
||
|
+ if (ret_primary)
|
||
|
+ *ret_primary = TAKE_PTR(primary);
|
||
|
if (ret_alg)
|
||
|
*ret_alg = alg;
|
||
|
|
||
|
@@ -785,10 +815,10 @@ static void hash_pin(const char *pin, size_t len, TPM2B_AUTH *auth) {
|
||
|
|
||
|
static int tpm2_make_encryption_session(
|
||
|
Tpm2Context *c,
|
||
|
- ESYS_TR primary,
|
||
|
- ESYS_TR bind_key,
|
||
|
+ const Tpm2Handle *primary,
|
||
|
+ const Tpm2Handle *bind_key,
|
||
|
const char *pin,
|
||
|
- ESYS_TR *ret_session) {
|
||
|
+ Tpm2Handle **ret_session) {
|
||
|
|
||
|
static const TPMT_SYM_DEF symmetric = {
|
||
|
.algorithm = TPM2_ALG_AES,
|
||
|
@@ -797,10 +827,11 @@ static int tpm2_make_encryption_session(
|
||
|
};
|
||
|
const TPMA_SESSION sessionAttributes = TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT |
|
||
|
TPMA_SESSION_CONTINUESESSION;
|
||
|
- ESYS_TR session = ESYS_TR_NONE;
|
||
|
TSS2_RC rc;
|
||
|
+ int r;
|
||
|
|
||
|
assert(c);
|
||
|
+ assert(ret_session);
|
||
|
|
||
|
/*
|
||
|
* if a pin is set for the seal object, use it to bind the session
|
||
|
@@ -816,7 +847,7 @@ static int tpm2_make_encryption_session(
|
||
|
|
||
|
hash_pin(pin, strlen(pin), &auth);
|
||
|
|
||
|
- rc = sym_Esys_TR_SetAuth(c->esys_context, bind_key, &auth);
|
||
|
+ rc = sym_Esys_TR_SetAuth(c->esys_context, bind_key->esys_handle, &auth);
|
||
|
if (rc != TSS2_RC_SUCCESS)
|
||
|
return log_error_errno(
|
||
|
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
@@ -829,10 +860,15 @@ static int tpm2_make_encryption_session(
|
||
|
/* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which
|
||
|
* means that the random salt will be encrypted with the well-known key. That way, only the TPM can
|
||
|
* recover the salt, which is then used for key derivation. */
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
|
||
|
+ r = tpm2_handle_new(c, &session);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
rc = sym_Esys_StartAuthSession(
|
||
|
c->esys_context,
|
||
|
- primary,
|
||
|
- bind_key,
|
||
|
+ primary->esys_handle,
|
||
|
+ bind_key->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
@@ -840,7 +876,7 @@ static int tpm2_make_encryption_session(
|
||
|
TPM2_SE_HMAC,
|
||
|
&symmetric,
|
||
|
TPM2_ALG_SHA256,
|
||
|
- &session);
|
||
|
+ &session->esys_handle);
|
||
|
if (rc != TSS2_RC_SUCCESS)
|
||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
"Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
@@ -848,19 +884,15 @@ static int tpm2_make_encryption_session(
|
||
|
/* Enable parameter encryption/decryption with AES in CFB mode. Together with HMAC digests (which are
|
||
|
* always used for sessions), this provides confidentiality, integrity and replay protection for
|
||
|
* operations that use this session. */
|
||
|
- rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session, sessionAttributes, 0xff);
|
||
|
+ rc = sym_Esys_TRSess_SetAttributes(c->esys_context, session->esys_handle, sessionAttributes, 0xff);
|
||
|
if (rc != TSS2_RC_SUCCESS)
|
||
|
return log_error_errno(
|
||
|
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
"Failed to configure TPM session: %s",
|
||
|
sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
- if (ret_session) {
|
||
|
- *ret_session = session;
|
||
|
- session = ESYS_TR_NONE;
|
||
|
- }
|
||
|
+ *ret_session = TAKE_PTR(session);
|
||
|
|
||
|
- session = tpm2_flush_context_verbose(c, session);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -1048,8 +1080,8 @@ static int find_signature(
|
||
|
|
||
|
static int tpm2_make_policy_session(
|
||
|
Tpm2Context *c,
|
||
|
- ESYS_TR primary,
|
||
|
- ESYS_TR parent_session,
|
||
|
+ const Tpm2Handle *primary,
|
||
|
+ const Tpm2Handle *parent_session,
|
||
|
TPM2_SE session_type,
|
||
|
uint32_t hash_pcr_mask,
|
||
|
uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
|
||
|
@@ -1058,7 +1090,7 @@ static int tpm2_make_policy_session(
|
||
|
uint32_t pubkey_pcr_mask,
|
||
|
JsonVariant *signature_json,
|
||
|
bool use_pin,
|
||
|
- ESYS_TR *ret_session,
|
||
|
+ Tpm2Handle **ret_session,
|
||
|
TPM2B_DIGEST **ret_policy_digest,
|
||
|
TPMI_ALG_HASH *ret_pcr_bank) {
|
||
|
|
||
|
@@ -1068,7 +1100,6 @@ static int tpm2_make_policy_session(
|
||
|
.mode.aes = TPM2_ALG_CFB,
|
||
|
};
|
||
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
||
|
- ESYS_TR session = ESYS_TR_NONE, pubkey_handle = ESYS_TR_NONE;
|
||
|
TSS2_RC rc;
|
||
|
int r;
|
||
|
|
||
|
@@ -1123,18 +1154,23 @@ static int tpm2_make_policy_session(
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
|
||
|
+ r = tpm2_handle_new(c, &session);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
rc = sym_Esys_StartAuthSession(
|
||
|
c->esys_context,
|
||
|
- primary,
|
||
|
+ primary->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
- parent_session,
|
||
|
+ parent_session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
NULL,
|
||
|
session_type,
|
||
|
&symmetric,
|
||
|
TPM2_ALG_SHA256,
|
||
|
- &session);
|
||
|
+ &session->esys_handle);
|
||
|
if (rc != TSS2_RC_SUCCESS)
|
||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
"Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
@@ -1147,7 +1183,12 @@ static int tpm2_make_policy_session(
|
||
|
TPM2B_PUBLIC pubkey_tpm2;
|
||
|
r = openssl_pubkey_to_tpm2_pubkey(pk, &pubkey_tpm2);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
+
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *pubkey_handle = NULL;
|
||
|
+ r = tpm2_handle_new(c, &pubkey_handle);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
|
||
|
rc = sym_Esys_LoadExternal(
|
||
|
c->esys_context,
|
||
|
@@ -1163,56 +1204,48 @@ static int tpm2_make_policy_session(
|
||
|
#else
|
||
|
TPM2_RH_OWNER,
|
||
|
#endif
|
||
|
- &pubkey_handle);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ &pubkey_handle->esys_handle);
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to load public key into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
/* Acquire the "name" of what we just loaded */
|
||
|
_cleanup_(Esys_Freep) TPM2B_NAME *pubkey_name = NULL;
|
||
|
rc = sym_Esys_TR_GetName(
|
||
|
c->esys_context,
|
||
|
- pubkey_handle,
|
||
|
+ pubkey_handle->esys_handle,
|
||
|
&pubkey_name);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to get name of public key from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
/* Put together the PCR policy we want to use */
|
||
|
TPML_PCR_SELECTION pcr_selection;
|
||
|
tpm2_pcr_mask_to_selection(pubkey_pcr_mask, pcr_bank, &pcr_selection);
|
||
|
rc = sym_Esys_PolicyPCR(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
NULL,
|
||
|
&pcr_selection);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ 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;
|
||
|
rc = sym_Esys_PolicyGetDigest(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&approved_policy);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
/* When we are unlocking and have a signature, let's pass it to the TPM */
|
||
|
_cleanup_(Esys_Freep) TPMT_TK_VERIFIED *check_ticket_buffer = NULL;
|
||
|
@@ -1231,7 +1264,7 @@ static int tpm2_make_policy_session(
|
||
|
&signature_raw,
|
||
|
&signature_size);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
/* TPM2_VerifySignature() will only verify the RSA part of the RSA+SHA256 signature,
|
||
|
* hence we need to do the SHA256 part ourselves, first */
|
||
|
@@ -1248,26 +1281,22 @@ static int tpm2_make_policy_session(
|
||
|
.sig.size = signature_size,
|
||
|
},
|
||
|
};
|
||
|
- if (signature_size > sizeof(policy_signature.signature.rsassa.sig.buffer)) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer.");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (signature_size > sizeof(policy_signature.signature.rsassa.sig.buffer))
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Signature larger than buffer.");
|
||
|
memcpy(policy_signature.signature.rsassa.sig.buffer, signature_raw, signature_size);
|
||
|
|
||
|
rc = sym_Esys_VerifySignature(
|
||
|
c->esys_context,
|
||
|
- pubkey_handle,
|
||
|
+ pubkey_handle->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&signature_hash,
|
||
|
&policy_signature,
|
||
|
&check_ticket_buffer);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to validate signature in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
check_ticket = check_ticket_buffer;
|
||
|
} else {
|
||
|
@@ -1282,7 +1311,7 @@ static int tpm2_make_policy_session(
|
||
|
|
||
|
rc = sym_Esys_PolicyAuthorize(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
@@ -1290,11 +1319,9 @@ static int tpm2_make_policy_session(
|
||
|
/* policyRef= */ &(const TPM2B_NONCE) {},
|
||
|
pubkey_name,
|
||
|
check_ticket);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to push Authorize policy into TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
#else
|
||
|
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL support is disabled.");
|
||
|
#endif
|
||
|
@@ -1307,17 +1334,15 @@ static int tpm2_make_policy_session(
|
||
|
tpm2_pcr_mask_to_selection(hash_pcr_mask, pcr_bank, &pcr_selection);
|
||
|
rc = sym_Esys_PolicyPCR(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
NULL,
|
||
|
&pcr_selection);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ 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));
|
||
|
}
|
||
|
|
||
|
if (use_pin) {
|
||
|
@@ -1325,16 +1350,14 @@ static int tpm2_make_policy_session(
|
||
|
|
||
|
rc = sym_Esys_PolicyAuthValue(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to add authValue policy to TPM: %s",
|
||
|
- sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to add authValue policy to TPM: %s",
|
||
|
+ sym_Tss2_RC_Decode(rc));
|
||
|
}
|
||
|
|
||
|
if (DEBUG_LOGGING || ret_policy_digest) {
|
||
|
@@ -1342,35 +1365,29 @@ static int tpm2_make_policy_session(
|
||
|
|
||
|
rc = sym_Esys_PolicyGetDigest(
|
||
|
c->esys_context,
|
||
|
- session,
|
||
|
+ session->esys_handle,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&policy_digest);
|
||
|
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_RC_SUCCESS)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
if (DEBUG_LOGGING) {
|
||
|
_cleanup_free_ char *h = NULL;
|
||
|
|
||
|
h = hexmem(policy_digest->buffer, policy_digest->size);
|
||
|
- if (!h) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!h)
|
||
|
+ return log_oom();
|
||
|
|
||
|
log_debug("Session policy digest: %s", h);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if (ret_session) {
|
||
|
- *ret_session = session;
|
||
|
- session = ESYS_TR_NONE;
|
||
|
- }
|
||
|
+ if (ret_session)
|
||
|
+ *ret_session = TAKE_PTR(session);
|
||
|
|
||
|
if (ret_policy_digest)
|
||
|
*ret_policy_digest = TAKE_PTR(policy_digest);
|
||
|
@@ -1378,12 +1395,7 @@ static int tpm2_make_policy_session(
|
||
|
if (ret_pcr_bank)
|
||
|
*ret_pcr_bank = pcr_bank;
|
||
|
|
||
|
- r = 0;
|
||
|
-
|
||
|
-finish:
|
||
|
- session = tpm2_flush_context_verbose(c, session);
|
||
|
- pubkey_handle = tpm2_flush_context_verbose(c, pubkey_handle);
|
||
|
- return r;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
int tpm2_seal(const char *device,
|
||
|
@@ -1407,7 +1419,6 @@ int tpm2_seal(const char *device,
|
||
|
static const TPML_PCR_SELECTION creation_pcr = {};
|
||
|
_cleanup_(erase_and_freep) void *secret = NULL;
|
||
|
_cleanup_free_ void *blob = NULL, *hash = NULL;
|
||
|
- ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE;
|
||
|
TPM2B_SENSITIVE_CREATE hmac_sensitive;
|
||
|
TPMI_ALG_PUBLIC primary_alg;
|
||
|
TPM2B_PUBLIC hmac_template;
|
||
|
@@ -1455,14 +1466,16 @@ int tpm2_seal(const char *device,
|
||
|
if (r < 0)
|
||
|
return r;
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
|
||
|
r = tpm2_make_primary(c, &primary, 0, &primary_alg);
|
||
|
if (r < 0)
|
||
|
return r;
|
||
|
|
||
|
/* we cannot use the bind key before its created */
|
||
|
- r = tpm2_make_encryption_session(c, primary, ESYS_TR_NONE, NULL, &session);
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
|
||
|
+ r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, NULL, &session);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
r = tpm2_make_policy_session(
|
||
|
c,
|
||
|
@@ -1479,7 +1492,7 @@ int tpm2_seal(const char *device,
|
||
|
&policy_digest,
|
||
|
&pcr_bank);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
/* 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
|
||
|
@@ -1510,17 +1523,15 @@ int tpm2_seal(const char *device,
|
||
|
log_debug("Generating secret key data.");
|
||
|
|
||
|
r = crypto_random_bytes(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size);
|
||
|
- if (r < 0) {
|
||
|
- log_error_errno(r, "Failed to generate secret key: %m");
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (r < 0)
|
||
|
+ return log_error_errno(r, "Failed to generate secret key: %m");
|
||
|
|
||
|
log_debug("Creating HMAC key.");
|
||
|
|
||
|
rc = sym_Esys_Create(
|
||
|
c->esys_context,
|
||
|
- primary,
|
||
|
- session, /* use HMAC session to enable parameter encryption */
|
||
|
+ primary->esys_handle,
|
||
|
+ session->esys_handle, /* use HMAC session to enable parameter encryption */
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&hmac_sensitive,
|
||
|
@@ -1532,17 +1543,13 @@ int tpm2_seal(const char *device,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ 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));
|
||
|
|
||
|
secret = memdup(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size);
|
||
|
- if (!secret) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!secret)
|
||
|
+ return log_oom();
|
||
|
|
||
|
log_debug("Marshalling private and public part of HMAC key.");
|
||
|
|
||
|
@@ -1552,10 +1559,8 @@ int tpm2_seal(const char *device,
|
||
|
size_t offset = 0;
|
||
|
|
||
|
buf = malloc(k);
|
||
|
- if (!buf) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!buf)
|
||
|
+ return log_oom();
|
||
|
|
||
|
rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, buf, k, &offset);
|
||
|
if (rc == TSS2_RC_SUCCESS) {
|
||
|
@@ -1566,16 +1571,12 @@ int tpm2_seal(const char *device,
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
- if (rc != TSS2_MU_RC_INSUFFICIENT_BUFFER) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (rc != TSS2_MU_RC_INSUFFICIENT_BUFFER)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc));
|
||
|
|
||
|
- if (k > SIZE_MAX / 2) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (k > SIZE_MAX / 2)
|
||
|
+ return log_oom();
|
||
|
|
||
|
k *= 2;
|
||
|
}
|
||
|
@@ -1596,12 +1597,7 @@ int tpm2_seal(const char *device,
|
||
|
*ret_pcr_bank = pcr_bank;
|
||
|
*ret_primary_alg = primary_alg;
|
||
|
|
||
|
- r = 0;
|
||
|
-
|
||
|
-finish:
|
||
|
- primary = tpm2_flush_context_verbose(c, primary);
|
||
|
- session = tpm2_flush_context_verbose(c, session);
|
||
|
- return r;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
#define RETRY_UNSEAL_MAX 30u
|
||
|
@@ -1622,8 +1618,6 @@ int tpm2_unseal(const char *device,
|
||
|
void **ret_secret,
|
||
|
size_t *ret_secret_size) {
|
||
|
|
||
|
- ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE, hmac_session = ESYS_TR_NONE,
|
||
|
- hmac_key = ESYS_TR_NONE;
|
||
|
_cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
|
||
|
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
|
||
|
_cleanup_(erase_and_freep) char *secret = NULL;
|
||
|
@@ -1677,6 +1671,7 @@ int tpm2_unseal(const char *device,
|
||
|
if (r < 0)
|
||
|
return r;
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
|
||
|
r = tpm2_make_primary(c, &primary, primary_alg, NULL);
|
||
|
if (r < 0)
|
||
|
return r;
|
||
|
@@ -1689,35 +1684,41 @@ int tpm2_unseal(const char *device,
|
||
|
* is provided. If an attacker gives back a bad key, we already lost since
|
||
|
* primary key is not verified and they could attack there as well.
|
||
|
*/
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *hmac_key = NULL;
|
||
|
+ r = tpm2_handle_new(c, &hmac_key);
|
||
|
+ if (r < 0)
|
||
|
+ return r;
|
||
|
+
|
||
|
rc = sym_Esys_Load(
|
||
|
c->esys_context,
|
||
|
- primary,
|
||
|
+ primary->esys_handle,
|
||
|
ESYS_TR_PASSWORD,
|
||
|
ESYS_TR_NONE,
|
||
|
ESYS_TR_NONE,
|
||
|
&private,
|
||
|
&public,
|
||
|
- &hmac_key);
|
||
|
+ &hmac_key->esys_handle);
|
||
|
if (rc != TSS2_RC_SUCCESS) {
|
||
|
/* If we're in dictionary attack lockout mode, we should see a lockout error here, which we
|
||
|
* need to translate for the caller. */
|
||
|
if (rc == TPM2_RC_LOCKOUT)
|
||
|
- r = log_error_errno(
|
||
|
+ return log_error_errno(
|
||
|
SYNTHETIC_ERRNO(ENOLCK),
|
||
|
"TPM2 device is in dictionary attack lockout mode.");
|
||
|
else
|
||
|
- r = log_error_errno(
|
||
|
+ return log_error_errno(
|
||
|
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
"Failed to load HMAC key in TPM: %s",
|
||
|
sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
}
|
||
|
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *hmac_session = NULL;
|
||
|
r = tpm2_make_encryption_session(c, primary, hmac_key, pin, &hmac_session);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
for (unsigned i = RETRY_UNSEAL_MAX;; i--) {
|
||
|
+ _cleanup_tpm2_handle_ Tpm2Handle *policy_session = NULL;
|
||
|
r = tpm2_make_policy_session(
|
||
|
c,
|
||
|
primary,
|
||
|
@@ -1729,11 +1730,11 @@ int tpm2_unseal(const char *device,
|
||
|
pubkey_pcr_mask,
|
||
|
signature,
|
||
|
!!pin,
|
||
|
- &session,
|
||
|
+ &policy_session,
|
||
|
&policy_digest,
|
||
|
/* ret_pcr_bank= */ NULL);
|
||
|
if (r < 0)
|
||
|
- goto finish;
|
||
|
+ return r;
|
||
|
|
||
|
/* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not
|
||
|
* wait until the TPM2 tells us to go away. */
|
||
|
@@ -1747,31 +1748,23 @@ int tpm2_unseal(const char *device,
|
||
|
|
||
|
rc = sym_Esys_Unseal(
|
||
|
c->esys_context,
|
||
|
- hmac_key,
|
||
|
- session,
|
||
|
- hmac_session, /* use HMAC session to enable parameter encryption */
|
||
|
+ hmac_key->esys_handle,
|
||
|
+ policy_session->esys_handle,
|
||
|
+ hmac_session->esys_handle, /* use HMAC session to enable parameter encryption */
|
||
|
ESYS_TR_NONE,
|
||
|
&unsealed);
|
||
|
- if (rc == TPM2_RC_PCR_CHANGED && i > 0) {
|
||
|
- log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
|
||
|
- session = tpm2_flush_context_verbose(c, session);
|
||
|
- continue;
|
||
|
- }
|
||
|
- if (rc != TSS2_RC_SUCCESS) {
|
||
|
- r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
- "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
- goto finish;
|
||
|
- }
|
||
|
-
|
||
|
- break;
|
||
|
+ if (rc == TSS2_RC_SUCCESS)
|
||
|
+ break;
|
||
|
+ if (rc != TPM2_RC_PCR_CHANGED || i == 0)
|
||
|
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||
|
+ "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc));
|
||
|
+ log_debug("A PCR value changed during the TPM2 policy session, restarting HMAC key unsealing (%u tries left).", i);
|
||
|
}
|
||
|
|
||
|
secret = memdup(unsealed->buffer, unsealed->size);
|
||
|
explicit_bzero_safe(unsealed->buffer, unsealed->size);
|
||
|
- if (!secret) {
|
||
|
- r = log_oom();
|
||
|
- goto finish;
|
||
|
- }
|
||
|
+ if (!secret)
|
||
|
+ return log_oom();
|
||
|
|
||
|
if (DEBUG_LOGGING)
|
||
|
log_debug("Completed TPM2 key unsealing in %s.", FORMAT_TIMESPAN(now(CLOCK_MONOTONIC) - start, 1));
|
||
|
@@ -1779,13 +1772,7 @@ int tpm2_unseal(const char *device,
|
||
|
*ret_secret = TAKE_PTR(secret);
|
||
|
*ret_secret_size = unsealed->size;
|
||
|
|
||
|
- r = 0;
|
||
|
-
|
||
|
-finish:
|
||
|
- primary = tpm2_flush_context_verbose(c, primary);
|
||
|
- session = tpm2_flush_context_verbose(c, session);
|
||
|
- hmac_key = tpm2_flush_context_verbose(c, hmac_key);
|
||
|
- return r;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h
|
||
|
index 0266f8128f..9819a33569 100644
|
||
|
--- a/src/shared/tpm2-util.h
|
||
|
+++ b/src/shared/tpm2-util.h
|
||
|
@@ -66,7 +66,18 @@ Tpm2Context *tpm2_context_unref(Tpm2Context *context);
|
||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Context*, tpm2_context_unref);
|
||
|
#define _cleanup_tpm2_context_ _cleanup_(tpm2_context_unrefp)
|
||
|
|
||
|
-ESYS_TR tpm2_flush_context_verbose(Tpm2Context *c, ESYS_TR handle);
|
||
|
+typedef struct {
|
||
|
+ Tpm2Context *tpm2_context;
|
||
|
+ ESYS_TR esys_handle;
|
||
|
+} Tpm2Handle;
|
||
|
+
|
||
|
+#define _tpm2_handle(c, h) { .tpm2_context = (c), .esys_handle = (h), }
|
||
|
+static const Tpm2Handle TPM2_HANDLE_NONE = _tpm2_handle(NULL, ESYS_TR_NONE);
|
||
|
+
|
||
|
+int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle);
|
||
|
+Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle);
|
||
|
+DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free);
|
||
|
+#define _cleanup_tpm2_handle_ _cleanup_(tpm2_handle_freep)
|
||
|
|
||
|
void tpm2_pcr_mask_to_selection(uint32_t mask, uint16_t bank, TPML_PCR_SELECTION *ret);
|
||
|
|
||
|
@@ -82,6 +93,7 @@ int tpm2_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const vo
|
||
|
|
||
|
#else /* HAVE_TPM2 */
|
||
|
typedef struct {} Tpm2Context;
|
||
|
+typedef struct {} Tpm2Handle;
|
||
|
#endif /* HAVE_TPM2 */
|
||
|
|
||
|
int tpm2_list_devices(void);
|