Add text to Attestation on using a WK (credit: Erik Larsson)

This commit is contained in:
Nicolas Williams 2021-06-03 17:35:56 -05:00
parent 93af1b4003
commit 3017b7eae9

View file

@ -780,54 +780,103 @@ for secret transport. This list is almost certainly not exhaustive.
[`TPM2_MakeCredential()`](/TPM-Commands/TPM2_MakeCredential.md) and [`TPM2_MakeCredential()`](/TPM-Commands/TPM2_MakeCredential.md) and
[`TPM2_ActivateCredential()`](/TPM-Commands/TPM2_ActivateCredential.md) [`TPM2_ActivateCredential()`](/TPM-Commands/TPM2_ActivateCredential.md)
can use any kind of loaded object with a private area as the "credential are a form of limited asymmetric encryption (`TPM2_MakeCredential()`)
object name" and "credential object handle" arguments of the two calls, and asymmetric decryption (`TPM2_ActivateCredential()`) subject to the
respectively. During attestation we need to use an AK for this object sender's choice of authorization. The details are explained
due to the need to have a signature key for [here](/TPM-Commands/TPM2_MakeCredential.md) and
[`TPM2_Quote()`](/TPM-Commands/TPM2_Quote.md), and we want that AK to [here](/TPM-Commands/TPM2_ActivateCredential.md). Basically, there are
have `stClear` set, meaning that it is ephemeral, rendering the outputs two TPM key objects involved:
of `TPM2_MakeCredential(EKpub, AKname, secrets)` ephemeral as well,
therefore `TPM2_MakeCredential(EKpub, AKname, secrets)` must be called
on each attestation, which means the `secrets` also have to be ephemeral
or else must be stored in cleartext on the attestation server.
However, we can use a key that does not have `stClear` set as the - a transport key (typically the `EK`),
credential object. A long-term key that survives reboots. - and an authorization key (typically an `AK`)
> We'd like to use the EK itself, however, and the caller of `TPM2_MakeCredential()` must specify the public part
> [that is not actually possible](https://github.com/tpm2-software/tpm2-tools/issues/1883) of the transport key and the
> because the `activateHandle` argument to [name](/Intro/README.md#Cryptographic-Object-Naming) of the
> [`TPM2_ActivateCredential()`](/TPM-Commands/TPM2_ActivateCredential.md) authorization key, along with a small secret to transport. The caller
> requires `ADMIN` role, and on most TPMs the auth policy for the EK of `TPM2_ActivateCredential()` must then provide the handles for those
> does not provide any way to satisfy it for this usage. Though in two key objects and the outputs of `TPM2_MakeCredential()` in order to
> principle this should be possible, and it would be very convenient if extract the small secret. Typically the small secret is an AES key for
> it was. encrypting larger secrets.
So for this approach one has to create a long-term attestation key that So if we can store the outputs of `TPM2_MakeCredential()` long-term so
we shall call the `LTAK`, and then the server can store that the client can activate over multiple reboots, then we have a way
`TPM2_MakeCredential(EKpub, LTAKname, secrets)` without knowing the to deliver secrets to the client.
secrets.
The client has to use We'll discuss two ways to do this:
[`TPM2_CreatePrimary()`](/TPM-Commands/TPM2_CreatePrimary.md) or
[`TPM2_CreateLoaded()`](/TPM-Commands/TPM2_CreateLoaded.md) in order to - use a `WK` -- a universally well-known key (thus WK, for well-known)
deterministically create the same `LTAK` (again, without the `stClear`
attribute), else if it uses Since the `WK`'s private area is not used for any cryptography in
[`TPM2_Create()`](/TPM-Commands/TPM2_Create.md) then it must store the `TPM2_MakeCredential()`/`TPM2_ActivateCredential()`, it can be a key
key save file somewhere (possibly in the attestation server!) or make that everyone knows.
the key object persistent.
Note that the `WK`'s public area can name arbitrary an auth policy,
and `TPM2_MakeCredential()` will enforce it.
E.g., the `WK` could be the all-zeros AES key. Its policy could be
whatever is appropriate for the organization. For example, the
policy could require that some non-resettable application PCR have
the value zero so that extending it can disable use of
`TPM2_MakeCredential()` post-boot.
- use an `LTAK` -- a long-term `AK`
I.e., an `AK` that lacks the `stClear` attribute, and _preferably_
created deterministically with either
[`TPM2_CreateLoaded()`](/TPM-Commands/TPM2_CreateLoaded.md) or
[`TPM2_CreatePrimary()`](/TPM-Commands/TPM2_CreatePrimary.md).
> Note that the `LTAK` need not be a primary.
> If the `LTAK` were created with
> [`TPM2_Create()`](/TPM-Commands/TPM2_Create.md) then the key's saved
> context file would have to be stored somewhere so that it could be
> loaded again on next boot with
> [`TPM2_Load()`](/TPM-Commands/TPM2_Load.md). Whereas creating it
> deterministically means that it can be re-created every time it's
> needed using the same hiercarchy, template, and entropy as
> arguments to `TPM2_CreatePrimary()` or `TPM2_CreateLoaded()`
Note that the `AK`'s public area can name arbitrary an auth policy,
and `TPM2_MakeCredential()` will enforce it.
The best option here is to use a `WK` because using an `LTAK` would
require recording its public key in the device's enrolled attestation
state, which would complicate enrollment, whereas the `WK`, being
well-known and the same for all cases, would not need to be recorded in
server-side attestation state.
> One might like to use the `EK` as the `activateHandle`. Sadly, this
> is not possible.
> While `TPM2_MakeCredential(EKpub, EKname, input)` works,
> `TPM2_ActivateCredential(EK, EK, credentialBlob, secret)` does not
> and cannot.
>
> The reason for this is that `TPM2_ActivateCredential()` requires
> `ADMIN` role for the `activateHandle`, and since the `EK` has
> `adminWithPolicy` attribute set and its policy doesn't have the
> `TPM_CC_ACTIVATECREDENTIAL` command permitted, the call must fail.
>
> Credit for the `WK` idea goes to [Erik > Larsson](https://developers.tpm.dev/chats/new?user_id=4336638).
Normally during attestation we want to use an `AK` with `stClear` set so
that each boot forces the client to use a new one. However, for sending
secrets to the client via `TPM2_MakeCredential()` /
`TPM2_ActivateCredential()` we really need need the `activateHandle`
object to not have `stClear` set.
For this approach then, the best solution is to use a `WK`.
``` ```
<having previously successfully enrolled
and saved
long_term_Credential =
TPM2_MakeCredential(EKpub, LTAKname, secrets_key) ||
Encrypt_secrets_key(long_term_secrets)>
CS0: timestamp, AKpub, PCRs, eventlog, CS0: timestamp, AKpub, PCRs, eventlog,
TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data}) TPM2_Quote(AK, PCRs, extra_data)=Signed_AK({hash-of-PCRs, misc, extra_data})
SC0: {TPM2_MakeCredential(EKpub, AKname, session_key), SC0: {TPM2_MakeCredential(EKpub, AKname, session_key),
Encrypt_session_key(long_term_Credential)} Encrypt_session_key(long_term_Credential)}
where
long_term_Credential = TPM2_MakeCredential(EKpub, WKname, secrets)
``` ```
New secrets can be added at any time without interaction with the New secrets can be added at any time without interaction with the
@ -846,12 +895,10 @@ The schema for storing secrets transported this way would be:
"current_operating_system_profiles": ["OSProfile1", "OSProfile2", "..."], "current_operating_system_profiles": ["OSProfile1", "OSProfile2", "..."],
"previous_PCRs": "<...>", "previous_PCRs": "<...>",
"proposed_PCRs": "<...>", "proposed_PCRs": "<...>",
"ak_cert_template": "<AKCertTemplate>",
"resetCount": "<resetCount value from last quote>", "resetCount": "<resetCount value from last quote>",
"secret store and transport fields":"vvvvvvvvvvvvvvvvvv", "secret store and transport fields":"vvvvvvvvvvvvvvvvvv",
"LTAKname": "<...>",
"secrets": ["<MakeCredential_0>", "<MakeCredential_1>", "..", "<MakeCredential_N>"] "secrets": ["<MakeCredential_0>", "<MakeCredential_1>", "..", "<MakeCredential_N>"]
"secrets_backup": ["<RSA_Encrypt_to_backup_key(...)", "..."], "secrets_backup": ["<RSA_Encrypt_to_backup_key(...)", "..."],
} }