Skip to content
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

PCR binding support #15

Open
Gigadoc2 opened this issue Aug 4, 2023 · 15 comments
Open

PCR binding support #15

Gigadoc2 opened this issue Aug 4, 2023 · 15 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@Gigadoc2
Copy link

Gigadoc2 commented Aug 4, 2023

It could be nice to support binding a key to the state of user-selectable PCRs at creation time, e.g. to restrict keys to be used only with some sort of verified boot. This can indirectly be achieved by storing the .tpm file on a filesystem backed by a LUKS partition which itself is then bound to PCR state, but for unencrypted systems it might still be nice to directly support this. Also, the .tpm files could theoretically be leaked into an unverified boot session and then used with incorrect PCR state, natively binding the key within the TPM would mitigate this.

@Foxboron
Copy link
Owner

Foxboron commented Aug 4, 2023

I agree, but the main "issue" I have is that I'd like to figure out how we should re-seal the key.

If we lock the key to a state, we should be able to take that key and say "this is the future state you should unseal towards". This is what enables this feature to work on systems that intend to upgrade.

It could possibly interface a bit with the systemd tooling written to figure out the future PCR states.

But curently this is both an UX issue (how do we document and communicate this) along with a technical one (I don't know how to implement this).

@Foxboron Foxboron added enhancement New feature or request help wanted Extra attention is needed labels Aug 4, 2023
@Gigadoc2
Copy link
Author

Gigadoc2 commented Aug 4, 2023

OK, that is a good point. I just thought about the PCR 0+7 use case when I wrote this (tying the key to secure boot and thus to some CA potentially under your control), where it is not too likely that the PCRs will change. On the other hand, a SSH key like that has - in contrast to the LUKS encryption which I mentally compared it to - no recovery method if the PCRs do need to change, so there really should be an upgrade path. I did not think about this difference when opening the issue.

@Foxboron
Copy link
Owner

Foxboron commented Aug 4, 2023

OK, that is a good point. I just thought about the PCR 0+7 use case when I wrote this (tying the key to secure boot and thus to some CA potentially under your control), where it is not too likely that the PCRs will change.

I don't necessarily think that is true. If you keep a reasonably updated system you need to update dbx a couple of times pr year, which will force you to reseal towards a new set of PCR values. However, as you noted, the path to recovery here is much easier :)

I did not think about this difference when opening the issue.

Thanks for opening it. And do feel free to write down how you envision this to work. I'm open for UX suggestions so I have more opinions to base things off on.

@Gigadoc2
Copy link
Author

Gigadoc2 commented Aug 4, 2023

I am much more lost than you when it comes to a vision how re-sealing might work, I simply did not think about it at all 😅. But should I manage to think of something I will write it down 😄.

@Foxboron
Copy link
Owner

Foxboron commented Aug 4, 2023

I am much more lost than you when it comes to a vision how re-sealing might work, I simply did not think about it at all sweat_smile. But should I manage to think of something I will write it down smile.

You can outline how you think the PCR binding should work :) The resealing can come later.

@Gigadoc2
Copy link
Author

Gigadoc2 commented Aug 4, 2023

You can outline how you think the PCR binding should work :) The resealing can come later.

I probably thought way too naive about this, I just thought of a cmdline similar to systemd-cryptenroll --tpm2-pcrs=0+7, and that it could look at the current value of those PCRs and seal it against those 😅

@Foxboron
Copy link
Owner

Foxboron commented Aug 6, 2023

I probably thought way too naive about this, I just thought of a cmdline similar to systemd-cryptenroll --tpm2-pcrs=0+7, and that it could look at the current value of those PCRs and seal it against those sweat_smile

The systemd syntax for --tpm2-pcrs is actually enough.

It has support to do something like --tpm2-pcrs=0:aabbxxccdd+7:aabbxxccdd123 to override the PCR values, which would allow you to reseal.

So ssh-tpm-keygen --reseal --tpm2-pcrs="0:123123123123" ~/.ssh/id_ecdsa.tpm might be good enough?

@Foxboron
Copy link
Owner

I'm a bit stuck on trying to understand how I should best implement Policy sessions for the keys and also support resealing through ObjectChangeAuth. The ACL model of the TPM is also very confusing.

  1. The Key could have a simple password authentication mechanism, where we seal the passphrase to a policy session with some PCRs. This gives us the benefit of being able to backup the password for the key to ensure it being recoverable.

  2. We just have a policy session towards the key. Less moving parts, but if we seal the key towards a new policy that can never be realized we'll essentially loose the key.

I also don't quite understand how userWithAuth and adminWithPolicy actually works when it comes to these things.

@chrisfenner sorry for poking you, but as I'll probably end up implementing more stuff for google/go-tpm it would be cool to have some opinions what the "correct" way of doing this would be.

@grawity
Copy link

grawity commented Nov 17, 2023

I also don't quite understand how userWithAuth and adminWithPolicy actually works when it comes to these things.

I haven't tinkered with this much, but I spent a while being confused by these as well, and this is as far as I can understand from my notes and the TPM 2.0 spec (part 1, page 129):

  • One is for operations that only require "user" level access (load, sign, all the basic stuff), the other is for operations that require "admin" level access (change auth value; various attestation operations).
  • The defaults for each level are opposite, and the bits would probably be better called userAlsoWithAuth and adminOnlyWithPolicy.
  • If userWithAuth is set, "user" level access can be achieved either through authPolicy or through authValue (password/HMAC). If unset, "user" level access can only be achieved through authPolicy.
  • If adminWithPolicy is set, "admin" level access can be achieved only through authPolicy (and the policy must check the specific PolicyCommandCode). If unset, "admin" level access can be achieved either through authPolicy or authValue.
  • Therefore if you set userWithAuth and don't set adminWithPolicy, you can have both a policy session for general usage and password for recovery (including resealing via ChangeAuth).

In other words, for user-level access:

userWithAuth Policy OK Password OK
Set
Unset

and for admin-level access:

adminWithPolicy Policy OK Password OK
Set
Unset

@Foxboron
Copy link
Owner

Hm, I have sorta been able to write up a thing where even if the key is created with an auth value that has a policy policy with a PolicyPCR thing I was able to change the auth value of the key without presenting any session and a nilled out PasswordAuth. Which seems strange to me, but I need to try and rewrite that test to see if I grasped why that was allowed.

I also found some notes on the unimplemented object auth policy of tpm2-pkcs11, https://github.com/tpm2-software/tpm2-pkcs11/blob/master/docs/tpm2-pkcs11_object_auth_model.md

@Foxboron
Copy link
Owner

Foxboron commented Nov 19, 2023

After batting my head with some new knowledge I've come to a couple of realizations.

The way people usually deal with this is a combination of TPM2_PolicyAuthorize and TPM2_PolicySigned which allows appending of new policies when they are signed by a explicit key.
This would require a secondary signing key just to update the TPM policy, and this seems less ideal? It's unclear to me if we can misuse the ssh key to sign new policies or if this should be a sepeare key. Regardless of this old policies are still valid, so this doesn't help if rollback support is not wanted.

Using TPM2_PolicyAuthorizeNV would allow us to specify a policy stored inside a NV index, and we can update this with future PCR values. I don't think there is any downsides to this approach, expect for occupying a NV index per ssh key, and that doesn't seem scaleable. The number of ssh keys we can generate would be tied to the amount of NV indexes we can occupy.

However, systemd-pcrlock would allow us to piggyback on their sealing policy to support unsealing. However it seems... less ideal as we would be tied to the systemd implementation for this.
https://www.freedesktop.org/software/systemd/man/latest/systemd-pcrlock.html

I am wondering if it's better to produce a authValue that combines the expected PCR values and their checksum with the optional PIN. It seems super hacky and doesn't really seal anything usefull towards the PCR values, but less complex.

@sevenrats
Copy link

check how clevis does it:
https://github.com/latchset/clevis
clevis is a part of latchset can be used to open encrypted devices, provided the named PCR registers have not changed.
I've never heard of a solution that reseals when the PCR's change. Breaking when the PCR's change is the entire point.
Systems that intend to upgrade have to be resealed as part of the upgrade process.

@Foxboron
Copy link
Owner

I'm not too impressed by the clevis implementation either.

See: latchset/clevis#121

@Cydox
Copy link

Cydox commented Apr 3, 2024

I think generally the way to deal with changing PCR values is to not bind against the values, but against a public key who's private key is used to sign PCR policies.

See --tpm2-public-key from systemd-cryptenroll

Maybe systemd-pcrlock offers a way of dealing with this as well (I think it provides rollback protection as well, but I gotta read up on it...)

@Foxboron
Copy link
Owner

Foxboron commented Apr 3, 2024

Sure, but then you are now dealing with two keys.

One key which is the ssh key, and one key to sign the policy.

What do we do with this signing key? Is this shared pr machine, do we store it on the FS or do we also seal this towards the TPM?

Maybe systemd-pcrlock offers a way of dealing with this as well (I think it provides rollback protection as well, but I gotta read up on it...)

I started writing some Go code to wrap systemd-pcrlock but I'm not super sure I want to rely on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants