From: Lennart Poettering Date: Thu, 19 Oct 2023 15:54:48 +0000 (+0200) Subject: tpm2-util: add calls for calculating/submitting PolicyAuthorizeNV + PolicyOR TPM2... X-Git-Tag: v255-rc1~27^2~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2cd8f75316152f4080f9820882f5e63352e78280;p=thirdparty%2Fsystemd.git tpm2-util: add calls for calculating/submitting PolicyAuthorizeNV + PolicyOR TPM2 policies --- diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 47907b7d18b..60254d1cc22 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -3438,7 +3438,7 @@ int tpm2_policy_auth_value( assert(c); assert(session); - log_debug("Adding authValue policy."); + log_debug("Submitting AuthValue policy."); rc = sym_Esys_PolicyAuthValue( c->esys_context, @@ -3454,6 +3454,185 @@ int tpm2_policy_auth_value( return tpm2_get_policy_digest(c, session, ret_policy_digest); } +int tpm2_calculate_policy_authorize_nv( + const TPM2B_NV_PUBLIC *public_info, + TPM2B_DIGEST *digest) { + TPM2_CC command = TPM2_CC_PolicyAuthorizeNV; + TSS2_RC rc; + int r; + + assert(public_info); + assert(digest); + assert(digest->size == SHA256_DIGEST_SIZE); + + r = dlopen_tpm2(); + if (r < 0) + return log_debug_errno(r, "TPM2 support not installed: %m"); + + uint8_t buf[sizeof(command)]; + size_t offset = 0; + + rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset); + if (rc != TSS2_RC_SUCCESS) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to marshal PolicyAuthorizeNV command: %s", sym_Tss2_RC_Decode(rc)); + + if (offset != sizeof(command)) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Offset 0x%zx wrong after marshalling PolicyAuthorizeNV command", offset); + + TPM2B_NV_PUBLIC public_info_copy = *public_info; /* Make a copy, since we must set TPMA_NV_WRITTEN for the calculation */ + public_info_copy.nvPublic.attributes |= TPMA_NV_WRITTEN; + + TPM2B_NAME name = {}; + r = tpm2_calculate_nv_index_name(&public_info_copy.nvPublic, &name); + if (r < 0) + return r; + + struct iovec data[] = { + IOVEC_MAKE(buf, offset), + IOVEC_MAKE(name.name, name.size), + }; + + r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, ELEMENTSOF(data), /* extend= */ true); + if (r < 0) + return r; + + tpm2_log_debug_digest(digest, "PolicyAuthorizeNV calculated digest"); + + return 0; +} + +int tpm2_policy_authorize_nv( + Tpm2Context *c, + const Tpm2Handle *session, + const Tpm2Handle *nv_handle, + TPM2B_DIGEST **ret_policy_digest) { + + TSS2_RC rc; + + assert(c); + assert(session); + + log_debug("Submitting AuthorizeNV policy."); + + rc = sym_Esys_PolicyAuthorizeNV( + c->esys_context, + ESYS_TR_RH_OWNER, + nv_handle->esys_handle, + session->esys_handle, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE); + if (rc != TSS2_RC_SUCCESS) + return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add AuthorizeNV policy to TPM: %s", + sym_Tss2_RC_Decode(rc)); + + return tpm2_get_policy_digest(c, session, ret_policy_digest); +} + +int tpm2_policy_or( + Tpm2Context *c, + const Tpm2Handle *session, + const TPM2B_DIGEST *branches, size_t n_branches, + TPM2B_DIGEST **ret_policy_digest) { + + TPML_DIGEST hash_list; + TSS2_RC rc; + + assert(c); + assert(session); + + if (n_branches > ELEMENTSOF(hash_list.digests)) + return -EOPNOTSUPP; + + log_debug("Submitting OR policy."); + + hash_list = (TPML_DIGEST) { + .count = n_branches, + }; + + memcpy(hash_list.digests, branches, n_branches * sizeof(TPM2B_DIGEST)); + + if (DEBUG_LOGGING) + for (size_t i = 0; i < hash_list.count; i++) { + _cleanup_free_ char *h = hexmem(hash_list.digests[i].buffer, hash_list.digests[i].size); + log_debug("Submitting OR Branch #%zu: %s", i, h); + } + + rc = sym_Esys_PolicyOR( + c->esys_context, + session->esys_handle, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &hash_list); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add OR policy to TPM: %s", + sym_Tss2_RC_Decode(rc)); + + return tpm2_get_policy_digest(c, session, ret_policy_digest); +} + +/* Extend 'digest' with the PolicyOR calculated hash. */ +int tpm2_calculate_policy_or(const TPM2B_DIGEST *branches, size_t n_branches, TPM2B_DIGEST *digest) { + TPM2_CC command = TPM2_CC_PolicyOR; + TSS2_RC rc; + int r; + + assert(digest); + assert(digest->size == SHA256_DIGEST_SIZE); + + if (n_branches == 0) + return -EINVAL; + if (n_branches == 1) + log_warning("PolicyOR with a single branch submitted, this is weird."); + if (n_branches > 8) + return -E2BIG; + + r = dlopen_tpm2(); + if (r < 0) + return log_error_errno(r, "TPM2 support not installed: %m"); + + uint8_t buf[sizeof(command)]; + size_t offset = 0; + + rc = sym_Tss2_MU_TPM2_CC_Marshal(command, buf, sizeof(buf), &offset); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to marshal PolicyOR command: %s", sym_Tss2_RC_Decode(rc)); + + if (offset != sizeof(command)) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Offset 0x%zx wrong after marshalling PolicyOR command", offset); + _cleanup_free_ struct iovec *data = new(struct iovec, 1 + n_branches); + if (!data) + return log_oom(); + + data[0] = IOVEC_MAKE(buf, offset); + for (size_t i = 0; i < n_branches; i++) { + data[1 + i] = IOVEC_MAKE((void*) branches[i].buffer, branches[i].size); + + if (DEBUG_LOGGING) { + _cleanup_free_ char *h = hexmem(branches[i].buffer, branches[i].size); + log_debug("OR Branch #%zu: %s", i, h); + } + } + + /* PolicyOR does not use the previous hash value; we must zero and then extend it. */ + zero(digest->buffer); + + r = tpm2_digest_many(TPM2_ALG_SHA256, digest, data, 1 + n_branches, /* extend= */ true); + if (r < 0) + return r; + + tpm2_log_debug_digest(digest, "PolicyOR calculated digest"); + + return 0; +} + /* Extend 'digest' with the PolicyPCR calculated hash. */ int tpm2_calculate_policy_pcr( const Tpm2PCRValue *pcr_values, @@ -3526,7 +3705,7 @@ int tpm2_policy_pcr( assert(session); assert(pcr_selection); - log_debug("Adding PCR hash policy."); + log_debug("Submitting PCR hash policy."); rc = sym_Esys_PolicyPCR( c->esys_context, diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index b23471ba849..7e13fad567b 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -205,15 +205,20 @@ int tpm2_set_auth(Tpm2Context *c, const Tpm2Handle *handle, const char *pin); int tpm2_set_auth_binary(Tpm2Context *c, const Tpm2Handle *handle, const TPM2B_AUTH *auth); int tpm2_make_policy_session(Tpm2Context *c, const Tpm2Handle *primary, const Tpm2Handle *encryption_session, Tpm2Handle **ret_session); + int tpm2_policy_auth_value(Tpm2Context *c, const Tpm2Handle *session, TPM2B_DIGEST **ret_policy_digest); +int tpm2_policy_authorize_nv(Tpm2Context *c, const Tpm2Handle *session, const Tpm2Handle *nv_handle, TPM2B_DIGEST **ret_policy_digest); int tpm2_policy_pcr(Tpm2Context *c, const Tpm2Handle *session, const TPML_PCR_SELECTION *pcr_selection, TPM2B_DIGEST **ret_policy_digest); +int tpm2_policy_or(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_DIGEST *branches, size_t n_branches, TPM2B_DIGEST **ret_policy_digest); int tpm2_calculate_pubkey_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name); int tpm2_calculate_nv_index_name(const TPMS_NV_PUBLIC *nvpublic, TPM2B_NAME *ret_name); int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest); int tpm2_calculate_policy_authorize(const TPM2B_PUBLIC *public, const TPM2B_DIGEST *policy_ref, TPM2B_DIGEST *digest); +int tpm2_calculate_policy_authorize_nv(const TPM2B_NV_PUBLIC *public, TPM2B_DIGEST *digest); int tpm2_calculate_policy_pcr(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPM2B_DIGEST *digest); +int tpm2_calculate_policy_or(const TPM2B_DIGEST *branches, size_t n_branches, TPM2B_DIGEST *digest); int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, const TPM2B_PUBLIC *public, bool use_pin, TPM2B_DIGEST *digest); int tpm2_get_or_create_srk(Tpm2Context *c, const Tpm2Handle *session, TPM2B_PUBLIC **ret_public, TPM2B_NAME **ret_name, TPM2B_NAME **ret_qname, Tpm2Handle **ret_handle);