return 0;
}
+static int tpm2_make_policy_session(
+ Tpm2Context *c,
+ const Tpm2Handle *primary,
+ const Tpm2Handle *encryption_session,
+ bool trial,
+ Tpm2Handle **ret_session) {
+
+ static const TPMT_SYM_DEF symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
+ };
+ TPM2_SE session_type = trial ? TPM2_SE_TRIAL : TPM2_SE_POLICY;
+ TSS2_RC rc;
+ int r;
+
+ assert(c);
+ assert(primary);
+ assert(encryption_session);
+ assert(ret_session);
+
+ if (!tpm2_is_encryption_session(c, encryption_session))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Missing encryption session");
+
+ log_debug("Starting policy session.");
+
+ _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->esys_handle,
+ ESYS_TR_NONE,
+ encryption_session->esys_handle,
+ ESYS_TR_NONE,
+ ESYS_TR_NONE,
+ NULL,
+ session_type,
+ &symmetric,
+ TPM2_ALG_SHA256,
+ &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));
+
+ *ret_session = TAKE_PTR(session);
+
+ return 0;
+}
+
static int openssl_pubkey_to_tpm2_pubkey(
const void *pubkey,
size_t pubkey_size,
#endif
}
-static int tpm2_make_policy_session(
+static int tpm2_build_sealing_policy(
Tpm2Context *c,
- const Tpm2Handle *primary,
- const Tpm2Handle *parent_session,
- TPM2_SE session_type,
+ const Tpm2Handle *session,
uint32_t hash_pcr_mask,
- uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */
+ uint16_t pcr_bank,
const void *pubkey,
size_t pubkey_size,
uint32_t pubkey_pcr_mask,
JsonVariant *signature_json,
bool use_pin,
- Tpm2Handle **ret_session,
- TPM2B_DIGEST **ret_policy_digest,
- TPMI_ALG_HASH *ret_pcr_bank) {
+ TPM2B_DIGEST **ret_policy_digest) {
- static const TPMT_SYM_DEF symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- };
TSS2_RC rc;
int r;
assert(c);
+ assert(session);
assert(pubkey || pubkey_size == 0);
assert(pubkey_pcr_mask == 0 || pubkey_size > 0);
- log_debug("Starting authentication session.");
-
- /* 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. */
- if (session_type == TPM2_SE_TRIAL && pubkey_pcr_mask == 0)
- session_type = TPM2_SE_POLICY;
+ log_debug("Building sealing policy.");
if ((hash_pcr_mask | pubkey_pcr_mask) != 0) {
- /* We are told to configure a PCR policy of some form, let's determine/validate the PCR bank to use. */
-
- if (pcr_bank != UINT16_MAX) {
- r = tpm2_pcr_mask_good(c, pcr_bank, hash_pcr_mask|pubkey_pcr_mask);
- if (r < 0)
- return r;
- if (r == 0)
- log_warning("Selected TPM2 PCRs are not initialized on this system, most likely due to a firmware issue. PCR policy is effectively not enforced. Proceeding anyway.");
- } else {
- /* No bank configured, pick automatically. Some TPM2 devices only can do SHA1. If we
- * detect that use that, but preferably use SHA256 */
- r = tpm2_get_best_pcr_bank(c, hash_pcr_mask|pubkey_pcr_mask, &pcr_bank);
- if (r < 0)
- return r;
- }
+ r = tpm2_pcr_mask_good(c, pcr_bank, hash_pcr_mask|pubkey_pcr_mask);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ log_warning("Selected TPM2 PCRs are not initialized on this system.");
}
- _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->esys_handle,
- ESYS_TR_NONE,
- parent_session->esys_handle,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- NULL,
- session_type,
- &symmetric,
- TPM2_ALG_SHA256,
- &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));
-
if (pubkey_pcr_mask != 0) {
_cleanup_free_ void *fp = NULL;
size_t fp_size = 0;
if (r < 0)
return r;
- if (ret_session)
- *ret_session = TAKE_PTR(session);
-
- if (ret_pcr_bank)
- *ret_pcr_bank = pcr_bank;
-
return 0;
}
if (r < 0)
return r;
+ TPMI_ALG_HASH pcr_bank = 0;
+ if (hash_pcr_mask | pubkey_pcr_mask) {
+ /* Some TPM2 devices only can do SHA1. Prefer SHA256 but allow SHA1. */
+ r = tpm2_get_best_pcr_bank(c, hash_pcr_mask|pubkey_pcr_mask, &pcr_bank);
+ if (r < 0)
+ return r;
+ }
+
_cleanup_tpm2_handle_ Tpm2Handle *primary = NULL;
r = tpm2_make_primary(c, /* alg = */0, !!ret_srk_buf, &primary_alg, &primary);
if (r < 0)
return r;
/* we cannot use the bind key before its created */
- _cleanup_tpm2_handle_ Tpm2Handle *session = NULL;
- r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, NULL, &session);
+ _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
+ r = tpm2_make_encryption_session(c, primary, &TPM2_HANDLE_NONE, NULL, &encryption_session);
if (r < 0)
return r;
- _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL;
- TPMI_ALG_HASH pcr_bank;
+ /* 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,
- session,
- TPM2_SE_TRIAL,
+ 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= */ UINT16_MAX,
+ pcr_bank,
pubkey, pubkey_size,
pubkey_pcr_mask,
/* signature_json= */ NULL,
!!pin,
- /* ret_session= */ NULL,
- &policy_digest,
- &pcr_bank);
+ &policy_digest);
if (r < 0)
return r;
rc = sym_Esys_Create(
c->esys_context,
primary->esys_handle,
- session->esys_handle, /* use HMAC session to enable parameter encryption */
+ encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
ESYS_TR_NONE,
ESYS_TR_NONE,
&hmac_sensitive,
sym_Tss2_RC_Decode(rc));
}
- _cleanup_tpm2_handle_ Tpm2Handle *hmac_session = NULL;
- r = tpm2_make_encryption_session(c, primary, hmac_key, pin, &hmac_session);
+ _cleanup_tpm2_handle_ Tpm2Handle *encryption_session = NULL;
+ r = tpm2_make_encryption_session(c, primary, hmac_key, pin, &encryption_session);
if (r < 0)
return r;
r = tpm2_make_policy_session(
c,
primary,
- hmac_session,
- TPM2_SE_POLICY,
+ encryption_session,
+ /* trial= */ false,
+ &policy_session);
+ if (r < 0)
+ return r;
+
+ r = tpm2_build_sealing_policy(
+ c,
+ policy_session,
hash_pcr_mask,
pcr_bank,
pubkey, pubkey_size,
pubkey_pcr_mask,
signature,
!!pin,
- &policy_session,
- &policy_digest,
- /* ret_pcr_bank= */ NULL);
+ &policy_digest);
if (r < 0)
return r;
c->esys_context,
hmac_key->esys_handle,
policy_session->esys_handle,
- hmac_session->esys_handle, /* use HMAC session to enable parameter encryption */
+ encryption_session->esys_handle, /* use HMAC session to enable parameter encryption */
ESYS_TR_NONE,
&unsealed);
if (rc == TSS2_RC_SUCCESS)