1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-10 05:18:17 +03:00

tpm2: add tpm2_calculate_sealing_policy()

This adds a function to fully calculate the authPolicy needed to seal a secret,
and updates tpm2_seal() to use the new function instead of a trial policy.
This commit is contained in:
Dan Streetman 2022-12-15 12:56:35 -05:00
parent 524cef3ff5
commit d9a1f1a724

View File

@ -2274,6 +2274,40 @@ static int tpm2_policy_authorize(
return tpm2_get_policy_digest(c, session, ret_policy_digest);
}
/* Extend 'digest' with the calculated policy hash. */
static int tpm2_calculate_sealing_policy(
const TPML_PCR_SELECTION *hash_pcr_selection,
const TPM2B_DIGEST *hash_pcr_values,
size_t n_hash_pcr_values,
const TPM2B_PUBLIC *public,
const char *pin,
TPM2B_DIGEST *digest) {
int r;
assert(digest);
if (public) {
r = tpm2_calculate_policy_authorize(public, NULL, digest);
if (r < 0)
return r;
}
if (hash_pcr_selection && !tpm2_tpml_pcr_selection_is_empty(hash_pcr_selection)) {
r = tpm2_calculate_policy_pcr(hash_pcr_selection, hash_pcr_values, n_hash_pcr_values, digest);
if (r < 0)
return r;
}
if (pin) {
r = tpm2_calculate_policy_auth_value(digest);
if (r < 0)
return r;
}
return 0;
}
static int tpm2_build_sealing_policy(
Tpm2Context *c,
const Tpm2Handle *session,
@ -2356,7 +2390,6 @@ int tpm2_seal(const char *device,
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *hash = NULL;
TPM2B_SENSITIVE_CREATE hmac_sensitive;
TPMI_ALG_PUBLIC primary_alg;
TPM2B_PUBLIC hmac_template;
usec_t start;
TSS2_RC rc;
@ -2409,59 +2442,37 @@ int tpm2_seal(const char *device,
return r;
}
TPML_PCR_SELECTION hash_pcr_selection = {};
_cleanup_free_ TPM2B_DIGEST *hash_pcr_values = NULL;
size_t n_hash_pcr_values = 0;
if (hash_pcr_mask) {
/* For now, we just read the current values from the system; we need to be able to specify
* expected values, eventually. */
tpm2_tpml_pcr_selection_from_mask(hash_pcr_mask, pcr_bank, &hash_pcr_selection);
r = tpm2_pcr_read(c, &hash_pcr_selection, &hash_pcr_selection, &hash_pcr_values, &n_hash_pcr_values);
if (r < 0)
return r;
}
TPM2B_PUBLIC pubkey_tpm2, *authorize_key = NULL;
_cleanup_free_ void *fp = NULL;
size_t fp_size = 0;
if (pubkey) {
r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, &fp, &fp_size);
r = openssl_pubkey_to_tpm2_pubkey(pubkey, pubkey_size, &pubkey_tpm2, NULL, NULL);
if (r < 0)
return r;
authorize_key = &pubkey_tpm2;
}
_cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary);
TPM2B_DIGEST policy_digest;
r = tpm2_digest_init(TPM2_ALG_SHA256, &policy_digest);
if (r < 0)
return r;
/* we cannot use the bind key before its created */
_cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, &encryption_session);
if (r < 0)
return r;
/* So apparently some TPM implementations don't implement trial mode correctly. To avoid issues let's
* avoid it when it is easy to. At the moment we only really need trial mode for the signed PCR
* policies (since only then we need to shove PCR values into the policy that don't match current
* state anyway), hence if we have none of those we don't need to bother. Hence, let's patch in
* TPM2_SE_POLICY even if trial mode is requested unless a pubkey PCR mask is specified that is
* non-zero, i.e. signed PCR policy is requested.
*
* One day we should switch to calculating policy hashes client side when trial mode is requested, to
* avoid this mess. */
bool trial = (pubkey_pcr_mask != 0);
_cleanup_tpm2_handle_ Tpm2Handle *policy_session = NULL;
r = tpm2_make_policy_session(
c,
primary,
encryption_session,
trial,
&policy_session);
if (r < 0)
return r;
_cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
r = tpm2_build_sealing_policy(
c,
policy_session,
hash_pcr_mask,
pcr_bank,
r = tpm2_calculate_sealing_policy(
&hash_pcr_selection,
hash_pcr_values,
n_hash_pcr_values,
authorize_key,
fp, fp_size,
pubkey_pcr_mask,
/* signature_json= */ NULL,
!!pin,
pin,
&policy_digest);
if (r < 0)
return r;
@ -2477,7 +2488,7 @@ int tpm2_seal(const char *device,
.objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT,
.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL,
.unique.keyedHash.size = SHA256_DIGEST_SIZE,
.authPolicy = *policy_digest,
.authPolicy = policy_digest,
},
};
@ -2501,11 +2512,22 @@ int tpm2_seal(const char *device,
if (r < 0)
return log_error_errno(r, "Failed to generate secret key: %m");
_cleanup_tpm2_handle_ Tpm2Handle *primary_handle = NULL;
TPMI_ALG_PUBLIC primary_alg;
r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary_handle);
if (r < 0)
return r;
_cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
r = tpm2_make_encryption_session(c, primary_handle, &TPM2_HANDLE_NONE, &encryption_session);
if (r < 0)
return r;
log_debug("Creating HMAC key.");
rc = sym_Esys_Create(
c->esys_context,
primary->esys_handle,
primary_handle->esys_handle,
encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
ESYS_TR_NONE,
ESYS_TR_NONE,
@ -2545,7 +2567,7 @@ int tpm2_seal(const char *device,
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to marshal public key: %s", sym_Tss2_RC_Decode(rc));
hash = memdup(policy_digest->buffer, policy_digest->size);
hash = memdup(policy_digest.buffer, policy_digest.size);
if (!hash)
return log_oom();
@ -2555,7 +2577,7 @@ int tpm2_seal(const char *device,
*/
if (ret_srk_buf) {
log_debug("Serializing SRK ESYS_TR reference");
rc = sym_Esys_TR_Serialize(c->esys_context, primary->esys_handle, &srk_buf, &srk_buf_size);
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));
@ -2583,7 +2605,7 @@ int tpm2_seal(const char *device,
*ret_blob = TAKE_PTR(blob);
*ret_blob_size = blob_size;
*ret_pcr_hash = TAKE_PTR(hash);
*ret_pcr_hash_size = policy_digest->size;
*ret_pcr_hash_size = policy_digest.size;
*ret_pcr_bank = pcr_bank;
*ret_primary_alg = primary_alg;