Re: One question about trusted key of keyring in Linux kernel.

From: James Bottomley
Date: Mon Dec 02 2019 - 22:12:16 EST


On Tue, 2019-12-03 at 02:11 +0000, Zhao, Shirley wrote:
> Thanks so much for you feedback, James.
> And glad to hear that the API will be made more friendly.
>
> But I have a little confused about the call stack.
> From the document, https://github.com/torvalds/linux/blob/master/Docu
> mentation/security/keys/trusted-encrypted.rst and
> https://github.com/zfsonlinux/dracut/tree/master/modules.d/97masterke
> y, the trusted key is a random number and generated by TPM2.0 and
> sealed with TPM2.0 2048 RSA key.

Well, um, that document seems to be based on TPM 1.2 ... a lot of what
it says isn't quite true for TPM 2.0. For instance all TPM 2.0 primary
keys come with a symmetric component, so the sealed data in TPM 2.0 is
actually symmetrically encrypted to a primary key.

> The 2048 RSA key is generated by tpm2_createprimary, and it can be
> got by the TPM2.0 handle, just the "keyhandle" used in the following
> keyctl command.
> $ keyctl add trusted kmk "new 32 keyhandle=0x81000001 hash=sha256
> policydigest=`cat pcr7.policy`" @u

The problem TPM 2.0 has is that most of them can't generate prime
numbers very fast, so even through the kernel could generate the RSA
primary, it would usually take far too long, so if you want to use a
RSA primary you have to pre-generate one and place it in NV storage;
the TCG recommends doing this at handle 81000001, which is what you
have above. However, the more modern way is to derive an elliptic
curve key primary key every time ... EC keys can be generated by most
TPMs in 10s of milliseconds, so the primary doesn't need to be present
in NVRAM.

THe kernel should be using the EC primary method for the parent. The
only exception is when the key has an intermediate parent, and then it
can be simply loaded from a file.

> If reboot, to re-load the trusted key back to keyring, just call
> tpm2_unseal is enough, don't need to call tpm2_load to load the
> TPM2.0 2048 RSA key.
> If the trusted key is also protected by policy, then the policy will
> be checked during tpm2_unseal.
>
> After check the source code, the call stack is mostly like:
> SYSCALL_DEFINE5(add_key,...) --> key_create_or_update() -->
> __key_instantiate_and_link() --> trusted_instantiate() -->
> tpm2_unseal_trusted() --> tpm2_unseal_cmd().

Well, the API is confusing, but the code seems to imply the parent
should be present somehow. A key in NVRAM, like 81000001 is always
present so it doesn't need to be loaded it can just be used as is.

> Another problem here is, to build the policy to unseal the key, it
> need to start an policy session, and transfer the session handle to
> TPM2.0 unseal command.
> In my keyctl command, I use tpm2.0 command to start the session and
> get the handle, put it into the keyctl command like:
> keyctl add trusted kmk "load `cat kmk.blob` keyhandle=0x81000001
> policyhandle=0x3000000" @u

As I said, using policy handles simply won't scale, so we need to use
the actual policy instead ... thus the policy should be passed into the
kernel as part of the trusted key and the kernel itself would generate
a policy session from the policy statements ... this approach is aready
proven to be useful and functional in the tpm2 openssl engine code.

James