Skip to content

Commit

Permalink
tpm2: instead of adjusting authValue trailing 0(s), trim them as requ…
Browse files Browse the repository at this point in the history
…ired by tpm spec

To keep compatibility with any existing object authValues with trailing 0's,
change tpm2_get_pin_auth() to trim trailing 0's, which is what the TPM
implementation will do. This should retain compatibility with any existing
authValues that contain trailing 0's.

Note that any existing authValues with trailing 0's are unlikely to have worked
in the way that systemd uses them in object sealing, which is as a bind key for
the encryption (and policy) session. However, it is better to be compatible
with the TPM spec (and implementations) even if previously created objects that
are affected may not have worked.

Fixes: systemd#28414
  • Loading branch information
ddstreet authored and bluca committed Jul 21, 2023
1 parent 73d6f20 commit 63477a7
Showing 1 changed file with 31 additions and 7 deletions.
38 changes: 31 additions & 7 deletions src/shared/tpm2-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2248,8 +2248,36 @@ int tpm2_digest_many_digests(
* the TPM specification Part 1 ("Architecture") section Authorization Values (subsection "Authorization Size
* Convention") states "Trailing octets of zero are to be removed from any string before it is used as an
* authValue". Since the TPM doesn't know if the auth value is a "string" or just a hash digest, any hash
* digest that randomly happens to end in 0 must have the final 0 changed, or the TPM will remove it before
* using the value in its HMAC calculations, resulting in failed HMAC checks. */
* digest that randomly happens to end in 0 must have the final 0(s) trimmed.
*
* This is required at 2 points. First, when setting the authValue during creation of new sealed objects, in
* tpm2_seal(). This only applies to newly created objects, of course. Second, when using a previously
* created sealed object that has an authValue set, we use the sealed objects as the session bind key. This
* requires calling SetAuth so tpm2-tss can correctly calculate the HMAC to use for the encryption session.
*
* TPM implementations will perform the trimming for any authValue for existing sealed objects, so the
* tpm2-tss library must also perform the trimming before HMAC calculation, but it does not yet; this bug is
* open to add the trimming: https://github.com/tpm2-software/tpm2-tss/issues/2664
*
* Until our minimum tpm2-tss version contains a fix for that bug, we must perform the trimming
* ourselves. Note that since we are trimming, which is exactly what a TPM implementation would do, this will
* work for both existing objects with a authValue ending in 0(s) as well as new sealed objects we create,
* which we will trim the 0(s) from before sending to the TPM.
*/
static void tpm2_trim_auth_value(TPM2B_AUTH *auth) {
bool trimmed = false;

assert(auth);

while (auth->size > 0 && auth->buffer[auth->size - 1] == 0) {
trimmed = true;
auth->size--;
}

if (trimmed)
log_debug("authValue ends in 0, trimming as required by the TPM2 specification Part 1 section 'HMAC Computation' authValue Note 2.");
}

static int tpm2_get_pin_auth(TPMI_ALG_HASH hash, const char *pin, TPM2B_AUTH *ret_auth) {
TPM2B_AUTH auth = {};
int r;
Expand All @@ -2261,11 +2289,7 @@ static int tpm2_get_pin_auth(TPMI_ALG_HASH hash, const char *pin, TPM2B_AUTH *re
if (r < 0)
return r;

assert(auth.size > 0);
if (auth.buffer[auth.size - 1] == 0) {
log_debug("authValue digest ends in 0 which the TPM will remove and cause HMAC authorization failures, adjusting.");
auth.buffer[auth.size - 1] = 0xff;
}
tpm2_trim_auth_value(&auth);

*ret_auth = TAKE_STRUCT(auth);

Expand Down

0 comments on commit 63477a7

Please sign in to comment.