[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> </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> </o:p></p>
<p class="MsoNormal">-Mike<o:p></o:p></p>
<p class="MsoNormal"><o:p> </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 <[email protected]> <br>
<b>Sent:</b> Saturday, October 30, 2021 8:02 AM<br>
<b>To:</b> Roberts, William C <[email protected]><br>
<b>Cc:</b> Millsap, Michael G <[email protected]>; [email protected]<br>
<b>Subject:</b> [tpm2] Re: Help implementing "OR" PCR policy using C lib<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p> </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> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Fri, Oct 29, 2021, 2:06 PM Roberts, William C <<a href="mailto:[email protected]">[email protected]</a>> 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> </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 --> Policy X --> Policy Y .... --> Get Digest = Digest A<br>
<br>
session B --> Policy Q --> Policy W .... --> Get Digest = Digest B<br>
<br>
PolicyOR (Digest A, Digest B) = Final Digest<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </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> </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> </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. <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt;color:black"><o:p> </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> </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> <<a href="mailto:[email protected]" target="_blank">[email protected]</a>><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> <<a href="mailto:[email protected]" target="_blank">[email protected]</a>><br>
<b>Subject:</b> [tpm2] Help implementing "OR" PCR policy using C lib</span> <o:p>
</o:p></p>
<div>
<p class="MsoNormal"> <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() & 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>