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

tpm2-util: add generic helpers for sealing/unsealing data

These helpers tpm2_seal_data()/tpm2_unseal_data() are useful for
sealing/unsealing data without any further semantics around them. This
is different from the existing tpm2_seal()/tpm2_unseal() which seal with
a specific policy and serialize in a specific way, as we use it for disk
encryption.

These new helpers are more generic, they do not serialize in a specific
way or imply policy, they are just the core of the sealing/unsealing.

(We should look into porting tpm2_seal()/tpm2_unseal() onto these new
helpers, but this isn#t trivial, since the classic serialization we use
uses a merged marshalling of private/public key, which we'd have to
change in one way or another)
This commit is contained in:
Lennart Poettering 2023-10-23 10:30:25 +02:00
parent 48d060564a
commit ce80da02b8
2 changed files with 128 additions and 0 deletions

View File

@ -4919,6 +4919,131 @@ int tpm2_undefine_policy_nv_index(
log_debug("Undefined NV index 0x%x", nv_index);
return 0;
}
int tpm2_seal_data(
Tpm2Context *c,
const struct iovec *data,
const Tpm2Handle *primary_handle,
const Tpm2Handle *encryption_session,
const TPM2B_DIGEST *policy,
struct iovec *ret_public,
struct iovec *ret_private) {
int r;
assert(c);
assert(data);
assert(primary_handle);
/* This is a generic version of tpm2_seal(), that doesn't imply any policy or any specific
* combination of the two keypairs in their marshalling. tpm2_seal() is somewhat specific to the FDE
* usecase. We probably should migrate tpm2_seal() to use tpm2_seal_data() eventually. */
if (data->iov_len >= sizeof_field(TPMS_SENSITIVE_CREATE, data.buffer))
return -E2BIG;
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 = data->iov_len,
.authPolicy = policy ? *policy : TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE),
};
TPMS_SENSITIVE_CREATE hmac_sensitive = {
.data.size = hmac_template.unique.keyedHash.size,
};
CLEANUP_ERASE(hmac_sensitive);
memcpy_safe(hmac_sensitive.data.buffer, data->iov_base, data->iov_len);
_cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
_cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL;
r = tpm2_create(c, primary_handle, encryption_session, &hmac_template, &hmac_sensitive, &public, &private);
if (r < 0)
return r;
_cleanup_(iovec_done) struct iovec public_blob = {}, private_blob = {};
r = tpm2_marshal_private(private, &private_blob.iov_base, &private_blob.iov_len);
if (r < 0)
return r;
r = tpm2_marshal_public(public, &public_blob.iov_base, &public_blob.iov_len);
if (r < 0)
return r;
if (ret_public)
*ret_public = TAKE_STRUCT(public_blob);
if (ret_private)
*ret_private = TAKE_STRUCT(private_blob);
return 0;
}
int tpm2_unseal_data(
Tpm2Context *c,
const struct iovec *public_blob,
const struct iovec *private_blob,
const Tpm2Handle *primary_handle,
const Tpm2Handle *policy_session,
const Tpm2Handle *encryption_session,
struct iovec *ret_data) {
TSS2_RC rc;
int r;
assert(c);
assert(public_blob);
assert(private_blob);
assert(primary_handle);
TPM2B_PUBLIC public;
r = tpm2_unmarshal_public(public_blob->iov_base, public_blob->iov_len, &public);
if (r < 0)
return r;
TPM2B_PRIVATE private;
r = tpm2_unmarshal_private(private_blob->iov_base, private_blob->iov_len, &private);
if (r < 0)
return r;
_cleanup_(tpm2_handle_freep) Tpm2Handle *what = NULL;
r = tpm2_load(c, primary_handle, NULL, &public, &private, &what);
if (r < 0)
return r;
_cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL;
rc = sym_Esys_Unseal(
c->esys_context,
what->esys_handle,
policy_session ? policy_session->esys_handle : ESYS_TR_NONE,
encryption_session ? encryption_session->esys_handle : ESYS_TR_NONE,
ESYS_TR_NONE,
&unsealed);
if (rc == TPM2_RC_PCR_CHANGED)
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE),
"PCR changed while unsealing.");
if (rc != TSS2_RC_SUCCESS)
return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to unseal data: %s", sym_Tss2_RC_Decode(rc));
_cleanup_(iovec_done) struct iovec d = {};
d = (struct iovec) {
.iov_base = memdup(unsealed->buffer, unsealed->size),
.iov_len = unsealed->size,
};
explicit_bzero_safe(unsealed->buffer, unsealed->size);
if (!d.iov_base)
return log_oom_debug();
*ret_data = TAKE_STRUCT(d);
return 0;
}
#endif /* HAVE_TPM2 */
int tpm2_list_devices(void) {

View File

@ -238,6 +238,9 @@ int tpm2_define_policy_nv_index(Tpm2Context *c, const Tpm2Handle *session, TPM2_
int tpm2_write_policy_nv_index(Tpm2Context *c, const Tpm2Handle *policy_session, TPM2_HANDLE nv_index, const Tpm2Handle *nv_handle, const TPM2B_DIGEST *policy_digest);
int tpm2_undefine_policy_nv_index(Tpm2Context *c, const Tpm2Handle *session, TPM2_HANDLE nv_index, const Tpm2Handle *nv_handle);
int tpm2_seal_data(Tpm2Context *c, const struct iovec *data, const Tpm2Handle *primary_handle, const Tpm2Handle *encryption_session, const TPM2B_DIGEST *policy, struct iovec *ret_public, struct iovec *ret_private);
int tpm2_unseal_data(Tpm2Context *c, const struct iovec *public, const struct iovec *private, const Tpm2Handle *primary_handle, const Tpm2Handle *policy_session, const Tpm2Handle *encryption_session, struct iovec *ret_data);
int tpm2_serialize(Tpm2Context *c, const Tpm2Handle *handle, void **ret_serialized, size_t *ret_serialized_size);
int tpm2_deserialize(Tpm2Context *c, const void *serialized, size_t serialized_size, Tpm2Handle **ret_handle);