-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
LUKS header change validation upon sealing and unsealing ops #1625
LUKS header change validation upon sealing and unsealing ops #1625
Conversation
5927fee
to
9d9e8a3
Compare
Simulating a LUKS attack/undesired key slot addition on Heads deployment with DUK setup (qemu with ubuntu deployed as OS): Result: @JonathonHall-Purism please review (wording suggestions welcome as usual) |
@tlaurion Here's what I gather from this PR: Goal: Advise more clearly whether LUKS header(s) have changed, if unsealing the TPM Disk Unlock Key fails. (We already check it - PCR #6. But there's no specific output, user doesn't know why unsealing failed, which could be due to the LUKS header(s), any state in other PCRs, or the passphrase.) Implementation:
I don't see how this solves #1092. I agree we should validate LUKS headers as well for boots without TPM Disk Unlock Key. The goal here is still valid, so #1092 could be addressed separately, but this doesn't address it and shouldn't close it, AFAICT. Regarding implementation - why are the LUKS headers checked in two separate places: kexec-unseal-key / kexec-insert-key? It seems like kexec-insert-key could check it before even prompting for the passphrase, and it could tell you right away. If the headers don't match, should we even bother trying to unlock DUK? Maybe we should assume DUK can't be unlocked then and ask whether to boot with the recovery passphrase? It also seems like 'luksDump.txt' really should exist at this point, so we shouldn't ignore kexec_lukshdr_hash.txt if it doesn't - that would mean something has gone really wrong. (But if kexec_lukshdr_hash.txt doesn't exist due to having been created by a much older Heads, that seems reasonable, and the signatures on /boot cover it to prevent tampering.) I'll post some review comments with some suggestions on details and wording too. |
Regarding the three key messages, how about the following wording:
Original for comparison:
I get that the LUKS header contains other things besides the volume key and key slots, but virtually everything relates in some way to the keys (e.g. changing the cipher changes the way the key is applied to the data). This differentiates it from the encrypted disk data, which we do not check and could still have been tampered (though not in a predictable manner if the attacker does not know a key). As usual I don't think we should require the user to know what a LUKS container is, what its header is, or what individual files in /boot mean to use Heads, which led me to the wording above. |
initrd/bin/kexec-insert-key
Outdated
@@ -57,6 +57,9 @@ tpmr extend -ix 4 -ic generic || | |||
# Check to continue | |||
if [ "$unseal_failed" = "y" ]; then | |||
confirm_boot="n" | |||
if diff "$(dirname $INITRD)/kexec_lukshdr_hash.txt" /tmp/luksDump.txt > /dev/null 2>&1; then | |||
echo "Headers of LUKS containers to be unlocked via TPM Disk Unlock Key passphrase did not change since sealed in TPM." |
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.
Recap.
When sealing DUK, PCR6 is extended with LUKS header backup prior of the resulting measurements sealed into seperate TPM nvram+DUK passphrase.
So here, by attempting to unseal TPM nvram DUK passphrase protected region, two things could happen:
- DUK won't unseal because DUK passphrase is wrong, while measurements are good
- DUK won't unseal because measurements are wrong, while DUK passphrase is good (but cannot know because measurements+passphrase needs to be as in sealed state
So here, if undeal fails, we improve upon @root-hardenedvault PR by reporting not only diff of current header vs detached signed header backup that was given only after the 3 bad useal attempts. As of today, DUK would'nt unseal, but the user would not know that its because of the LUKS header having changed.
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.
Also a few detailed review comments - but some of the details may change if the logic is moved around as I suggested a couple of comments up, let me know what you think
@JonathonHall-Purism I think #1092 is badly named and would go forward changing its name since tits content and goals in description are all fixed by this PR. As for having LUKS header verified outside of DUK, it would require refactoring with that goal in mind. I think validating LUKS header could be done independently without it being unsealed, but as of now, this is never the case. |
9d9e8a3
to
97328b2
Compare
@JonathonHall-Purism addressed review, opened #1629 and corrected name of #1092 which this PR should still close. Will test under qemu now |
@tlaurion Did you see this part of the comment above? (Not trying to be snarky, just might have been overlooked)
Would like to know your thoughts on these, did not see anything in the comments above 🤔 |
initrd/bin/kexec-insert-key
Outdated
@@ -57,6 +57,9 @@ tpmr extend -ix 4 -ic generic || | |||
# Check to continue | |||
if [ "$unseal_failed" = "y" ]; then | |||
confirm_boot="n" | |||
if cmp -s "$bootdir/kexec_lukshdr_hash.txt" /tmp/luksDump.txt > /dev/null 2>&1; then | |||
echo "Encrypted disk keys(s) have not been changed since sealed in TPM Disk Unlock Key" |
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.
IMO: keys
instead of keys(s)
(3x). I get that the idea is to permit the possibility that there's only one key, but I think key(s)
is unnecessarily awkward. (keys(s) has two Ss too, reads like "Hobbitses" to me 😅 )
I think I'd only really use (s)
when we're asking the user something and it needs to be abundantly clear that this is the option for one or more "thing(s)" - and there's no better way to rewrite the prompt, etc. Otherwise it could be unclear what to do for exactly one "thing".
I think the meaning is clear and we're watering down the real point by making it more awkward. It doesn't agree with have
as written either, etc.
initrd/bin/kexec-unseal-key
Outdated
warn "Unable to unseal LUKS Disk Unlock Key from TPM" | ||
if [ -e /boot/kexec_lukshdr_hash.txt ] && [ -e /tmp/luksDump.txt ]; then | ||
if ! cmp -s /boot/kexec_lukshdr_hash.txt /tmp/luksDump.txt > /dev/null 2>&1; then | ||
warn "Encrypted disk keys(s) have changed since sealed in TPM Disk Unlock Key. You might want to investigate." |
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 like the precision of specifying that they have not been changed relative to a specific point in time (sealing the TPM Disk Unlock Key). But IMO "You might want to investigate." is unnecessarily vague, we can say why they may want to investigate.
So I'd suggest:
Encrypted disk keys have changed since the TPM Disk Unlock Key was sealed. If you did not make this change, the disk may be compromised.
Answer was at #1625 (comment).
@JonathonHall-Purism still want the refactoring? Security is chain of trust here where higher level is TPM and then files are used to give context. I prefer to trust TPM here and give context on unseal failure more then use tpm file creating without TPM. |
69de7a3
to
6896539
Compare
initrd/bin/kexec-insert-key
Outdated
#TODO: remove "+++" with boot info helper when added, same with "!!!" currently for info. | ||
fi | ||
else | ||
warn "Could not check for tampering of Encrypted disk keys(s)" |
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.
warn "Could not check for tampering of Encrypted disk keys(s)" | |
warn "Could not check for tampering of Encrypted disk keys" |
Please change keys(s)
to keys
here
6ab4801
to
8f77408
Compare
Has been refactored upon request. Now luks headers hashes compared before unsealing attempt. |
@tlaurion I don't see any changes to any initrd scripts now, were they lost in a force-push? |
Ease cleaning up everything. IMOH better then real.clean target Signed-off-by: Thierry Laurion <[email protected]>
…sk Unlock Key. Fixes linuxboot#1092. Supersedes linuxboot#1093 - Cherry-picks ed1c23a (credit to @hardened-vault) thank you!) - Addresses and correct self-review under linuxboot#1093 (@hardened-vault: you don't answer often here!) - kexec-unseal-key: Warn a user who attempts to default boot while his Disk Unlock Key passphrase fails to unseal because LUKS headers changed. (linuxboot#1093 (comment)) - kexec-seal-key: Identical as in ed1c23a - kexec-add-key: Tell the user that the Headers did not change when changing TPM released Disk Unlock Key (Through changing default boot at Options->Boot Options -> Show OS boot options: select a new boot option and set a Disk Unlock Key in TPM, accept to modify disk and sign /boot options) - Here, we cancel the diff output shown on screen linuxboot#1093 (comment) - And we change the warning given to the user to past tense "Headers of LUKS containers to be unlocked via TPM Disk Unlock Key passphrase did not change." Signed-off-by: Thierry Laurion <[email protected]>
…erbiage, remove irrelevant DEBUG trace under kexec-unseal-key TODO: - $(pcrs) call sometimes fail in DEBUG call, outputting too many chars to be inserted in kmesg. Call removed here since redundant (PCR6 already extended with LUKS header) - Notes added for TPM2 simplification over TPM1 in code as TODO Signed-off-by: Thierry Laurion <[email protected]>
8f77408
to
ebbccba
Compare
…ior of TPM unsealing ops move code from kexec-unseal-key to kexec-insert-key, address code review and apply verbiage suggestion changes Signed-off-by: Thierry Laurion <[email protected]>
ebbccba
to
fb5cbf4
Compare
@JonathonHall-Purism Sorry about the past mess in commits (and thanks for the pointer). Should be clean now... |
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.
LGTM, thanks @tlaurion
Edit: UX change in screenshots at #1625 (comment)
Fixes #1092
Supersedes #1093
Rework of ed1c23a (credit to @root-hardenedvault) thank you!)
Addresses and correct self-review under Make it possible to report headers of which LUKSes to be unlocked via TPM change #1093 (@root-hardenedvault : you don't answer often here!)
kexec-unseal-key: Warn a user who attempts to default boot while his Disk Unlock Key passphrase fails to unseal because LUKS headers changed (Make it possible to report headers of which LUKSes to be unlocked via TPM change #1093 (comment))EDIT: everything move to kexec-insert-key to check header checksum part of detached signed hash digest, before attempting TPM DUK unseal op.kexec-add-key: Tell the user that the Headers did not change when changing TPM released Disk Unlock Key(Through changing default boot at Options->Boot Options -> Show OS boot options: select a new boot option
and set a Disk Unlock Key in TPM, accept to modify disk and sign /boot options)
Here, we cancel the diff output shown on screen Make it possible to report headers of which LUKSes to be unlocked via TPM change #1093 (comment)And we change the warning given to the user to past tense "Headers of LUKS containers to be unlocked via TPM Disk Unlock Key passphrase did not change." The user knows that unsealing error is not due to LUKS header having changed.Workflow in pictures at LUKS header change validation upon sealing and unsealing ops #1625 (comment)