Re: Discussion about using NV indexes for kernel properties like localities and PCRs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2023-12-04 at 10:20 +0100, Lennart Poettering wrote:
> On Fr, 01.12.23 17:23, James Bottomley
> (James.Bottomley@xxxxxxxxxxxxxxxxxxxxx) wrote:
[...]
> > > > I'm bringing this up for discussion now, in case anyone has a
> > > > better idea or wants to add nuances (like measuring the
> > > > creation to a real PCR and adding an event log to measured
> > > > boot) before I (or someone else) look into coding it up.
> > > 
> > > Why would that be necessary though? The "name" of an nvindex pins
> > > the access policy of the nvindex.
> > 
> > I assume you're talking about using TPM2_PolicyNameHash coupled
> > with TPM2_PolicyNV?  That pins to NV index value and name, but the
> > problem is that still doesn't necessarily solve the deletion
> > problem (see below).
> 
> I was thinking TPM2_PolicyAuthorizeNV and similar things too. They
> generally pin NVs by "name".

Heh, well, you have to be careful with that one as I just discovered
with NV PINs.  Most of the TPMs I have in my system actually comply
with rev 116.  NV PIN was added in rev 124 and PolicyAuthorizeNV in rev
132 which means they're not universally supported by TPM2 systems.

> > >  And nvindexes are always created uninitialized, thus to to
> > > initialize one you just created (i.e. execute the first write to
> > > it) you must be able to fulfill the write policy set for it. But
> > > if you can do that, then why bother with deleting/recreating them
> > > in the first place?
> > 
> > Well, I wasn't really considering using a policy for the index, I
> > was thinking of using the index for other policies (like key
> > release). However, even though you can have a policy for read and
> > write, you can't have a policy for delete unless you have access to
> > the platform hierarchy (which the problem statement above explained
> > is getting increasingly unlikely), so your index can still be reset
> > by deleting and recreating it (even if it is recreated with the
> > same policy). You're right that such an index would be detectably
> > uninitialized unless whoever deleted it can also write to it.
> 
> Yes, deletion doesn't really matter as long as the write policy for
> the NV is properly chosen so that whoever deletes/recreates the NV
> cannot write to it.
> 
> > >  And if you set a different access policy on them then the "name"
> > > of the nvindex would change, and it would become useless in all
> > > references from other objects/quotes/…
> > 
> > Right but to take a NV Extend index, you're saying I can delete it
> > and recreate it with exactly the same policy and attributes (so
> > same name) but then to prevent me placing malicious entries in it,
> > the policy has to be narrowly crafted to prevent malicious actors
> > extending it (because then policy can't tell the difference between
> > that recreated index and the original one).  I've thought about
> > this, but haven't ever really been able to come up with usable
> > policies, because all such policies end up requiring either a
> > privileged locality to write from or a shared secret between the
> > TPM and the trusted writer.
> 
> So my understanding is that you want fake PCRs, i.e. NV indexes that
> are world-readable, and world-extendable, and cannot be reset,
> correct?

Yes, effectively a simple extension of the PCR system beyond 24 indexes
for anyone to use.

> So a write policy like this should work, no:
> 
>     A TPM2_PolicyOR with three branches:
>         1. TPM2_PolicyCommandCode(TPM2_NV_Write) +
>            TPM2_PolicyNvWritten(writtenSet=false) +
>            TPM2_PolicySigned(…)
>         2. TPM2_PolicyCommandCode(TPM2_NV_Write) +
>            TPM2_PolicyNvWritten(writtenSet=true)
>         3. TPM2_PolicyCommandCode(TPM2_NV_Read)
> 
> (where "+" is suposed to mean AND...)

Well, no, that would mean the entity doing the create (first write) has
to be able to sign the command.  That requires a permanent secret (the
private key).  The problem I have is that I want to do this in the
kernel.  The kernel can generate ephemeral secrets but not permanent
ones that last across a boot and it certainly can't usefully (without
leaking) carry persistent private keys, so whatever scheme we come up
with for the kernel can't code a policy that contains a long lived
secret.  That's why I went for restricted creation and deletion: The
kernel can create the index and populate it with a random auth known
only to it and no-one else can delete and recreate.  Thus we have an
index that can be mentioned in PolicNV of a sealed object meaning that
only the kernel can unseal it.  For the NV Extend Indexes it means
they're wold readable and writable but usable by anyone and possessing
a no reset guarantee.

> So the first branch covers initialization. The branch first checks
> for *Write* access, and whether the NV hasn't been written yet. It
> then combines that with PolicySigned policy whith some public key.
> The idea would be to use a key pair here that you generate for this
> purpose only and throw it away after initialization. You could use
> other policies here too i guess. Important is that you use a policy
> here that only you as the creator can fulfill, and that fully pins
> all authentication objects you use, like PolicySigned does.
> 
> The second branch covers later extensions, all it checks is that the
> PCR is already initialized, and then makes no further restructions.
> 
> The third branch covers reading, and makes no restrictions beyond
> that.
> 
> I haven't tested the above, but it was my understanding that this is
> how you'd do it.
> 
> Crucial in all of the above is that you reference the NV indexes
> afterwards by their full name (thus also by their policy, which pins
> the public key of TPM2_PolicySigned), instead just by their numeric
> handle. Because if you'd ref them by their numeric handle only, then
> of course anyone can recreate them with a different policy without
> you noticing it. The important part is that you assign a policy to
> the NV index that ensures only you could have initialized them,
> because they pin some resource only you have control over.
> 
> In upcoming systemd 255 we now provide an IPC API for local clients
> to measure stuff into PCRs, and write a TCG-CEL record about it
> automatically. I was looking into extending that to also allow
> writing NV-index based "fake PCRs" and the above is basically what I
> had in mind to implement that.
> 
> But admittedly I am talking a bit out of my ass here, since I did not
> in fact implement the above. But I don't see why it wouldn't work.

I think it could work.  However to be effective in the above
PolicySigned, the entity creating the NV index will have to sign the
nonceTPM, meaning systemd will have to have the private key ... how
does that get provisioned? (it seems like a similar problem to
provisioning the kernel with a private key)

> 
> > > This logic is explicitly mentioned in that tpm book btw, it took
> > > me a while to grok how great that concept is, since it basically
> > > means you don't have to be concerned about removed/readded
> > > nvindexes at all.
> > 
> > Which TPM book is this?
> 
> "A practical guide to TPM 2.0". The one that always shows up in your
> google searches...

Thanks ... I didn't know anyone had written an actual book about the
TPM. I usually just get my insights from the architecture documents
(and how they change).

James





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux