[tpm2] Re: Help implementing "OR" PCR policy using C lib

Millsap, Michael G <michael.g.millsap at intel.com>
Newsgroups dev.linux.lists.tpm2
Message-ID <DM4PR11MB55655FFCEDF15A5CD67B1812A98A9@DM4PR11MB5565.namprd11.prod.outlook.com>
The problem I have with PolicyauthorizeNV is how do I protect it from unauthorized change in a headless system? The platform is a headless, edge system. What’s to stop an attacker from booting off a USB stick, changing the authorized digest in the NV, then rebooting and gaining access to the secret which allows them to decrypt the drive?

I’m thinking that rather than using PolicyauthorizeNV or PolicyOR, I just create a new update sealed blob, which is sealed against the expected updated PCR digest and contains a new LUKS passphrase. On boot, if the original blob fails to unseal, I check for an update blob. If there is a validate update blob, I delete the original blob, delete the original LUKS passphrase keyslot, and rename the update blob to the current blob. This feels pretty straight forward and protects against rollback.

-Mike

From: David Challener <david.c.challener(a)gmail.com>
Sent: Saturday, October 30, 2021 8:02 AM
To: Roberts, William C <william.c.roberts(a)intel.com>
Cc: Millsap, Michael G <michael.g.millsap(a)intel.com>; tpm2(a)lists.01.org
Subject: [tpm2] Re: Help implementing "OR" PCR policy using C lib

PolicyauthorizeNV is orobably a better way to change an authorization. A policy is place in an NV index. Then policyauthorizeNV points to that index. Only the person with authorization to write the index can change it. Caution: writing the NV index should requure a policysign to avoid the remove index recreate index attack.

On Fri, Oct 29, 2021, 2:06 PM Roberts, William C <william.c.roberts(a)intel.com<mailto:william.c.roberts(a)intel.com>> wrote:
The best way to enable firmware updates is to use a mutable policy, either through policy signed (ie trust any policy signed with this key[1]) or through policyauthorizenv (Allows for mutable policies by referencing an NV Index [2]). The tpm2-tools have full examples in the man pages, and you can just play with the tools and then port it to ESYS. The tests in tpm2-tss also have examples of all the ESYS calls, but they are often times a bit contrived.

When trying to create an OR policy, you essentially have:

session A --> Policy X --> Policy Y .... --> Get Digest = Digest A

session B --> Policy Q --> Policy W .... --> Get Digest = Digest B

PolicyOR (Digest A, Digest B)  = Final Digest

Every policy event you run a session is an AND operation. So a policy can have 1 or more statements. You then take the digests of all those and feed it to the policy OR
command which gives you the final digest that's used for policy value for an object.

To satisfy the policy, you must run the commands on at least one branch that evaluates to true and pass all the same hashes back to policy OR to satisfy the policy. Its a bit awkward. So generally, you want to retain the policy hashes for each or branch, and then know which one you want to try or compute the hashes without using
the TPM and only use the TPM for the branch that is going to be true... But it also depends on commands that are deferred evaluation (ie you don't know that fail until you try and auth with the policy) or ones that fail at command time. So, figuring out which branch you want to run isn't always easy.

Thats probably a lot to unpack in there... I probably didn't help much to distill it.

You can also use Feature API's JSON policy format to handle all of this for you a bit simpler.

[1] Old policies are still valid unless you take other steps like adding in something like policynv against a counter you increment and that it's eq to the current value. Also has some of the issue of [2]. Compromising the nv index here means you can only reuse old policies.
[2] The authvalue protecting the nvindex is very important, if that nv index is compromised your whole policy is compromised. [1] would require the signing key to get full control.
________________________________
From: michael.g.millsap(a)intel.com<mailto:michael.g.millsap(a)intel.com> <michael.g.millsap(a)intel.com<mailto:michael.g.millsap(a)intel.com>>
Sent: Thursday, October 28, 2021 6:17 PM
To: tpm2(a)lists.01.org<mailto:tpm2(a)lists.01.org> <tpm2(a)lists.01.org<mailto:tpm2(a)lists.01.org>>
Subject: [tpm2] Help implementing "OR" PCR policy using C lib

I'm implementing the sealing of a LUKS key against secure boot PCRs and am trying to enable firmware updates using Esys_PolicyOR(). I can't find any example code. I am currently doing an Esys_PolicyPCR(), followed by Esys_PolicyGetDigest() and then I seal against that digest. How would I add the PolicyOR step? Would I do an Esys_PolicyPCR() & Esys_PolicyGetDigest() for each set of PCR values, followed by a Esys_PolicyOR() and then another Esys_PolicyGetDigest() to get the final digest to seal against? What would the unseal process look like?

Thanks,
Mike
_______________________________________________
tpm2 mailing list -- tpm2(a)lists.01.org<mailto:tpm2(a)lists.01.org>
To unsubscribe send an email to tpm2-leave(a)lists.01.org<mailto:tpm2-leave(a)lists.01.org>
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
_______________________________________________
tpm2 mailing list -- tpm2(a)lists.01.org<mailto:tpm2(a)lists.01.org>
To unsubscribe send an email to tpm2-leave(a)lists.01.org<mailto:tpm2-leave(a)lists.01.org>
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
attachment.htm (text/html, 10 KB)
<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<!--[if !mso]><style>v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style><![endif]--><style><!--
/* Font Definitions */
@font-face
	{font-family:"Cambria Math";
	panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
	{font-family:Calibri;
	panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0in;
	font-size:11.0pt;
	font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
	{mso-style-priority:99;
	color:blue;
	text-decoration:underline;}
span.EmailStyle18
	{mso-style-type:personal-reply;
	font-family:"Calibri",sans-serif;
	color:windowtext;}
.MsoChpDefault
	{mso-style-type:export-only;
	font-family:"Calibri",sans-serif;}
@page WordSection1
	{size:8.5in 11.0in;
	margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
	{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">The problem I have with PolicyauthorizeNV is how do I protect it from unauthorized change in a headless system? The platform is a headless, edge system. What’s to stop an attacker from booting off a USB stick, changing the authorized digest
 in the NV, then rebooting and gaining access to the secret which allows them to decrypt the drive?
<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal">I’m thinking that rather than using PolicyauthorizeNV or PolicyOR, I just create a new update sealed blob, which is sealed against the expected updated PCR digest and contains a new LUKS passphrase. On boot, if the original blob fails to
 unseal, I check for an update blob. If there is a validate update blob, I delete the original blob, delete the original LUKS passphrase keyslot, and rename the update blob to the current blob. This feels pretty straight forward and protects against rollback.<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal">-Mike<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal"><b>From:</b> David Challener &lt;[email protected]&gt; <br>
<b>Sent:</b> Saturday, October 30, 2021 8:02 AM<br>
<b>To:</b> Roberts, William C &lt;[email protected]&gt;<br>
<b>Cc:</b> Millsap, Michael G &lt;[email protected]&gt;; [email protected]<br>
<b>Subject:</b> [tpm2] Re: Help implementing &quot;OR&quot; PCR policy using C lib<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<div>
<p class="MsoNormal">PolicyauthorizeNV is orobably a better way to change an authorization. A policy is place in an NV index. Then policyauthorizeNV points to that index. Only the person with authorization to write the index can change it. Caution: writing
 the NV index should requure a policysign to avoid the remove index recreate index attack.<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<div>
<div>
<p class="MsoNormal">On Fri, Oct 29, 2021, 2:06 PM Roberts, William C &lt;<a href="mailto:[email protected]">[email protected]</a>&gt; wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">The best way to enable firmware updates is to use a mutable policy, either through policy signed (ie trust any policy signed with this key[1]) or through policyauthorizenv (Allows for mutable policies
 by referencing an NV Index [2]). The tpm2-tools have full examples in the man pages, and you can just play with the tools and then port it to ESYS. The tests in tpm2-tss also have examples of all the ESYS calls, but they are often times a bit contrived.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">When trying to create an OR policy, you essentially have:<br>
<br>
session A --&gt; Policy X --&gt; Policy Y .... --&gt; Get Digest = Digest A<br>
<br>
session B --&gt; Policy Q --&gt; Policy W .... --&gt; Get Digest = Digest B<br>
<br>
PolicyOR (Digest A, Digest B)&nbsp; = Final Digest<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">Every policy event you run a session is an AND operation. So a policy can have 1 or more statements. You then take the digests of all those and feed it to the policy OR<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">command which gives you the final digest that's used for policy value for an object.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">To satisfy the policy, you must run the commands on at least one branch that evaluates to true and pass all the same hashes back to policy OR to satisfy the policy. Its a bit awkward. So generally,
 you want to retain the policy hashes for each or branch, and then know which one you want to try or compute the hashes without using<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">the TPM and only use the TPM for the branch that is going to be true... But it also depends on commands that are deferred evaluation (ie you don't know that fail until you try and auth with the
 policy) or ones that fail at command time. So, figuring out which branch you want to run isn't always easy.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">Thats probably a lot to unpack in there... I probably didn't help much to distill it.&nbsp;<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">You can also use Feature API's JSON policy format to handle all of this for you a bit simpler.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p>&nbsp;</o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">[1] Old policies are still valid unless you take other steps like adding in something like policynv against a counter you increment and that it's eq to the current value. Also has some of the issue
 of [2]. Compromising the nv index here means you can only reuse old policies.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black">[2] The authvalue protecting the nvindex is very important, if that nv index is compromised your whole policy is compromised. [1] would require the signing key to get full control.<o:p></o:p></span></p>
</div>
<div class="MsoNormal" align="center" style="text-align:center">
<hr size="2" width="98%" align="center">
</div>
<div id="m_652579158680338919divRplyFwdMsg">
<p class="MsoNormal"><b><span style="color:black">From:</span></b><span style="color:black">
<a href="mailto:[email protected]" target="_blank">[email protected]</a> &lt;<a href="mailto:[email protected]" target="_blank">[email protected]</a>&gt;<br>
<b>Sent:</b> Thursday, October 28, 2021 6:17 PM<br>
<b>To:</b> <a href="mailto:[email protected]" target="_blank">[email protected]</a> &lt;<a href="mailto:[email protected]" target="_blank">[email protected]</a>&gt;<br>
<b>Subject:</b> [tpm2] Help implementing &quot;OR&quot; PCR policy using C lib</span> <o:p>
</o:p></p>
<div>
<p class="MsoNormal">&nbsp;<o:p></o:p></p>
</div>
</div>
<div>
<div>
<p class="MsoNormal">I'm implementing the sealing of a LUKS key against secure boot PCRs and am trying to enable firmware updates using Esys_PolicyOR(). I can't find any example code. I am currently doing an Esys_PolicyPCR(), followed by Esys_PolicyGetDigest()
 and then I seal against that digest. How would I add the PolicyOR step? Would I do an Esys_PolicyPCR() &amp; Esys_PolicyGetDigest() for each set of PCR values, followed by a Esys_PolicyOR() and then another Esys_PolicyGetDigest() to get the final digest to seal
 against? What would the unseal process look like?<br>
<br>
Thanks,<br>
Mike<br>
_______________________________________________<br>
tpm2 mailing list -- <a href="mailto:[email protected]" target="_blank">[email protected]</a><br>
To unsubscribe send an email to <a href="mailto:[email protected]" target="_blank">
[email protected]</a><br>
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s<o:p></o:p></p>
</div>
</div>
</div>
<p class="MsoNormal">_______________________________________________<br>
tpm2 mailing list -- <a href="mailto:[email protected]" target="_blank">[email protected]</a><br>
To unsubscribe send an email to <a href="mailto:[email protected]" target="_blank">
[email protected]</a><br>
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s<o:p></o:p></p>
</blockquote>
</div>
</div>
</body>
</html>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.