-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tpm2: add tpm2_get_pin_auth() #28414
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2244,6 +2244,34 @@ int tpm2_digest_many_digests( | |
return tpm2_digest_many(alg, digest, iovecs, n_data, extend); | ||
} | ||
|
||
/* This hashes the provided pin into a digest value, but also verifies that the final byte is not 0, because | ||
* 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. */ | ||
static int tpm2_get_pin_auth(TPMI_ALG_HASH hash, const char *pin, TPM2B_AUTH *ret_auth) { | ||
TPM2B_AUTH auth = {}; | ||
int r; | ||
|
||
assert(pin); | ||
assert(ret_auth); | ||
|
||
r = tpm2_digest_buffer(hash, &auth, pin, strlen(pin), /* extend= */ false); | ||
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; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, i don't fully grok why this is necessary. can you explain? I mean, as long as everyone drops the trailing NUL bytes we should be fine, no? or are you saying some code does and other code does not? can you be more specific on that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see #27716 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still not getting this. As long as the zeroes at the end are dropped systematically things should always result in the same state in the TPM, hence should be OK. Why specifically does that trigger any issue? can you elaborate for somebody a bit thick, like me? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. right, while the tpm drops the trailing 0, tpm2-tss doesn't, and so when tpm2-tss makes the hmac calculations they don't match what the tpm is expecting. If/when tpm2-tss is fixed, we could drop this, but of course we'd then need to set a minimum tpm2-tss version (that includes the fix). @williamcroberts do you happen to know if there's an open bug in tpm2-tss for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, it's possible there are some tpms that dont drop the trailing 0 - as i noted in the issue, the spec is horribly ambiguous on this point; it says:
but then also
Without acknowledging that a hash digest can also end in a 0. Basically, the safest thing to do to ensure all parts work correctly is to never, ever use a auth value that ends in a 0. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
right, but tpm2-tss doesnt trim those trailing null bytes, which is what causes the HMAC errors... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see in the spec it does have a buried note that clarifies; in HMAC Computation under authValue there is "NOTE 2": So yeah, this does seem like tpm2-tss should strip trailing 0's (probably in Esys_TR_SetAuth)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Ahh OK yeah I see that linked issue now, makes sense. I filed a bug in tpm2-tss: tpm2-software/tpm2-tss#2664. However, the code here needs to strip all of them, just not one. But you can just wrap the calls to Esys_TR_SetAuth to essentially right trim the array and re-adjust the auth buffer size field, then you won't need to set a minimum ESYS version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ddstreet I can't reprod with the tpm2-tss stack, but I did file a bug 2664 and Juergen is looking into it on our side. However, can I nack this patch so it doesn't get released and could you respin a fix to address a passphrase ending in more than one zero byte (ie foopass\0\0\0\0\0\0\0), which is possible. It needs to rtrim all 0s. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
since we're using a hash digest, the actual text passphrase doesn't really matter, right? And also we shouldn't need to handle any 0's other than the last one, since we're not actually trimming it; we are adjusting it (from 0->0xff). So any 0's before it should be handled normally. No? |
||
|
||
*ret_auth = TAKE_STRUCT(auth); | ||
|
||
return 0; | ||
} | ||
|
||
static int tpm2_set_auth(Tpm2Context *c, const Tpm2Handle *handle, const char *pin) { | ||
TPM2B_AUTH auth = {}; | ||
TSS2_RC rc; | ||
|
@@ -2257,7 +2285,7 @@ static int tpm2_set_auth(Tpm2Context *c, const Tpm2Handle *handle, const char *p | |
|
||
CLEANUP_ERASE(auth); | ||
|
||
r = tpm2_digest_buffer(TPM2_ALG_SHA256, &auth, pin, strlen(pin), /* extend= */ false); | ||
r = tpm2_get_pin_auth(TPM2_ALG_SHA256, pin, &auth); | ||
if (r < 0) | ||
return r; | ||
|
||
|
@@ -3228,7 +3256,7 @@ int tpm2_seal(const char *device, | |
CLEANUP_ERASE(hmac_sensitive); | ||
|
||
if (pin) { | ||
r = tpm2_digest_buffer(TPM2_ALG_SHA256, &hmac_sensitive.userAuth, pin, strlen(pin), /* extend= */ false); | ||
r = tpm2_get_pin_auth(TPM2_ALG_SHA256, pin, &hmac_sensitive.userAuth); | ||
if (r < 0) | ||
return r; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you might as well drop the first argument. We chose the hash function ourselves here, and hence we can just hardcode it inside this function, no need to pass it in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was trying to leave is as easy as possible to allow using a different hash alg in the future, and reduce the number of places we have sha256 hardcoded.