return 0;
}
+static void hash_pin(const char *pin, size_t len, TPM2B_AUTH *auth) {
+ struct sha256_ctx hash;
+
+ assert(auth);
+ assert(pin);
+ auth->size = SHA256_DIGEST_SIZE;
+
+ sha256_init_ctx(&hash);
+ sha256_process_bytes(pin, len, &hash);
+ sha256_finish_ctx(&hash, auth->buffer);
+
+ explicit_bzero_safe(&hash, sizeof(hash));
+}
+
static int tpm2_make_encryption_session(
ESYS_CONTEXT *c,
ESYS_TR primary,
+ ESYS_TR bind_key,
+ const char *pin,
ESYS_TR *ret_session) {
static const TPMT_SYM_DEF symmetric = {
assert(c);
+ /*
+ * if a pin is set for the seal object, use it to bind the session
+ * key to that object. This prevents active bus interposers from
+ * faking a TPM and seeing the unsealed value. An active interposer
+ * could fake a TPM, satisfying the encrypted session, and just
+ * forward everything to the *real* TPM.
+ */
+ if (pin) {
+ TPM2B_AUTH auth = {};
+
+ hash_pin(pin, strlen(pin), &auth);
+
+ rc = sym_Esys_TR_SetAuth(c, bind_key, &auth);
+ /* ESAPI knows about it, so clear it from our memory */
+ explicit_bzero_safe(&auth, sizeof(auth));
+ if (rc != TSS2_RC_SUCCESS)
+ return log_error_errno(
+ SYNTHETIC_ERRNO(ENOTRECOVERABLE),
+ "Failed to load PIN in TPM: %s",
+ sym_Tss2_RC_Decode(rc));
+ }
+
log_debug("Starting HMAC encryption session.");
/* Start a salted, unbound HMAC session with a well-known key (e.g. primary key) as tpmKey, which
rc = sym_Esys_StartAuthSession(
c,
primary,
- ESYS_TR_NONE,
+ bind_key,
ESYS_TR_NONE,
ESYS_TR_NONE,
ESYS_TR_NONE,
return r;
}
-static void hash_pin(const char *pin, size_t len, uint8_t ret_digest[static SHA256_DIGEST_SIZE]) {
- struct sha256_ctx hash;
-
- assert(pin);
-
- sha256_init_ctx(&hash);
- sha256_process_bytes(pin, len, &hash);
- sha256_finish_ctx(&hash, ret_digest);
-
- explicit_bzero_safe(&hash, sizeof(hash));
-}
-
int tpm2_seal(
const char *device,
uint32_t pcr_mask,
if (r < 0)
return r;
- r = tpm2_make_encryption_session(c.esys_context, primary, &session);
+ /* we cannot use the bind key before its created */
+ r = tpm2_make_encryption_session(c.esys_context, primary, ESYS_TR_NONE, NULL, &session);
if (r < 0)
goto finish;
.size = sizeof(hmac_sensitive.sensitive),
.sensitive.data.size = 32,
};
- if (pin) {
- hash_pin(pin, strlen(pin), hmac_sensitive.sensitive.userAuth.buffer);
- hmac_sensitive.sensitive.userAuth.size = SHA256_DIGEST_SIZE;
- }
+ if (pin)
+ hash_pin(pin, strlen(pin), &hmac_sensitive.sensitive.userAuth);
+
assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size);
(void) tpm2_credit_random(c.esys_context);
if (r < 0)
return r;
- r = tpm2_make_encryption_session(c.esys_context, primary, &hmac_session);
- if (r < 0)
- goto finish;
-
- r = tpm2_make_pcr_session(
- c.esys_context,
- primary,
- hmac_session,
- TPM2_SE_POLICY,
- pcr_mask,
- pcr_bank,
- !!pin,
- &session,
- &policy_digest,
- /* ret_pcr_bank= */ NULL);
- if (r < 0)
- goto finish;
-
- /* 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. */
- if (known_policy_hash_size > 0 &&
- memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash, known_policy_hash_size) != 0)
- return log_error_errno(SYNTHETIC_ERRNO(EPERM),
- "Current policy digest does not match stored policy digest, cancelling TPM2 authentication attempt.");
-
log_debug("Loading HMAC key into TPM.");
+ /*
+ * Nothing sensitive on the bus, no need for encryption. Even if an attacker
+ * gives you back a different key, the session initiation will fail if a pin
+ * 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.
+ */
rc = sym_Esys_Load(
c.esys_context,
primary,
- hmac_session, /* use HMAC session to enable parameter encryption */
+ ESYS_TR_PASSWORD,
ESYS_TR_NONE,
ESYS_TR_NONE,
&private,
goto finish;
}
- if (pin) {
- TPM2B_AUTH auth = {
- .size = SHA256_DIGEST_SIZE
- };
+ r = tpm2_make_encryption_session(c.esys_context, primary, hmac_key, pin, &hmac_session);
+ if (r < 0)
+ goto finish;
- hash_pin(pin, strlen(pin), auth.buffer);
+ r = tpm2_make_pcr_session(
+ c.esys_context,
+ primary,
+ hmac_session,
+ TPM2_SE_POLICY,
+ pcr_mask,
+ pcr_bank,
+ !!pin,
+ &session,
+ &policy_digest,
+ /* ret_pcr_bank= */ NULL);
+ if (r < 0)
+ goto finish;
- rc = sym_Esys_TR_SetAuth(c.esys_context, hmac_key, &auth);
- explicit_bzero_safe(&auth, sizeof(auth));
- if (rc != TSS2_RC_SUCCESS) {
- r = log_error_errno(
- SYNTHETIC_ERRNO(ENOTRECOVERABLE),
- "Failed to load PIN in TPM: %s",
- sym_Tss2_RC_Decode(rc));
- goto finish;
- }
- }
+ /* 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. */
+ if (known_policy_hash_size > 0 &&
+ memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash, known_policy_hash_size) != 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+ "Current policy digest does not match stored policy digest, cancelling "
+ "TPM2 authentication attempt.");
log_debug("Unsealing HMAC key.");