<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://tpm2-software.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tpm2-software.github.io/" rel="alternate" type="text/html" /><updated>2025-11-05T16:46:24+00:00</updated><id>https://tpm2-software.github.io/feed.xml</id><title type="html">tpm2-software community</title><subtitle>The community around the TPM Software Stack 2.0 and its tpm2-tss open source implementation and all the tools and software that build upon it.</subtitle><entry><title type="html">Protecting Secrets At Tpm Interface</title><link href="https://tpm2-software.github.io/2021/02/17/Protecting-secrets-at-TPM-interface.html" rel="alternate" type="text/html" title="Protecting Secrets At Tpm Interface" /><published>2021-02-17T00:00:00+00:00</published><updated>2021-02-17T00:00:00+00:00</updated><id>https://tpm2-software.github.io/2021/02/17/Protecting-secrets-at-TPM-interface</id><content type="html" xml:base="https://tpm2-software.github.io/2021/02/17/Protecting-secrets-at-TPM-interface.html"><![CDATA[<h1 id="protecting-secrets-at-the-tpm-interface">Protecting secrets at the TPM interface</h1>

<p><a href="#abstract">Abstract</a>
<a href="#introduction">Introduction</a>
<a href="#provisioning">Provisioning</a>
<a href="#runtime-extended-provisioning">Runtime extended provisioning</a>
<a href="#sealing-application-secret">Sealing application secret</a>
<a href="#unsealing-application-secret">Unsealing application secret</a>
<a href="#demonstration-script-using-tpm2-tools">Demonstration script using tpm2-tools</a>
<a href="#credits">Credits</a></p>

<h4 id="abstract">Abstract</h4>

<p>This tutorial demonstrates a method to protect application secrets on the TPM.
TPM’s RTS protected-storage guarantees protection of information on the TPM.
This tutorial explains a method to protect the secrets on the interface between
the CPU and the TPM using provisions in the TPM standard.</p>

<p>In the method we discuss the following protections for an application secret:</p>

<ul>
  <li>
    <p>The application secret is sealed to a trusted TPM device whose identity is
known to be valid.</p>
  </li>
  <li>
    <p>The TPM device and the CPU are bound with a secret. The authorization policy
for the sealing object is made dependent on the secret. This offers protection
against the attacker ability to transplant the TPM to an attacker controlled
CPU to retrieve the secrets.</p>
  </li>
  <li>
    <p>Inhibit the attacker ability to retrieve or replay any of the secrets used
for the provisioning and the application-secrets on the CPU&lt;==&gt;TPM interface.</p>
  </li>
</ul>

<h4 id="introduction">Introduction</h4>

<p>The method works by sealing the application secret to a sealing-object whose
auth policy dictates that the content of an NV index must be the hash of a
secret value that is known only to a CPU.</p>

<p>The rest of the mechanism details the encryption of the sensitive content
transferred between the CPU and the TPM with a verified identity.</p>

<p>There are four distinct steps to the method, namely:</p>

<ol>
  <li>
    <p>Provisioning:
At this step, the NV index with specific attributes and authorization-value
and authorization-policy is created by the CPU(RTM).</p>
  </li>
  <li>
    <p>Runtime-extended-provisioning:
At this step, the NV index of the type “Extend” is extended with the NV
secret value derived from the CPU known secret.</p>
  </li>
  <li>
    <p>Sealing-data:
A sealing object is created with the policy-command-code (TPM2_CC_PolicyNV
AND TPM2_CC_Unseal)</p>
  </li>
  <li>
    <p>Unsealing-data:
The authorization-policy for unsealing is satisfied and the secret is
unsealed.</p>
  </li>
</ol>

<h4 id="provisioning">Provisioning</h4>

<p><img src="/images/secret-protection/provisioning.png" alt="Provisioning" /></p>

<pre><code class="language-mermaid">sequenceDiagram
    Note over CPU(RTM): (NVIndex==MISSING || Attributes==MISSING)
    Note over CPU(RTM): State = PROVISIONING
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_GetCapability&lt;br&gt;TPM2_CC_NVReadPublic
    Note over CPU(RTM): Get/verify EK against EK certificate
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_CreatePrimary&lt;br&gt;TPM2_CC_NVRead

    Note over CPU(RTM): Retrieve NV-index access policy
    PROTECTED-STORAGE-&gt;&gt;+CPU(RTM):PolicyOr(A|B|C)&lt;br&gt;A: TPM2_CC_PolicyCommandCode = TPM2_CC_NVRead&lt;br&gt;B: TPM2_CC_PolicyCommandCode = TPM2_CC_NVExtend&lt;br&gt;C: TPM2_CC_PolicyCommandCode = TPM2_CC_PolicyNV

    Note over CPU(RTM): Read CPU secret-seed
    PROTECTED-STORAGE-&gt;&gt;+CPU(RTM): CPU-SECRET-SEED
    Note over CPU(RTM): Lock further access to the secret seed

    Note over CPU(RTM):1. Derive HOST_SECRET
    Note over CPU(RTM):2. Start a salted session
    Note over CPU(RTM):3. Encrypt HOST_SECRET
    Note over CPU(RTM):4. Define/provision NVIndex with auth
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_StartAuthSession&lt;br&gt;TPM2_CC_NV_DefineSpace&lt;br&gt;PlatformCreate|NT=Extend|Orderly|StClear|NoDa|&lt;br&gt;PolicyRead|PolicyWrite|AuthRead|Authwrite
</code></pre>

<h4 id="runtime-extended-provisioning">Runtime extended provisioning</h4>

<p><img src="/images/secret-protection/runtime-extended-provisioning.png" alt="Runtime-extended-provisioning" /></p>

<pre><code class="language-mermaid">sequenceDiagram
    Note over CPU(RTM): (NVIndex==PRESENT || Attributes==SET)
    Note over CPU(RTM): State = RUNTIME-PROVISIONING
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_GetCapability&lt;br&gt;TPM2_CC_NVReadPublic

    Note over CPU(RTM): Read CPU secret-seed
    PROTECTED-STORAGE-&gt;&gt;+CPU(RTM): CPU-SECRET-SEED
    Note over CPU(RTM): Lock further access to the secret seed

    Note over CPU(RTM): 1. Derive HOST_SECRET
    Note over CPU(RTM): 2. Derive NV_SECRET
    Note over CPU(RTM): 3. Start a bounded session to encrypt NV_SECRET
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_StartAuthSession&lt;br&gt;Bind-object = NV-index&lt;br&gt;Bind-object-auth = HOST_SECRET
    Note over CPU(RTM): 4. Satisfy the NV access policy
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_PolicyCommandCode == TPM2_CC_PolicyNV&lt;br&gt;TPM2_CC_PolicyOR
    Note over CPU(RTM): 5. Populate/Extend NVIndex
    CPU(RTM)-&gt;&gt;+TPM: TPM2_CC_NV_Extend
</code></pre>

<h4 id="sealing-application-secret">Sealing application secret</h4>

<p><img src="/images/secret-protection/sealing-app-secret.png" alt="Sealing-app-secret" /></p>

<pre><code class="language-mermaid">sequenceDiagram
    Note over CPU(Application): 1. Generate sealing-policy
    CPU(Application)-&gt;&gt;+TPM: (D and E)&lt;br&gt;D: TPM2_CC_PolicyNV &lt;specify Hash(NV-Extend-Secret)&gt;&lt;br&gt;E: TPM2_CC_PolicyCommandCode = TPM2_CC_Unseal

    Note over CPU(Application):2. Started a salted session `tpmkey = EKpub`
    CPU(Application)-&gt;&gt;+TPM: TPM2_CC_StartAuthSession

    Note over CPU(Application):3. Choose/encrypt application secret

    Note over CPU(Application):4. Create the sealing object with auth = sealing-policy
    CPU(Application)-&gt;&gt;+TPM: TPM2_CC_CreatePrimary&lt;br&gt;TPM2_CC_Create
</code></pre>

<h4 id="unsealing-application-secret">Unsealing application secret</h4>

<p><img src="/images/secret-protection/unseal-app-secret.png" alt="Unseal-app-secret" /></p>

<pre><code class="language-mermaid">sequenceDiagram
    Note over CPU(Application): 1. Load the sealing object on the TPM
    CPU(Application)-&gt;&gt;+TPM: TPM2_CC_CreatePrimary&lt;br&gt;TPM2_CC_Load

    Note over CPU(Application):2. Start a salted session `tpmkey = EKpub` to protect unsealed data
    CPU(Application)-&gt;&gt;+TPM: TPM2_CC_StartAuthSession

    Note over CPU(Application):3. Start a policy session for NV access with TPM2_CC_PolicyNV
    CPU(Application)-&gt;&gt;+TPM: TPM2_CC_StartAuthSession&lt;br&gt;TPM2_CC_PolicyCommandCode&lt;br&gt;TPM2_CC_PolicyOr

    Note over CPU(Application): 4. Satisfy the auth policy for sealing object
    CPU(Application)-&gt;&gt;+TPM: PolicyAnd(D and E)&lt;br&gt;`D: PolicyNV &lt;Hash(NV_SECRET), NV-access-policy-session&gt;`&lt;br&gt;`E: PolicyCommandCode = TPM2_CC_Unseal`
    
    Note over CPU(Application): 5. Unseal the data from loaded object
    
    TPM-&gt;&gt;+CPU(Application): Encrypt and send the sealing-blob back to the application
    
    Note over CPU(Application): 6. Decrypt and consume the sealed data
</code></pre>

<h4 id="demonstration-script-using-tpm2-tools">Demonstration script using tpm2-tools</h4>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>
<span class="c">#</span>
<span class="c"># Filename : tpm2-software-secret-protection-demo.sh</span>
<span class="c"># Author   : imran.desai@intel.com, github.com/idesai</span>
<span class="c">#</span>

<span class="nb">set</span> <span class="nt">-E</span>

tpm-secret-protection-demo-help<span class="o">()</span> <span class="o">{</span>
    <span class="nb">echo</span> <span class="s2">"
    #
    # Flows:
    #
    # RTM checks for the NVIndex and its properties and triggers either:
    #
    # (1) cpu_secret_provisioning : Creates NVIndex with required auths &amp; attributes
    #             OR
    # (2) runtime_provisioning    : Extends NVIndex with data only known to the CPU
    #
    # Applications can now reference the NVIndex in a PolicyNV and perform either:
    #
    # (1) seal_data               : Create a sealing object and seal data
    #
    # (2) unseal_data             : Load the sealing object and unseal data
    #
    #
    # NOTE: Source this script to avail all the functions
    "</span>
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Globals</span>
<span class="c">#</span>
<span class="c"># The NV index should ideally be created as a platform hierarchy object</span>
<span class="nv">NVIndex</span><span class="o">=</span>0x1500018

<span class="c"># This is one of the two secrets derived from a seed value ideally accessible</span>
<span class="c"># only to the CPU. This serves as the NV index auth that can be used as bind obj</span>
<span class="nv">HOST_SECRET</span><span class="o">=</span><span class="s2">"host-secret"</span>

<span class="c"># This is the second secret derived from a seed value ideally accessible</span>
<span class="c"># only to the CPU. When extended to the NV index, a hash of this value can be</span>
<span class="c"># used in PolicyNV to authorize unsealing of application secret. Only a CPU with</span>
<span class="c"># access to the HOST_SECRET will be able to extend the required value.</span>
<span class="nv">NV_SECRET</span><span class="o">=</span><span class="s2">"nv-secret"</span>

<span class="c"># The application secret to be sealed to the TPM. So long as the CPU extends the</span>
<span class="c"># required NV_SECRET value to the TPM, the unsealing operation is allowed.</span>
<span class="nv">SEALBLOB</span><span class="o">=</span><span class="s2">"app-secret"</span>

cleanup<span class="o">()</span> <span class="o">{</span>

    tpm2_clear <span class="nt">-Q</span>
    tpm2_nvreadpublic | <span class="nb">grep</span> <span class="nt">-q</span> <span class="nv">$NVIndex</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span> <span class="k">then
        </span>tpm2_nvundefine <span class="nt">-Q</span> <span class="nt">-C</span> p <span class="nv">$NVIndex</span>
    <span class="k">fi
    </span><span class="nb">rm</span> <span class="nt">-f</span> ek.ctx salted_session.ctx policycc_nv_session.ctx A.policy B.policy <span class="se">\</span>
    C.policy nvaccess_policy_generation_session.ctx nvaccess.policy <span class="se">\</span>
    bounded_policy_session.ctx unseal_policy_generate_session.ctx <span class="se">\</span>
    unseal.policy oprim.ctx seal_obj.ctx nvread_session.ctx
<span class="o">}</span>

<span class="nb">trap </span>cleanup EXIT

<span class="c">#</span>
<span class="c"># Salted session for encrypting sensitive information when:</span>
<span class="c"># 1. Creating the NV index</span>
<span class="c"># 2. Creating the sealing object</span>
<span class="c"># 3. Unsealing the application secret</span>
<span class="c">#</span>
setup_salted_param_encrypt_session_with_ek<span class="o">()</span> <span class="o">{</span>

    tpm2_createek <span class="nt">-Q</span> <span class="nt">--key-algorithm</span> rsa <span class="nt">--ek-context</span> ek.ctx

    tpm2_startauthsession <span class="nt">-Q</span>  <span class="nt">--session</span> salted_session.ctx <span class="nv">$1</span> <span class="se">\</span>
    <span class="nt">--tpmkey-context</span> ek.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> ek.ctx

    tpm2_sessionconfig <span class="nt">-Q</span>  salted_session.ctx <span class="nt">--enable-decrypt</span>
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Starting the PolicyNV policy session required when:</span>
<span class="c"># 1. Generating the policy for the sealing object at creation</span>
<span class="c"># 2. Unsealing the application secret</span>
<span class="c">#</span>
nvaccess_policycc_policynv<span class="o">()</span> <span class="o">{</span>

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> policycc_nv_session.ctx <span class="nt">--policy-session</span>

    tpm2_policycommandcode <span class="nt">-Q</span> <span class="nt">--session</span> policycc_nv_session.ctx TPM2_CC_PolicyNV

    tpm2_policyor <span class="nt">-Q</span> <span class="nt">--session</span> policycc_nv_session.ctx <span class="se">\</span>
    <span class="nt">--policy-list</span> sha256:A.policy,B.policy,C.policy
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Generate the policy paths for accessing read/ write operations on NV index</span>
<span class="c"># A.policy ==&gt; PolicyCommandCode = TPM2_CC_NV_Read</span>
<span class="c"># B.policy ==&gt; PolicyCommandCode = TPM2_CC_NV_Extend</span>
<span class="c"># C.policy ==&gt; PolicyCommandCode = TPM2_CC_PolicyNV</span>
<span class="c"># Access-Policy = A||B||C</span>
<span class="c">#</span>
generate_nv_access_policy<span class="o">()</span> <span class="o">{</span>

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_policycommandcode <span class="nt">-Q</span> TPM2_CC_NV_Read <span class="nt">--policy</span> A.policy <span class="se">\</span>
    <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_flushcontext <span class="nt">-Q</span> nvaccess_policy_generation_session.ctx

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_policycommandcode <span class="nt">-Q</span>  TPM2_CC_NV_Extend <span class="nt">--policy</span> B.policy <span class="se">\</span>
    <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_flushcontext <span class="nt">-Q</span> nvaccess_policy_generation_session.ctx

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_policycommandcode <span class="nt">-Q</span> TPM2_CC_PolicyNV <span class="nt">--policy</span> C.policy <span class="se">\</span>
    <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_flushcontext <span class="nt">-Q</span> nvaccess_policy_generation_session.ctx

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> nvaccess_policy_generation_session.ctx

    tpm2_policyor <span class="nt">-Q</span> <span class="nt">--session</span> nvaccess_policy_generation_session.ctx <span class="se">\</span>
    <span class="nt">--policy-list</span> sha256:A.policy,B.policy,C.policy <span class="nt">--policy</span> nvaccess.policy

    tpm2_flushcontext <span class="nt">-Q</span> nvaccess_policy_generation_session.ctx

    <span class="nb">rm</span> <span class="nt">-f</span> nvaccess_policy_generation_session.ctx
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># This provisioning step is done once under RTM control</span>
<span class="c">#</span>
cpu_secret_provisioning<span class="o">()</span> <span class="o">{</span>
    generate_nv_access_policy

    setup_salted_param_encrypt_session_with_ek <span class="nt">--hmac-session</span>

    tpm2_nvdefine <span class="nt">-Q</span>  <span class="nt">--session</span> salted_session.ctx <span class="nt">-C</span> p <span class="nt">-p</span> <span class="nv">$HOST_SECRET</span> <span class="nv">$NVIndex</span> <span class="se">\</span>
    <span class="nt">-a</span> <span class="s2">"orderly|clear_stclear|platformcreate|no_da|nt=extend|policyread|policywrite|authread|authwrite"</span> <span class="se">\</span>
    <span class="nt">--policy</span> nvaccess.policy

    tpm2_flushcontext <span class="nt">-Q</span> salted_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> salted_session.ctx nvaccess.policy
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># This step is done once at every TPM restart under RTM control</span>
<span class="c"># Satisfy policy to be able to extend the NV index in bounded policy session</span>
<span class="c"># Note: Auth specified in the bounded session generation is used to</span>
<span class="c">#       calculate the sessionvalue by ESAPI. The auth is not exposed on</span>
<span class="c">#       TPM interface.</span>
<span class="c">#</span>
runtime_provisioning<span class="o">()</span> <span class="o">{</span>
    tpm2_startauthsession <span class="nt">-Q</span>  <span class="nt">--session</span> bounded_policy_session.ctx <span class="se">\</span>
    <span class="nt">--policy-session</span> <span class="nt">--bind-context</span> <span class="nv">$NVIndex</span> <span class="nt">--bind-auth</span> <span class="nv">$HOST_SECRET</span>

    tpm2_sessionconfig <span class="nt">-Q</span> bounded_policy_session.ctx <span class="se">\</span>
    <span class="nt">--enable-decrypt</span> <span class="nt">--enable-encrypt</span>

    tpm2_policycommandcode <span class="nt">-Q</span> <span class="nt">--session</span> bounded_policy_session.ctx <span class="se">\</span>
    TPM2_CC_NV_Extend

    tpm2_policyor <span class="nt">-Q</span> <span class="nt">--session</span> bounded_policy_session.ctx <span class="se">\</span>
    <span class="nt">--policy-list</span> sha256:A.policy,B.policy,C.policy

    <span class="nb">echo</span> <span class="nt">-n</span> <span class="nv">$NV_SECRET</span>|tpm2_nvextend <span class="nt">-Q</span> <span class="nt">-C</span> <span class="nv">$NVIndex</span> <span class="nt">-i-</span> <span class="nv">$NVIndex</span> <span class="se">\</span>
    <span class="nt">-P</span> session:bounded_policy_session.ctx

    tpm2_flushcontext <span class="nt">-Q</span> bounded_policy_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> bounded_policy_session.ctx
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Satisfy policy to be able to read the NV Index</span>
<span class="c">#</span>
nvread_session_setup<span class="o">()</span> <span class="o">{</span>
    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> nvread_session.ctx <span class="nt">--policy-session</span>

    tpm2_policycommandcode <span class="nt">-Q</span> <span class="nt">--session</span> nvread_session.ctx TPM2_CC_NV_Read

    tpm2_policyor <span class="nt">-Q</span> <span class="nt">--session</span> nvread_session.ctx <span class="se">\</span>
    <span class="nt">--policy-list</span> sha256:A.policy,B.policy,C.policy
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Sealing-object-policy:</span>
<span class="c"># PolicyCommandCode == (TPM2_CC_PolicyNV &amp;&amp; TPM2_CC_Unseal)</span>
<span class="c">#</span>
seal_data<span class="o">()</span> <span class="o">{</span>

    nvaccess_policycc_policynv

    tpm2_startauthsession <span class="nt">-Q</span> <span class="nt">--session</span> unseal_policy_generate_session.ctx

    nvread_session_setup

    tpm2_nvread <span class="nv">$NVIndex</span> <span class="nt">-P</span> session:nvread_session.ctx | tpm2_policynv <span class="nt">-Q</span> <span class="nt">-i-</span> <span class="se">\</span>
    <span class="nv">$NVIndex</span> eq <span class="nt">--session</span> unseal_policy_generate_session.ctx <span class="se">\</span>
    <span class="nt">-P</span> session:policycc_nv_session.ctx <span class="nt">--policy</span> unseal.policy 

    tpm2_flushcontext <span class="nt">-Q</span> policycc_nv_session.ctx
    tpm2_flushcontext <span class="nt">-Q</span> nvread_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> policycc_nv_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> nvread_session.ctx

    tpm2_policycommandcode <span class="nt">-Q</span> <span class="nt">--session</span> unseal_policy_generate_session.ctx <span class="se">\</span>
    <span class="nt">--policy</span> unseal.policy TPM2_CC_Unseal

    tpm2_flushcontext <span class="nt">-Q</span> unseal_policy_generate_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> unseal_policy_generate_session.ctx

    setup_salted_param_encrypt_session_with_ek <span class="nt">--hmac-session</span>

    tpm2_createprimary <span class="nt">-Q</span>  <span class="nt">-C</span> o <span class="nt">-c</span> oprim.ctx

    <span class="nb">echo</span> <span class="nt">-n</span> <span class="nv">$SEALBLOB</span> | tpm2_create <span class="nt">-Q</span>  <span class="nt">-C</span> oprim.ctx <span class="nt">--policy</span> unseal.policy <span class="se">\</span>
    <span class="nt">-u</span> seal_obj.pub <span class="nt">-r</span> seal_obj.priv <span class="nt">--session</span> salted_session.ctx <span class="nt">-i-</span>
    <span class="nb">rm</span> <span class="nt">-f</span> oprim.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> unseal.policy

    tpm2_flushcontext <span class="nt">-Q</span> salted_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> salted_session.ctx
<span class="o">}</span>

load_sealing_object<span class="o">()</span> <span class="o">{</span>
    tpm2_createprimary <span class="nt">-Q</span>  <span class="nt">-C</span> o <span class="nt">-c</span> oprim.ctx

    tpm2_load <span class="nt">-Q</span>  <span class="nt">-C</span> oprim.ctx <span class="nt">-c</span> seal_obj.ctx <span class="nt">-u</span> seal_obj.pub <span class="nt">-r</span> seal_obj.priv
    <span class="nb">rm</span> <span class="nt">-f</span> oprim.ctx
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># 1. Read NV index &lt;non secret data&gt;</span>
<span class="c"># 2. Satisfy PolicyNV</span>
<span class="c"># 3. Unseal</span>
<span class="c">#</span>
unseal_data<span class="o">()</span> <span class="o">{</span>

    nvaccess_policycc_policynv

    setup_salted_param_encrypt_session_with_ek <span class="nt">--policy-session</span>

    nvread_session_setup

    tpm2_nvread <span class="nt">-C</span> <span class="nv">$NVIndex</span> <span class="nt">-P</span> session:nvread_session.ctx <span class="nv">$NVIndex</span> | <span class="se">\</span>
    tpm2_policynv <span class="nt">-Q</span> <span class="nt">-i-</span> <span class="nv">$NVIndex</span> eq <span class="nt">--session</span> salted_session.ctx <span class="se">\</span>
    <span class="nt">-P</span> session:policycc_nv_session.ctx 

    tpm2_flushcontext <span class="nt">-Q</span> policycc_nv_session.ctx
    tpm2_flushcontext <span class="nt">-Q</span> nvread_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> policycc_nv_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> nvread_session.ctx

    tpm2_policycommandcode <span class="nt">-Q</span> <span class="nt">--session</span> salted_session.ctx TPM2_CC_Unseal

    load_sealing_object

    <span class="nv">UNSEALBLOB</span><span class="o">=</span><span class="si">$(</span>tpm2_unseal <span class="nt">-Q</span> <span class="nt">-c</span> seal_obj.ctx <span class="nt">-p</span> session:salted_session.ctx<span class="si">)</span>

    <span class="nb">echo</span> <span class="s2">"UNSEALBLOB=</span><span class="nv">$UNSEALBLOB</span><span class="s2">"</span>

    tpm2_flushcontext <span class="nt">-Q</span> salted_session.ctx
    <span class="nb">rm</span> <span class="nt">-f</span> seal_obj.ctx
<span class="o">}</span>

tpm-secret-protection-demo-help
</code></pre></div></div>

<h2 id="credits">Credits</h2>

<p>This document is a culmination of thoughts and ideas of the members of the TCG
Device Driver Working Group (DDWG). Thanks to the contributors:</p>

<ul>
  <li>Liran Perez(Intel)</li>
  <li>Ken Goldman (IBM)</li>
  <li>Ronald Aigner (Microsoft)</li>
  <li>Amy Nelson (Dell)</li>
  <li>Imran Desai (Intel)</li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[Protecting secrets at the TPM interface]]></summary></entry><entry><title type="html">Tpm2 Device Emulation With Qemu</title><link href="https://tpm2-software.github.io/2020/10/19/TPM2-Device-Emulation-With-QEMU.html" rel="alternate" type="text/html" title="Tpm2 Device Emulation With Qemu" /><published>2020-10-19T00:00:00+00:00</published><updated>2020-10-19T00:00:00+00:00</updated><id>https://tpm2-software.github.io/2020/10/19/TPM2-Device-Emulation-With-QEMU</id><content type="html" xml:base="https://tpm2-software.github.io/2020/10/19/TPM2-Device-Emulation-With-QEMU.html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>End-to-end development with physical hardware can be challenging due to a myriad
of factors. Things like persistent state, physical wear, slow and difficult
to update hardware bugs, lagging features, etc can pose additional hurdles to
development tasks.</p>

<p>A potential way to overcome this, is to use <a href="https://www.qemu.org">QEMU</a> instance with an attached
virtualized TPM2.0 device. This device is made available to the guest OS, and
with the appropriate versions of Linux, will expose the familiar /dev/tpm0
and /dev/tpmrm0 interfaces.</p>

<p>In this brief tutorial, we provide instructions on how to build such a system by leveraging other documentation as required.</p>

<h1 id="prerequisites">Prerequisites</h1>
<p>Prior art does exist on this topic, and details used in this tutorial have references from
the following resources:</p>
<ul>
  <li>https://www.qemu.org/docs/master/specs/tpm.html</li>
  <li>https://graspingtech.com/ubuntu-desktop-18.04-virtual-machine-macos-qemu/</li>
</ul>

<h2 id="install-the-proper-tpm20-simulator">Install the proper TPM2.0 Simulator</h2>

<p>In this tutorial, we demonstrate how to leverage the <a href="https://github.com/stefanberger/swtpm">swtpm</a> as the TPM simulator.
The project wiki has instructions for building and installing the simulator and its dependency, <a href="https://github.com/stefanberger/libtpms">libtpms</a>.</p>

<h2 id="install-qemu">Install QEMU</h2>

<p>Next, you need to install QEMU. This is operating system dependent. Details on installing
QEMU can be found by visiting their website:</p>
<ul>
  <li>https://www.qemu.org/</li>
</ul>

<p><strong>The minimum version of QEMU to support this is 4.0. In this tutorial, the author tested with version 5.2.</strong></p>

<h1 id="install-the-guest-os">Install The Guest OS</h1>

<p>The author installed Ubuntu 20.04, so the commands will be specific to that ISO, but another ISO
could be substituted. Additionally, the naming convention on things like hard-drive could be changed
to reflect your environment more closely.</p>

<p>Install the guest OS. This will be guest-OS specific. The general commands are to build
a virtual disk:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">qemu-img create -f qcow2 ubuntu-20.04-amd64.img 30G
</span></code></pre></div></div>

<p>Then attach it to a VM and start it with the installation media, usually an ISO:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">qemu-system-x86_64 -hda ~/qemu-images/ubuntu-20.04-amd64.img -boot d -cdrom ~/Downloads/ubuntu-20.04.1-desktop-amd64.iso -m 2048 -enable-kvm
</span></code></pre></div></div>

<h1 id="start-the-guest-with-a-tpm20-device">Start the Guest with a TPM2.0 Device</h1>

<p>Now start the guest with a virtualized TPM2.0 device. To do this, one needs to start the SWTPM simulator in tpm2 mode using the option
<code class="language-plaintext highlighter-rouge">--tpm2</code>, like so:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">mkdir /tmp/emulated_tpm
swtpm socket --tpmstate dir=/tmp/emulated_tpm --ctrl type=unixio,path=/tmp/emulated_tpm/swtpm-sock --log level=20 --tpm2
</span></code></pre></div></div>

<p>Then start the guest:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">qemu-system-x86_64 -hda ~/qemu-images/ubuntu-20.04-amd64.img -boot d -m 2048 -enable-kvm \
  -chardev socket,id=chrtpm,path=/tmp/emulated_tpm/swtpm-sock \
  -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0
</span></code></pre></div></div>

<p>Now verify that the device nodes are present in the guest VM by opening a console and running the following command:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">ls /dev/tpm*
</span></code></pre></div></div>

<p>You should see <code class="language-plaintext highlighter-rouge">/dev/tpm0</code> and <code class="language-plaintext highlighter-rouge">/dev/tpmrm0</code> devices in the output of the <code class="language-plaintext highlighter-rouge">ls</code> command.</p>

<h1 id="conclusion">Conclusion</h1>

<p>One of the major benefits to the emulated environment is being able to test end-to-end development without the need for physical
hardware and it’s associated drawbacks across a wide variety of environments. QEMU has the ability to emulate multiple physical
CPU architectures. Couple that with the ability to install a wide array of operating systems, and you have a flexible system for
debugging and building new features from the lowest portions of the stack all they way to end client applications.</p>

<h1 id="author">Author</h1>
<p>William Roberts</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Introduction End-to-end development with physical hardware can be challenging due to a myriad of factors. Things like persistent state, physical wear, slow and difficult to update hardware bugs, lagging features, etc can pose additional hurdles to development tasks.]]></summary></entry><entry><title type="html">Fapi_crypto_profiles</title><link href="https://tpm2-software.github.io/2020/07/22/Fapi_Crypto_Profiles.html" rel="alternate" type="text/html" title="Fapi_crypto_profiles" /><published>2020-07-22T00:00:00+00:00</published><updated>2020-07-22T00:00:00+00:00</updated><id>https://tpm2-software.github.io/2020/07/22/Fapi_Crypto_Profiles</id><content type="html" xml:base="https://tpm2-software.github.io/2020/07/22/Fapi_Crypto_Profiles.html"><![CDATA[<h1 id="basics">Basics</h1>
<p>The Feature API (FAPI) contains the concept of cryptographic profiles.
These define a combination of cryptographic algorithms and properties that shall be used.
On a typical installation they are located under <code class="language-plaintext highlighter-rouge">/etc/tpm2-tss/fapi-profiles</code>.
One of these profiles is selected using the fapi config file; key <code class="language-plaintext highlighter-rouge">profile_name</code> in <code class="language-plaintext highlighter-rouge">/etc/tpm2-tss/fapi-config.json</code>.</p>

<p>When calling <code class="language-plaintext highlighter-rouge">Fapi_Profision()</code> the keystore of Fapi is initialized, the <code class="language-plaintext highlighter-rouge">SRKs</code> are created and the <code class="language-plaintext highlighter-rouge">EK</code> is checked based on the currently selected profile. From that point on, the parameters of the profile are used for all relevant operations.</p>

<h1 id="multiple-profiles">Multiple Profiles</h1>
<p>The FAPI includes a concept for cryptographic transition. The purpose is that if the crypto policy changes one can transition to the new policy whilst retaining access to old key material. As such, one can change the <code class="language-plaintext highlighter-rouge">profile_name</code> in the <code class="language-plaintext highlighter-rouge">fapi-config.json</code> and call <code class="language-plaintext highlighter-rouge">Fapi_Provision()</code> in order to populate the new keystore.</p>

<p>Note that you have to make sure that the persistent handles between the old and the new profile in <code class="language-plaintext highlighter-rouge">/etc/tpm2-tss/fapi-profiles</code> do not collide. On a standard installation they both are set to <code class="language-plaintext highlighter-rouge">0x81000001</code>.</p>

<p>Once the new profile is provisioned, the old profile can be access by prefixing all keypaths accordings, e.g. <code class="language-plaintext highlighter-rouge">/P_OLDPROFILE/HS/SRK/...</code></p>

<h1 id="asymmetric-encryption">Asymmetric Encryption</h1>
<p>At the time of this writing only the RSA crypto profiles support asymmetric encryption and decryption. The reason is that even though the Elliptic Curve Integrated Encryption Scheme (ECIES) seems to be well established, there exists no one standard for the exact semantics and data encoding formats. See also OpenSSL for a reference: https://github.com/openssl/openssl/issues/9314#issuecomment-508724551</p>

<p>Thus in order to utilize the functions <code class="language-plaintext highlighter-rouge">Fapi_Encrypt()</code> and <code class="language-plaintext highlighter-rouge">Fapi_Decrypt()</code> the RSA profile must be selected. Note that multiple profiles can be provisioned at once, as mentioned above.</p>

<h1 id="updates">Updates</h1>
<p>This page may be updated in the future with more information.</p>

<h1 id="author">Author</h1>
<p>Andreas Fuchs @Fraunhofer SIT</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Basics The Feature API (FAPI) contains the concept of cryptographic profiles. These define a combination of cryptographic algorithms and properties that shall be used. On a typical installation they are located under /etc/tpm2-tss/fapi-profiles. One of these profiles is selected using the fapi config file; key profile_name in /etc/tpm2-tss/fapi-config.json.]]></summary></entry><entry><title type="html">Remote Attestation With Tpm2 Tools</title><link href="https://tpm2-software.github.io/2020/06/12/Remote-Attestation-With-tpm2-tools.html" rel="alternate" type="text/html" title="Remote Attestation With Tpm2 Tools" /><published>2020-06-12T00:00:00+00:00</published><updated>2020-06-12T00:00:00+00:00</updated><id>https://tpm2-software.github.io/2020/06/12/Remote-Attestation-With-tpm2-tools</id><content type="html" xml:base="https://tpm2-software.github.io/2020/06/12/Remote-Attestation-With-tpm2-tools.html"><![CDATA[<h1 id="table-of-contents">Table of Contents</h1>

<ul>
  <li><a href="#introduction">Introduction</a>
    <ul>
      <li><a href="#software-required">Software required</a></li>
      <li><a href="#tools-and-utilities-used-from-the-tpm2-tools-project">Tools and utilities used from the tpm2-tools project</a></li>
    </ul>
  </li>
  <li><a href="#attestation-goals">Attestation-Goals</a>
    <ul>
      <li><a href="#privacy-considerations">Privacy considerations</a>
        <ul>
          <li><a href="#why-anonymity-or-privacy-matters">Why anonymity or privacy matters?</a></li>
          <li><a href="#solution">Solution</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#tpm-attestation">TPM attestation</a>
    <ul>
      <li><a href="#what-is-a-pcr-and-how-are-pcr-values-generated">What is a PCR and how are PCR values generated</a>
        <ul>
          <li><a href="#initial-state-of-the-pcr">Initial state of the PCR</a></li>
          <li><a href="#extending-values-into-pcr-indices">Extending values into PCR indices</a></li>
          <li><a href="#golden-or-reference-pcr">Golden or reference PCR</a></li>
        </ul>
      </li>
      <li><a href="#system-software-state">System software state</a></li>
      <li><a href="#roots-of-trust-for-reporting-(rtr)">Roots of trust for reporting (RTR)</a></li>
    </ul>
  </li>
  <li><a href="#roles-identified-in-the-bare-bone-remote-attestation-model">Roles identified in the bare bone remote attestation model</a>
    <ul>
      <li><a href="#device-service-registration">Device service registration</a></li>
      <li><a href="#service-request-part-1-platform-anonymous-identity-validation">Service request Part 1 (Platform Anonymous Identity Validation)</a></li>
      <li><a href="#service-request-part-2-(platform-software-state-validation)">Service request Part 2 (Platform Software State Validation)</a></li>
      <li><a href="#service-delivery">Service delivery</a></li>
    </ul>
  </li>
  <li><a href="#simple-attestation-with-tpm2-tools">Simple attestation with tpm2-tools</a></li>
  <li><a href="#scripts-for-implementation-of-the-simple-attestation-framework">Scripts for implementation of the simple attestation framework</a>
    <ul>
      <li><a href="#device-node">Device-Node</a></li>
      <li><a href="#service-provider">Service-Provider</a></li>
      <li><a href="#privacy-ca">Privacy-CA</a></li>
    </ul>
  </li>
  <li><a href="#FAQ">FAQ</a></li>
</ul>

<h1 id="introduction">Introduction</h1>

<p>This article shows how to use the utilities/ tools from the
<a href="https://github.com/tpm2-software/tpm2-tools">tpm2-tools</a> project to set up a
bare bone remote attestation of the system software state as reflected by the
TPM2 platform-configuration-registers (PCR). The intent is to provide a general
guidance on the topic and does not discuss or reference any attestation
framework in particular.</p>

<p><strong><em>CAUTION: All code samples for the sample attestation framework are strictly for
demonstration purpose. It has not been evaluated for production use.</em></strong></p>

<p><img src="/images/tpm2-attestation-demo/tpm2-attestation-demo.gif" alt="Attestation-demo" /></p>

<h2 id="software-required">Software required</h2>
<ul>
  <li><a href="https://github.com/tpm2-software/tpm2-tss">tpm2-tss v2.3.0</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-abrmd">tpm2-abrmd v2.2.0</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools">tpm2-tools v4.0</a></li>
  <li><a href="https://sourceforge.net/projects/ibmswtpm2/">ibmswtpm</a></li>
  <li><a href="https://linux.die.net/man/1/openssl">openssl</a></li>
</ul>

<h2 id="tools-and-utilities-used-from-the-tpm2-tools-project">Tools and utilities used from the tpm2-tools project</h2>
<ul>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createprimary.1.md">tpm2_createprimary</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_create.1.md">tpm2_create</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createek.1.md">tpm2_createek</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createak.1.md">tpm2_createak</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_getekcertificate.1.md">tpm2_getekcertificate</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_makecredential.1.md">tpm2_makecredential</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_activatecredential.1.md">tpm2_activatecredential</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_pcrextend.1.md">tpm2_pcrextend</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_pcrread.1.md">tpm2_pcrread</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_quote.1.md">tpm2_quote</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_checkquote.1.md">tpm2_checkquote</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_getrandom.1.md">tpm2_getrandom</a></li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_readpublic.1.md">tpm2_readpublic</a></li>
</ul>

<h1 id="attestation-goals">Attestation-Goals</h1>

<p>“Attestation is the evidence or proof of something. It is a declaration that
something exists or is the case. It is the action of being a witness to or
formally certifying something.”<br /></p>

<p>The <a href="https://www.lexico.com/en/definition/attestation">literary-definition</a>
very much applies in the context of this tutorial which discusses attesting of
the PCR contents in a TPM.</p>

<p>An attestation has two critical parts for it to hold true, namely:</p>

<ol>
  <li>
    <p>Attestor identity:
 To believe something is true, one needs to vouch the authenticity of what is
 being attested. This inherently means the identity of the one who attests
 is known and or trusted.</p>
  </li>
  <li>
    <p>Attestation data integrity:
 To believe something is true, both the process to generate the information
 and the process to protect the information from tampering need to be
 inherently trusted.</p>
  </li>
</ol>

<h2 id="privacy-considerations">Privacy considerations</h2>

<p>While private or sensitive portion of keys used to sign attestation blobs must
remain confidential or secret, it is possible to identify a unique signer with
the public key used to verify the signature over the attestation blobs. This
defeats the anonymity or privacy of the platform user.</p>

<h3 id="why-anonymity-or-privacy-matters">Why anonymity or privacy matters?</h3>

<p>Let’s use a hypothetical example of a smart-lock device that has an embedded
application. It has integrated multiple microservices from different providers
that provide various services, namely:</p>
<ol>
  <li>Two-factor-authentication(2FA).</li>
  <li>Facial-recognition.</li>
  <li>Device-Logs.</li>
</ol>

<p>If the device uses the same key across all the microservices for public key
authentication and or signing attestation quotes. The service provider or a
third party analytics could potentially stage a privacy violation knowingly or
unknowingly simply by tracking usage of same public key. And so it can be
determined that the device owner uses facial recognition for 2FA and operates
the device consistently certain times of the day which updates the device logs.</p>

<h3 id="solution">Solution</h3>

<p>There are at least four possible ways to resolve this.</p>
<ol>
  <li>Every user uses the same private/public key pair to sign attestation blobs.
Cryptographically, this method is as strong as the process and controls
involved in duplicating the private key into multiple platforms.
Additionally, the strength is also dependent on the robustness of the methods
and mechanisms to store the private key once imported in the platform.
Revocation of the key implies that all the platforms having the key must be
revoked and re-provisioned with new key. Refer <a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_import.1.md">tpm2_import</a>
that demonstrates a way to import external keys into the TPM.</li>
  <li>Every user has a unique private key, however, all the private keys keys map
to a single public key. This is possible with <a href="https://eprint.iacr.org/2009/095.pdf">Intel® EPID</a>
technology. EPID also affords a mechanism to revoke a single key or all the
platforms in the group. A similar direct-anonymous-attestation (DAA) based on
elliptic curve cryptography scheme is also available in the TPM and is called
ECDAA; it is not discussed in this tutorial.</li>
  <li>Every user generates and uses a new key (ephemeral key) every time an
attestation blob has to be signed. There are some unique challenges with this.
If every attestation blob is signed with a brand-new key, how to infer the
anonymous identity at the minimum to determine the genuineness of the platform
and hence the attestation. It then follows that we need an anonymous identity
that is cryptographically bound to a unique trusted identity and that the
unique identity is never revealed to any entity other than the Privacy-CA.</li>
  <li>A variant of #3. One AIK per party that’s verifying attestations. Allows
abstracting the client ID, but the verifier knows it’s the same client on
subsequent verifications. This is useful in applications like banking etc.</li>
</ol>

<p>Note: Platform anonymity can also be defeated if the platform’s host-name and or
ip-address remains the same on every connection. This is not a topic of
discussion here, yet there is an assumption made here that sufficient measures
are taken by the platform user to resolve this using a
<a href="https://www.pcmag.com/how-to/how-to-hide-your-ip-address">VPN</a> or other
reasonable mechanisms.</p>

<h1 id="tpm-attestation">TPM attestation</h1>

<p>Depending on the robustness and privacy rules of the system, platform
anonymity may not be mandatory and so privacy considerations don’t apply. If
that is the case or if methods #1 or #2 discussed above suffice your attestation
and privacy needs, subsequent sections detailing information on TCG endorsement
keys (EK) and attestation identity keys (AIK) are irrelevant.</p>

<p>Note: A more detailed discussion on TPM attestation terminologies can be found
<a href="https://tpm2-software.github.io/tpm2-tss/getting-started/2019/12/18/Remote-Attestation.html">here</a>.
This document expands on that discussion to demonstrate how one can set up a
minimal or bare bones attestation framework using tpm2-tools.</p>

<p>With these definitions in mind, let’s dive straight into TPM attestation topic.
Of the various object types in the TPM, the following discussion is restricted
to how the TPM PCR data can be attested securely and anonymously using method #3.</p>

<h2 id="what-is-a-pcr-and-how-are-pcr-values-generated">What is a PCR and how are PCR values generated</h2>

<p>PCR or platform configuration registers are special TPM2 objects that can only
be modified or written to by hash extension mechanism. In that, the incoming
new value is concatenated with the existing value in the PCR and hashed. The
new hash value now replaces the old value. This means that though it is a single
location, the final value reflects a history of all the hash extensions. PCRs
are arranged in banks, one each for a specific hash algorithm SHA1, SHA256, etc.
Every bank has up to 32 PCRs. The Trusted Computing Group publishes a guideline
of what part of system software should be extended to specific PCR indices in
the <a href="https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientSpecPlat_TPM_2p0_1p04_pub.pdf">PC Client specification</a>.
There is also a debug PCR at index 16 that can be reset to 0 by issuing the
tpm2_pcrreset command. Other PCRs reset on TPM resets.</p>

<p>The fact that the only way to modify a PCR is to extend a hash and that the
robustness mechanisms that prevent physical tampering of the values, make the
TPM a root of trust for storage (RTS).</p>

<h3 id="initial-state-of-the-pcr">Initial state of the PCR</h3>

<p>The initial values in a PCR index is determined by the platform-specific
<a href="https://www.trustedcomputinggroup.org/wp-content/uploads/PC-Client-Specific-Platform-TPM-Profile-for-TPM-2-0-v43-150126.pdf">specification</a>.
Values at a given PCR index can be read using the <strong>tpm2_pcrread</strong> tool and
specifying the PCR-selection string. Relevant to our example, let’s read PCR
indices 0,1,2 in SHA1 and SHA256 banks.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tpm2_pcrread sha1:0,1,2+sha256:0,1,2
</code></pre></div></div>

<p>If running it on a simulator, the PCR are in the initial state, in that the PCR
are not extended just yet. Hence, the default values (00/ FF) should be displayed
as shown below.</p>

<p>SHA1<br />
  0 : 0000000000000000000000000000000000000000<br />
  1 : 0000000000000000000000000000000000000000<br />
  2 : 0000000000000000000000000000000000000000<br /></p>

<p>SHA256<br />
  0 : 0000000000000000000000000000000000000000000000000000000000000000<br />
  1 : 0000000000000000000000000000000000000000000000000000000000000000<br />
  2 : 0000000000000000000000000000000000000000000000000000000000000000<br /></p>

<h3 id="extending-values-into-pcr-indices">Extending values into PCR indices</h3>

<p>A PCR index can be modified only by extending it. In that, it cannot be set to
an absolute value like a register. One of the three tools can modify the PCR
values, namely:</p>

<ol>
  <li><strong>tpm2_pcrextend</strong>: A pre-calculated digest of data is presented to the TPM.</li>
  <li><strong>tpm2_pcrevent</strong>: The data is directly presented to the TPM and the TPM
calculates the data-digest prior to extending.</li>
  <li><strong>tpm2_pcrreset</strong>: The PCR index value is reset to zero. Not all PCR indices
are resettable.</li>
</ol>

<p>In the case of <strong>tpm2_pcrextend</strong> and <strong>tpm2_pcrevent</strong>, the TPM ultimately
concatenates the incoming data-digest with the current value at the PCR index,
hashes the concatenation-data and replaces the PCR index value in place.</p>

<p>It should be noted that the entity extending the PCR is inherently trusted. This
trusted entity is called a Root-of-trust-for-measurement (RTM) in TCG
terminology. <a href="https://en.wikipedia.org/wiki/Intel_vPro#Intel_Boot_Guard">Intel (R) Bootguard</a>
is an example. The tamper resistant code extends the initial measurements of the
critical portions of the pre-boot software.</p>

<p>Relevant to our example scripts in this tutorial below is an example of how to
use <strong>tpm2_pcrextend</strong> to modify PCR indices.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#</span>
<span class="c"># Let's suppose the critical portion of software to be extended is a plain text</span>
<span class="c"># "CRITICAL-DATA". We need to first calculate the hash using a crypto lib/tool</span>
<span class="c"># like openssl and then pass it to the tpm2_pcrextend command.</span>
<span class="c">#</span>
<span class="nv">SHA256_DATA</span><span class="o">=</span><span class="sb">`</span><span class="nb">echo</span> <span class="s2">"CRITICAL-DATA"</span> | openssl dgst <span class="nt">-sha256</span> <span class="nt">-binary</span> | xxd <span class="nt">-p</span> <span class="nt">-c</span> 32<span class="sb">`</span>
<span class="nv">SHA1_DATA</span><span class="o">=</span><span class="sb">`</span><span class="nb">echo</span> <span class="s2">"CRITICAL-DATA"</span> | openssl dgst <span class="nt">-sha1</span> <span class="nt">-binary</span> | xxd <span class="nt">-p</span> <span class="nt">-c</span> 20<span class="sb">`</span>

tpm2_pcrextend 0:sha1<span class="o">=</span><span class="nv">$SHA1_DATA</span>,sha256<span class="o">=</span><span class="nv">$SHA256_DATA</span>
tpm2_pcrextend 1:sha1<span class="o">=</span><span class="nv">$SHA1_DATA</span>,sha256<span class="o">=</span><span class="nv">$SHA256_DATA</span>
tpm2_pcrextend 2:sha1<span class="o">=</span><span class="nv">$SHA1_DATA</span>,sha256<span class="o">=</span><span class="nv">$SHA256_DATA</span>

<span class="c"># Let's read the PCR values now</span>

tpm2_pcrread sha1:0,1,2+sha256:0,1,2

<span class="c">#</span>
<span class="c"># The new PCR values should be as follows:</span>
<span class="c">#sha1:</span>
<span class="c">#  0 : 0xA3EBF00F6520B2C85DBBF3D32B6A8B3A30ABB748</span>
<span class="c">#  1 : 0xA3EBF00F6520B2C85DBBF3D32B6A8B3A30ABB748</span>
<span class="c">#  2 : 0xA3EBF00F6520B2C85DBBF3D32B6A8B3A30ABB748</span>
<span class="c">#sha256:</span>
<span class="c">#  0 : 0xAF42D77065F4791B6738DA5944E6B4074E3190F0993B5EE5D42DC4FBED424ABA</span>
<span class="c">#  1 : 0xAF42D77065F4791B6738DA5944E6B4074E3190F0993B5EE5D42DC4FBED424ABA</span>
<span class="c">#  2 : 0xAF42D77065F4791B6738DA5944E6B4074E3190F0993B5EE5D42DC4FBED424ABA</span>
<span class="c">#</span>

<span class="c"># Let's see how we got one of these values as a demonstration of PCR extension.</span>
<span class="nv">INITIAL_SHA1_DATA</span><span class="o">=</span><span class="s2">"0000000000000000000000000000000000000000"</span>
<span class="nv">CONCATENATED</span><span class="o">=</span><span class="sb">`</span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="nv">$INITIAL_SHA1_DATA</span><span class="p">;</span> <span class="nb">echo</span> <span class="nv">$SHA1_DATA</span><span class="sb">`</span>
<span class="nb">echo</span> <span class="nv">$CONCATENATED</span> | xxd <span class="nt">-r</span> <span class="nt">-p</span> | openssl dgst <span class="nt">-sha1</span>
<span class="c"># This should output 0xA3EBF00F6520B2C85DBBF3D32B6A8B3A30ABB748</span>
</code></pre></div></div>

<h3 id="golden-or-reference-pcr">Golden or reference PCR</h3>

<p>The term golden/ reference is not a formal terminology. It is simply a digest of
the content of the PCR indices in a PCR selection. The selection is a choice of
PCR indices across all the PCR banks. Values in a PCR index itself is a digest
of the binary blob of software/ data that represents a known good state.
The digest algorithm for individual PCR indices is the same as that of the
specific bank. Whereas, the digest of the golden/ reference state has to be
specified.</p>

<p>The golden/reference PCR state can be calculated in one of three ways:</p>

<ol>
  <li>Using the <strong>tpm2_quote</strong> tool. The signing scheme used to sign the quote
determines the digest algorithm for the quote. This should be done once on a
reference platform.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tpm2_quote <span class="se">\</span>
<span class="nt">--key-context</span> rsa_ak.ctx <span class="se">\</span>
<span class="nt">--pcr-list</span> sha1:0,1,2+sha256:0,1,2 <span class="se">\</span>
<span class="nt">--message</span> pcr_quote.plain <span class="se">\</span>
<span class="nt">--signature</span> pcr_quote.signature <span class="se">\</span>
<span class="nt">--qualification</span> SERVICE_PROVIDER_NONCE <span class="se">\</span>
<span class="nt">--hash-algorithm</span> sha256 <span class="se">\</span>
<span class="nt">--pcr</span> pcr.bin

<span class="nv">GOLDEN_PCR</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat </span>pcr.bin | openssl dgst <span class="nt">-sha256</span> <span class="nt">-binary</span> | xxd <span class="nt">-p</span> <span class="nt">-c</span> 32<span class="sb">`</span>
</code></pre></div></div>

<ol>
  <li>If only the PCR data is to be read from the reference platform, it can
always be done using <strong>tpm2_pcrread</strong> tool as well. Also, the output of the
<strong>tpm2_pcrread</strong> tool can be passed to the <strong>tpm2_checkquote</strong> tool directly.
However, when doing so, specifying the PCR-selection information to the
<strong>tpm2_checkquote</strong> tool is a must. Calculating the golden/ reference PCR data
using this method is shown below.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tpm2_pcrread sha1:0,1,2+sha256:0,1,2 <span class="nt">-o</span> pcr.bin

<span class="nv">GOLDEN_PCR</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat </span>pcr.bin | openssl dgst <span class="nt">-sha256</span> <span class="nt">-binary</span> | xxd <span class="nt">-p</span> <span class="nt">-c</span> 32<span class="sb">`</span>
</code></pre></div></div>

<ol>
  <li>Entirely without the TPM as shown below.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">CONCATENATE_ALL_DIGESTS</span><span class="o">=</span><span class="sb">`</span><span class="se">\</span>
<span class="nb">echo</span> <span class="nv">$SHA1_DATA</span>
<span class="nb">echo</span> <span class="nv">$SHA1_DATA</span>
<span class="nb">echo</span> <span class="nv">$SHA1_DATA</span>
<span class="nb">echo</span> <span class="nv">$SHA256_DATA</span>
<span class="nb">echo</span> <span class="nv">$SHA256_DATA</span>
<span class="nb">echo</span> <span class="nv">$SHA256_DATA</span>
<span class="sb">`</span>
<span class="nv">GOLDEN_PCR</span><span class="o">=</span><span class="sb">`</span><span class="se">\</span>
<span class="nb">echo</span> <span class="nv">$CONCATENATE_ALL_DIGESTS</span> |
xxd <span class="nt">-r</span> <span class="nt">-p</span> | openssl <span class="nt">-dgst</span> <span class="nt">-sha256</span> <span class="nt">-binary</span> | xxd <span class="nt">-p</span> <span class="nt">-c</span> 32
<span class="sb">`</span>
</code></pre></div></div>

<p>Using any of the 3 methods above the GOLDEN_PCR value is
“e756e3af77a4f15a3f2ed489a7411a93d91d619506b6d1ed1121faaeaf45d8de”.</p>

<h2 id="system-software-state">System software state</h2>

<p>In a nutshell, this is a single digest aka measurement of interesting/ critical
pieces of system software. To do this, a trusted portion of the software does
the following:</p>
<ol>
  <li>Calculates the hash of the software module that will be loaded for execution.</li>
  <li>Sends over the digest to the TPM and requests it be extended in the PCR.</li>
</ol>

<p>Note: The trusted portion of the system software extending measurements is
termed root-of-trust-for-measurement (RTM). This is inherently trusted.</p>

<p>Throughout the platform boot process, a log of all executable code and relevant
configuration data is created and extended into PCRs. Each time a PCR is
extended, a log entry is made in the TCG event log. This allows a challenger to
see how the final PCR digests were built. The event log can be examined using
the <a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_eventlog.1.md">tpm2_eventlog</a>
tool. The event log is typically stored at this location
/sys/kernel/security/tpm0/binary_bios_measurements.</p>

<h2 id="roots-of-trust-for-reporting-rtr">Roots of trust for reporting (RTR)</h2>

<p>The private or sensitive portion of the TPM key object is protected by the TPM.
Couple this with authentication and enhanced authorization models the TPM
design affords, the signatures generated from such keys are deemed trustworthy.
As discussed earlier that identity is yet another facet to the trustworthiness of
the signature and hence the data. We also determined that in order to preserve
the privacy of the end user there is need for both anonymous identity and
a unique identity that are cryptographically bound. Together these requirements
form a criterion for defining a TPM object and these properties make the TPM a
root of trust for reporting (RTR).</p>

<p>Of the four hierarchies the TPM is partitioned into, the endorsement hierarchy
is to be used by the privacy administrator. The primary key created under the
endorsement hierarchy provides the unique identity and is called the endorsement
key (EK). Following properties make EKs special amongst other primary keys that
can be created under any of the hierarchies:</p>
<ol>
  <li>TCG EK cannot be used as a signing key.</li>
  <li>TCG EK authentication is a policy that references endorsement hierarchy
authorization.</li>
  <li>TCG EK are certified by the TPM manufacturer.
More details on the key can be found from
<a href="https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_Credential_Profile_EK_V2.1_R13.pdf">TCG EK credential specification</a>.
As already mentioned, the EK is a primary key and so can be created using the
<a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createprimary.1.md">tpm2_createprimary</a>
tool by supplying the right attributes and authorization policy. In order to
simplify attestation, a tool
<a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createek.1.md">tpm2_createek</a>
is also available that has all the defaults specified by TCG EK credential spec.</li>
</ol>

<p>The anonymous identity is the attestation identity key (AIK) created with the EK
as its parent. There is no specific key template that is mandated by TCG that
determines the AIK key attributes or authorization model. Since the key is
typically used in privacy sensitive operations like quoting/ signing/ certifying
, the key is a signing key created under endorsement hierarchy with privacy
administrator controls. And so it’s authorization model typically references the
authorization of the endorsement hierarchy through a policy. The association of
the AIK to an EK is done using a cryptographical method called credential
activation. Unlike EK which is a constant/ unique primary key that can be
re-created, the AIK keys are ephemeral. In that, every time an AIK is created it
results in a brand-new key and thus makes the key anonymous. The AIK as
mentioned is a child of the EK primary key and can be created with the tool
<a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_create.1.md">tpm2_create</a>.
Alternatively, the key can also be created using the <a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_createak.1.md">tpm2_createak</a>
in order to simply attestation. The tool implements the TPM2_CC_Create command
with the most commonly used AIK properties.</p>

<p>In summary,</p>
<ol>
  <li>The TPM manufacturer EK certificate vouches for unique identity;
while the credential activation process vouches the association of the AIK to
the EK and hence the TPM.</li>
  <li>tpm2_createek and tpm2_createak tools can be used to create EK and AIK. Any
further customizations to the keys outside the chosen defaults can be done by
creating the objects with tpm2_createprimary and tpm2_create respectively.</li>
</ol>

<p>Note:
System software state can also be deemed as a system’s trusted identity without
requiring a signing key. Such an identity is only useful for self attestation of
the system. This is also known as local attestation. Local attestation has use
cases like <a href="https://tpm2-software.github.io/2020/04/13/Disk-Encryption.html">sealing-encryption-secrets</a>
or using PCR state as proxy authentication model to make authorization for TPM
objects valid as long as system identity aka system software state does not
change.</p>

<h1 id="roles-identified-in-the-bare-bone-remote-attestation-model">Roles identified in the bare bone remote attestation model</h1>

<p>The primary goals for the minimal bare bone remote attestation are:</p>
<ol>
  <li>To demonstrate verification of an attestation quote.</li>
  <li>The quote should contain the digest of the PCR values representing system
software state.</li>
  <li>Signer of the quote should be anonymous to the verifier; yet the verifier
should be able to make a determination that the quote was signed by a valid
signer.</li>
</ol>

<p>To achieve the goals it is sufficient to have 3 players, namely:</p>
<ol>
  <li>Device-Node: The edge platform with a TPM whose system software state is of
interest. It generates the attestation structures with digest of PCR data
included in the quotes. The platform signs the quotes with an attestation
identity key for anonymity. AIK is cryptographically bound to the unique
identity key on the same platform. The unique identity key is the
endorsement-key (EK).</li>
  <li>Privacy-CA: The only trusted entity that can prove the association of an AIK
to a valid EK without disclosing the EK to the “Service-Provider”. This is
also the only entity in addition to the “Device-Node” that knows the EK for a
given AIK from the “Device-Node“.</li>
  <li>Service-Provider: The entity that the “Device-Node“ communicates with to
avail services. The “Service-Provider“ need to ensure the following:<br />
a. Entity requesting services has registered its unique identity with
   the “Privacy-CA“.<br />
b. Anonymous identity belongs to the pool of registered unique identities
   that the “Privacy-CA“ stores.<br />
c. System software state of the “Device-Node“ is an acceptable one.</li>
</ol>

<p><strong>In practice, however the various roles as shown here can be further broken
down. As an example, all the verifications for anonymous-identity and
system-software state can be handed off to an additional “Verifier“ role.</strong></p>

<p>Let’s now look at the various stages of our example attestation framework.</p>
<ol>
  <li>Service-registration.</li>
  <li>Service-request Part 1 (Anonymous identity validation).</li>
  <li>Service-request Part 2 (Platform software state validation).</li>
  <li>Service-delivery.</li>
</ol>

<h2 id="device-service-registration">Device service registration</h2>

<p>This is the stage where the “Device-Node“ requests services from the
“Service-Provider“. The “Service-Provider“ has two requirements at this stage.</p>
<ol>
  <li>The “Device-Node“ sends its unique key to the “Privacy-CA“</li>
  <li>The “Privacy-CA“ verifies the genuineness of the EK from the EK certificate
validation and also the presence of the EK on the platform through the
credential-activation process.</li>
</ol>

<p>In order to verify that #1 &amp; #2 above happened, the “Service-Provider“ creates
an ephemeral secret called REGISTRATION-TOKEN that it shares only with the
Privacy-CA who in turn reveals it to the “Device-Node“ if and only if all
verifications on EK-certificate and Credential-Activation pass which are only
possible if “Device-Node“ communicates the platform EK and AIK with the
Privacy-CA. The “Device-Node“ then presents the REGISTRATION-TOKEN to the
“Service-Provider“ to complete registration.</p>

<p>Note: The “Service-Provider“ has no further information recorded about the
platform at the end of the registration. It only knows that a registration
request was made by some platform and that it’s EK is registered in the pool
of valid EKs with the Privacy-CA.</p>

<p>The sequence diagram below shows the interactions during the registration.
<img src="/images/tpm2-attestation-demo/registration.png" alt="Registration" /></p>

<h2 id="service-request-part-1-platform-anonymous-identity-validation">Service request Part 1 (Platform Anonymous Identity Validation)</h2>

<p>This is the stage where a registered platform makes a service request to the
“Service-Provider“ and sends an ephemeral AIK to securely procure the services.
The “Service-Provider“ needs to know the following:</p>
<ol>
  <li>The AIK is a valid one and that the Privacy-CA can prove that the AIK is
bound to an EK from the Privacy-CA’s trusted pool of EKs.</li>
  <li>The AIK is from a TPM currently accessible to the platform.</li>
</ol>

<p>In order to achieve this, The Privacy-CA needs to request the EK from the
platform and also ensure the AIK is present on the platform through the
credential activation process.</p>

<p>In order to verify these interactions between the “Privacy-CA“ and the
“Device-Node“ occurred, the “Service-Provider“ creates an ephemeral secret called
SERVICE-TOKEN that it shares with the “Privacy-CA“ who in turn reveals it to the
“Device-Node“ after a successful credential activation process. The “Device-Node“
now proves the validity of the service request by presenting the SERVICE-TOKEN
back to the “Service-Provider“.</p>

<p>The sequence diagram below shows the interactions during the service-request.
<img src="/images/tpm2-attestation-demo/identity-validation.png" alt="Identity-validation" /></p>

<h2 id="service-request-part-2-platform-software-state-validation">Service request Part 2 (Platform Software State Validation)</h2>

<p>At this stage, by validating the “SERVICE-TOKEN” presented by the device, the
“Service-Provider“ has ascertained the AIK comes from a registered platform and
that it is a trusted signing key. Now the “Service-Provider“ needs to assured of
the system-software state of the “Device-Node“. To achieve this the
“Service-Provider“ requests an attestation quote from the “Device-Node“ that has
to be signed with the AIK. In order to prevent replay attacks, the
“Service-Provider“ generates a NONCE that needs to be added to the attestation
quote before signing.</p>

<p>Below is a YAML representation of PCR included attestation data returned by
tpm2_quote.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">TPM2B_ATTEST_DATA</span><span class="pi">:</span>
    <span class="s">size</span>
    <span class="s">attestationData</span><span class="err">:</span>
        <span class="s">magic</span>
        <span class="s">type</span>
        <span class="s">qualifiedSigner</span>
        <span class="s">extraData</span>
        <span class="s">clockInfo</span><span class="err">:</span>
            <span class="s">clock</span>
            <span class="s">resetCount</span>
            <span class="s">restartCount</span>
            <span class="s">safe</span>
        <span class="s">firmwareVersion</span>
        <span class="s">quote</span><span class="err">:</span>
            <span class="s">pcrSelect</span>
                <span class="s">count</span>
                <span class="s">pcrSelections[TPM2_NUM_PCR_BANKS]</span><span class="err">:</span>
                    <span class="s">hash</span>
                    <span class="s">sizeofSelect</span>
                    <span class="s">pcrSelect[TPM2_PCR_SELECT_MAX]</span>
            <span class="s">pcrDigest</span>
</code></pre></div></div>

<p>Shown above in yaml representation is all the information included in an
attestation quote. Brief description of the important fields follow:</p>

<ul>
  <li>
    <p>magic: the indication that this structure was created by a TPM always
TPM2_GENERATED_VALUE.</p>
  </li>
  <li>
    <p>type: The type of the attestation structure. It is TPM2_ST_ATTEST_QUOTE for
the type that has the PCR information and being discussed at length here in.</p>
  </li>
  <li>
    <p>qualifiedSigner: Qualified Name of the signing key. The term qualified name
is the digest of all the Names of all the ancestor keys back to the Primary Seed
at the root of the hierarchy.</p>
  </li>
  <li>
    <p>extraData: External information supplied by caller. The NONCE generated by the
“Service-Provider“ is added here in this field.</p>
  </li>
  <li>
    <p>Clock: The time in milliseconds during which the TPM has been powered. This
value is reset to zero when the Storage Primary Seed is changed TPM2_Clear.</p>
  </li>
  <li>
    <p>resetCount: The number of occurrences of TPM Reset since the last TPM2_Clear.</p>
  </li>
  <li>
    <p>restartCount: The number of times that TPM2_Shutdown or _TPM_Hash_Start have
occurred since the last TPM Reset or TPM2_Clear.</p>
  </li>
  <li>
    <p>Safe: Indicates that no value of Clock greater than the current value of Clock
has been previously reported by the TPM. Set to YES on TPM2_Clear.</p>
  </li>
  <li>
    <p>firmwareVersion: TPM vendor-specific value identifying the version number of
the firmware.</p>
  </li>
  <li>
    <p>pcrSelect: The information on algID, PCR selected, and the digest.</p>
  </li>
  <li>
    <p>count: The number of selection structures. A value of zero is allowed. This
indicates the count of selected PCR banks (SHA1, SHA256, etc.)</p>
  </li>
  <li>pcrSelections: This is a list of PCR selection structures.
    <ol>
      <li>
        <p>hash: The hash algorithm associated with the selection bank.</p>
      </li>
      <li>
        <p>sizeofSelect: The size in octets of the pcrSelect array. This
 indicates number of bytes required to represent all the
 PCRs in a bank. Every PCR is represented as a bit. E.g. For 24 PCRs per bank
 the sizeofselect should be 3 bytes.</p>
      </li>
      <li>
        <p>pcrSelect: The bit map of selected PCR (the least significant byte first)</p>
      </li>
    </ol>
  </li>
  <li>pcrDigest: The digest of selected PCR using hash algorithm of the signing key.</li>
</ul>

<p>Below is an example dump from an attestation quote for PCR0 from SHA1 bank and
PCR0, PCR1 from SHA256 bank.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">magic</span><span class="pi">:</span> <span class="s">ff544347</span>
<span class="na">type</span><span class="pi">:</span> <span class="m">8018</span>
<span class="na">qualifiedSigner</span><span class="pi">:</span> <span class="s">000bfebea9500be6aff07565dc09537ae5c887e1cc550a1a4653a618f86486ac28fe</span>
<span class="na">extraData</span><span class="pi">:</span> <span class="m">12345678</span>
<span class="na">clockInfo</span><span class="pi">:</span>
  <span class="na">clock</span><span class="pi">:</span> <span class="m">2260078</span>
  <span class="na">resetCount</span><span class="pi">:</span> <span class="m">0</span>
  <span class="na">restartCount</span><span class="pi">:</span> <span class="m">0</span>
  <span class="na">safe</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">firmwareVersion</span><span class="pi">:</span> <span class="m">3636160019061720</span>
<span class="na">attested</span><span class="pi">:</span>
  <span class="na">quote</span><span class="pi">:</span>
    <span class="na">pcrSelect</span><span class="pi">:</span>
      <span class="na">count</span><span class="pi">:</span> <span class="m">2</span>
      <span class="na">pcrSelections</span><span class="pi">:</span>
        <span class="na">0</span><span class="pi">:</span>
          <span class="na">hash</span><span class="pi">:</span> <span class="s">11 (sha256)</span>
          <span class="na">sizeofSelect</span><span class="pi">:</span> <span class="m">3</span>
          <span class="na">pcrSelect</span><span class="pi">:</span> <span class="m">010000</span>
        <span class="na">1</span><span class="pi">:</span>
          <span class="na">hash</span><span class="pi">:</span> <span class="s">4 (sha1)</span>
          <span class="na">sizeofSelect</span><span class="pi">:</span> <span class="m">3</span>
          <span class="na">pcrSelect</span><span class="pi">:</span> <span class="m">030000</span>
    <span class="na">pcrDigest</span><span class="pi">:</span> <span class="s">834a709ba2534ebe3ee1397fd4f7bd288b2acc1d20a08d6c862dcd99b6f04400</span>
</code></pre></div></div>

<p>The sequence diagram below shown the interactions during this stage.
<img src="/images/tpm2-attestation-demo/software-state-validation.png" alt="Software-state-validation" /></p>

<h2 id="service-delivery">Service delivery</h2>

<p>At this stage, by validating the “SERVICE-TOKEN“ and the attestation-quote it
received from the “Device-Node“, the “Service-Provider“ has ascertained the
“Device-Node“ anonymous identity and system-software state. With the system in
a known state, the “Service-Provider“ can now wrap the “SERVICE-SECRET“ with a service-content-key signed by the
device AIK.<br /></p>

<p><img src="/images/tpm2-attestation-demo/service-delivery.png" alt="Service-delivery" /></p>

<h1 id="simple-attestation-with-tpm2-tools">Simple attestation with tpm2-tools</h1>

<p>The following demonstration shows the tpm2-tools involved in the sequence
diagrams discussed above. Following the demonstration of the tpm2-tools in this
section, there is a subsequent section showing the scripts for the different
roles and their interactions in the simple attestation framework. It involves
scripting the tools and the logic to move identities, quotes, tokens, nonce,
etc. between the “Service-Provider“, “Device-Node“ and the “Privacy-CA“.</p>

<p>With that preface, let’s dive straight into the tpm2-tools.</p>

<ol>
  <li>“Device-Node“ creating the endorsement-key and the attestation-identity-key.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
tpm2_createek <span class="se">\</span>
<span class="nt">--ek-context</span> rsa_ek.ctx <span class="se">\</span>
<span class="nt">--key-algorithm</span> rsa <span class="se">\</span>
<span class="nt">--public</span> rsa_ek.pub

tpm2_createak <span class="se">\</span>
<span class="nt">--ek-context</span> rsa_ek.ctx <span class="se">\</span>
<span class="nt">--ak-context</span> rsa_ak.ctx <span class="se">\</span>
<span class="nt">--key-algorithm</span> rsa <span class="se">\</span>
<span class="nt">--hash-algorithm</span> sha256 <span class="se">\</span>
<span class="nt">--signing-algorithm</span> rsassa <span class="se">\</span>
<span class="nt">--public</span> rsa_ak.pub <span class="se">\</span>
<span class="nt">--private</span> rsa_ak.priv <span class="se">\</span>
<span class="nt">--ak-name</span> rsa_ak.name
</code></pre></div></div>

<ol>
  <li>“Device-Node“ retrieving the endorsement-key-certificate to send to the
“Privacy-CA“. There are two possible locations where the endorsement key
certificates are provided by the TPM manufacturer. While most TPM manufacturers
store them in the <a href="(https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_Credential_Profile_EK_V2.1_R13.pdf)">TCG specified NV indices</a>
, some make it available for download through a web hosting. Let’s look at both
these methods.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Location 1 - TPM2 NV Index 0x1c00002 is the TCG specified location for RSA-EK-certificate.</span>
<span class="nv">RSA_EK_CERT_NV_INDEX</span><span class="o">=</span>0x01C00002

<span class="nv">NV_SIZE</span><span class="o">=</span><span class="sb">`</span>tpm2_nvreadpublic <span class="nv">$RSA_EK_CERT_NV_INDEX</span> | <span class="nb">grep </span>size |  <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>

tpm2_nvread <span class="se">\</span>
<span class="nt">--hierarchy</span> owner <span class="se">\</span>
<span class="nt">--size</span> <span class="nv">$NV_SIZE</span> <span class="se">\</span>
<span class="nt">--output</span> rsa_ek_cert.bin <span class="se">\</span>
<span class="nv">$RSA_EK_CERT_NV_INDEX</span>

<span class="c"># Location 2 - Web hosting. This applies specifically to Intel(R) PTT RSA-EK-certificate.</span>
tpm2_getekcertificate <span class="se">\</span>
<span class="nt">--ek-public</span> rsa_ek.pub <span class="se">\</span>
<span class="nt">--offline</span> <span class="se">\</span>
<span class="nt">--allow-unverified</span> <span class="se">\</span>
<span class="nt">--ek-certificate</span> rsa_ek_cert.bin

<span class="c">## convert to a standard DER format</span>
<span class="nb">sed</span> <span class="s1">'s/-/+/g;s/_/\//g;s/%3D/=/g;s/^{.*certificate":"//g;s/"}$//g;'</span> <span class="se">\</span>
rsa_ek_cert.bin | <span class="nb">base64</span> <span class="nt">--decode</span> <span class="o">&gt;</span> rsa_ek_cert.bin
</code></pre></div></div>

<ol>
  <li>“Privacy-CA“ and the “Device-Node“ performing a credential activation
challenge in order to verify the AIK is bound to the EK from the EK-certificate
originally shared by the “Device-Node“. This is done in two different instances
in the proposed simple-attestation-framework — Once when the “Service-Provider“
requests the “Device-Node“ to send over the identities as part of the service
registration process. And the second time when the “Device-Node“ sends its AIK
to the “Service-Provider“ and the “Service-Provider“ in turn sends it over to
the “Privacy-CA“ in order to verify the anonymous identity.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Privacy-CA creating the wrapped credential and encryption key</span>
<span class="nv">file_size</span><span class="o">=</span><span class="sb">`</span><span class="nb">stat</span> <span class="nt">--printf</span><span class="o">=</span><span class="s2">"%s"</span> rsa_ak.name<span class="sb">`</span>
<span class="nv">loaded_key_name</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat </span>rsa_ak.name | xxd <span class="nt">-p</span> <span class="nt">-c</span> <span class="nv">$file_size</span><span class="sb">`</span>

<span class="nb">echo</span> <span class="s2">"this is my secret"</span> <span class="o">&gt;</span> file_input.data
tpm2_makecredential <span class="se">\</span>
<span class="nt">--tcti</span> none <span class="se">\</span>
<span class="nt">--encryption-key</span> rsa_ek.pub <span class="se">\</span>
<span class="nt">--secret</span> file_input.data <span class="se">\</span>
<span class="nt">--name</span> <span class="nv">$loaded_key_name</span> <span class="se">\</span>
<span class="nt">--credential-blob</span> cred.out

<span class="c"># Device-Node activating the credential</span>
tpm2_startauthsession <span class="se">\</span>
<span class="nt">--policy-session</span> <span class="se">\</span>
<span class="nt">--session</span> session.ctx

<span class="nv">TPM2_RH_ENDORSEMENT</span><span class="o">=</span>0x4000000B
tpm2_policysecret <span class="nt">-S</span> session.ctx <span class="nt">-c</span> <span class="nv">$TPM2_RH_ENDORSEMENT</span>

tpm2_activatecredential <span class="se">\</span>
<span class="nt">--credentialedkey-context</span> rsa_ak.ctx <span class="se">\</span>
<span class="nt">--credentialkey-context</span> rsa_ek.ctx <span class="se">\</span>
<span class="nt">--credential-blob</span> cred.out <span class="se">\</span>
<span class="nt">--certinfo-data</span> actcred.out <span class="se">\</span>
<span class="nt">--credentialkey-auth</span> <span class="s2">"session:session.ctx"</span>

tpm2_flushcontext session.ctx
</code></pre></div></div>

<ol>
  <li>“Device-Node“ generating the PCR attestation quote on request from the
“Service-Provider“. The “Service-Provider“ specifies the PCR-banks, PCR-indices,
and the ephemeral NONCE data. The NONCE is to ensure there is no possibility of
a replay attack on the quote verification and validation process. Validity of
the signing key for attestation quote is ascertained to be a valid one by the
“Privacy-CA“.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"12345678"</span> <span class="o">&gt;</span> SERVICE_PROVIDER_NONCE

tpm2_quote <span class="se">\</span>
<span class="nt">--key-context</span> rsa_ak.ctx <span class="se">\</span>
<span class="nt">--pcr-list</span> sha1:0,1,2+sha256:0,1,2 <span class="se">\</span>
<span class="nt">--message</span> pcr_quote.plain <span class="se">\</span>
<span class="nt">--signature</span> pcr_quote.signature <span class="se">\</span>
<span class="nt">--qualification</span> SERVICE_PROVIDER_NONCE <span class="se">\</span>
<span class="nt">--hash-algorithm</span> sha256 <span class="se">\</span>
<span class="nt">--pcr</span> pcr.bin
</code></pre></div></div>

<ol>
  <li>“Service-Provider“ verifying the attestation quote generated and signed by
the “Device-Node“. To make the determination of the software-state of the
“Device-Node“, after the signature and nonce verification process, the
“Service-Provider“ validates the digest of the PCR values in the quote against
a known-good-valid —the <a href="#golden-or-reference-pcr">golden/ reference value</a>
ascertained previously.</li>
</ol>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tpm2_checkquote <span class="se">\</span>
<span class="nt">--public</span> rsa_ak.pub <span class="se">\</span>
<span class="nt">--message</span> pcr_quote.plain <span class="se">\</span>
<span class="nt">--signature</span> pcr_quote.signature <span class="se">\</span>
<span class="nt">--qualification</span> SERVICE_PROVIDER_NONCE <span class="se">\</span>
<span class="nt">--pcr</span> pcr.bin
</code></pre></div></div>

<h1 id="scripts-for-implementation-of-the-simple-attestation-framework">Scripts for implementation of the simple attestation framework</h1>

<h2 id="device-node">Device-Node</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Fixed location</span>
<span class="nv">service_provider_location</span><span class="o">=</span><span class="s2">"</span><span class="nv">$PWD</span><span class="s2">/../SP"</span>

<span class="c"># PCA location</span>
<span class="nv">privacy_ca_location</span><span class="o">=</span><span class="s2">""</span>

<span class="c"># Location for node 1, node 2, etc.</span>
<span class="nv">device_location</span><span class="o">=</span><span class="s2">"</span><span class="nv">$PWD</span><span class="s2">"</span>

<span class="c"># State</span>
<span class="nv">event_file_found</span><span class="o">=</span>0
<span class="nv">device_registration_request</span><span class="o">=</span>0
<span class="nv">device_service_request</span><span class="o">=</span>0

wait_loop<span class="o">()</span> <span class="o">{</span>
    <span class="nv">counter</span><span class="o">=</span>1
    <span class="k">until</span> <span class="o">[</span> <span class="nv">$counter</span> <span class="nt">-gt</span> <span class="nv">$1</span> <span class="o">]</span>
    <span class="k">do
       </span><span class="nb">test</span> <span class="nt">-f</span> <span class="nv">$2</span>
       <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
          </span><span class="nv">event_file_found</span><span class="o">=</span>1
          <span class="nb">break
       </span><span class="k">else
          </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"Waiting </span><span class="nv">$1</span><span class="s2"> seconds: </span><span class="nv">$counter</span><span class="s2">"</span><span class="s1">'\r'</span>
       <span class="k">fi</span>
       <span class="o">((</span>counter++<span class="o">))</span>
       <span class="nb">sleep </span>1
    <span class="k">done</span>
<span class="o">}</span>

LOG_ERROR<span class="o">()</span> <span class="o">{</span>
    <span class="nv">errorstring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[31mFAIL: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">errorstring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

LOG_INFO<span class="o">()</span> <span class="o">{</span>
    <span class="nv">messagestring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[93mPASS: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">messagestring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

await_and_compelete_credential_challenge<span class="o">()</span> <span class="o">{</span>
    
    <span class="c"># Wait for credential challenge</span>
    <span class="nv">cred_status_string</span><span class="o">=</span><span class="s2">"Encrypted credential receipt from Privacy-CA."</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> cred.out
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$cred_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span><span class="nv">event_file_found</span><span class="o">=</span>0
    LOG_INFO <span class="s2">"</span><span class="nv">$cred_status_string</span><span class="s2">"</span>

    tpm2_startauthsession <span class="nt">--policy-session</span> <span class="nt">--session</span> session.ctx <span class="nt">-Q</span>

    <span class="nv">TPM2_RH_ENDORSEMENT</span><span class="o">=</span>0x4000000B
    tpm2_policysecret <span class="nt">-S</span> session.ctx <span class="nt">-c</span> <span class="nv">$TPM2_RH_ENDORSEMENT</span> <span class="nt">-Q</span>

    tpm2_activatecredential <span class="nt">--credentialedkey-context</span> rsa_ak.ctx <span class="se">\</span>
    <span class="nt">--credentialkey-context</span> rsa_ek.ctx <span class="nt">--credential-blob</span> cred.out <span class="se">\</span>
    <span class="nt">--certinfo-data</span> actcred.out <span class="nt">--credentialkey-auth</span> <span class="s2">"session:session.ctx"</span> <span class="nt">-Q</span>
    
    <span class="nb">rm</span> <span class="nt">-f</span> cred.out

    tpm2_flushcontext session.ctx <span class="nt">-Q</span>

    <span class="nb">rm</span> <span class="nt">-f</span> session.ctx
<span class="o">}</span>

device_registration<span class="o">()</span> <span class="o">{</span>

    <span class="c"># Send device location to service-provider</span>
    <span class="nb">echo</span> <span class="s2">"device_location: </span><span class="nv">$device_location</span><span class="s2">"</span> <span class="o">&gt;</span> d_s_registration.txt
    <span class="nb">cp </span>d_s_registration.txt <span class="nv">$service_provider_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_registration.txt

    <span class="c"># Wait for PCA location information from service provider</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> s_d_registration.txt
    <span class="nv">registration_status_string</span><span class="o">=</span><span class="s2">"Privacy-CA information receipt from Service-Provider."</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span><span class="nv">event_file_found</span><span class="o">=</span>0
    LOG_INFO <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
    <span class="nv">privacy_ca_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>privacy_ca_location s_d_registration.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_registration.txt

    <span class="nv">registration_status_string</span><span class="o">=</span><span class="s2">"Acknowledgement reciept from Privacy-CA."</span>
    wait_loop <span class="nv">$max_wait</span> p_d_pca_ready.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span><span class="nv">event_file_found</span><span class="o">=</span>0
    LOG_INFO <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_pca_ready.txt

    <span class="c">#Ready EKcertificate, EK and AIK and set ready status so PCA can pull</span>
    tpm2_createek <span class="nt">--ek-context</span> rsa_ek.ctx <span class="nt">--key-algorithm</span> rsa <span class="se">\</span>
    <span class="nt">--public</span> rsa_ek.pub <span class="nt">-Q</span>

    tpm2_createak <span class="se">\</span>
        <span class="nt">--ek-context</span> rsa_ek.ctx <span class="se">\</span>
        <span class="nt">--ak-context</span> rsa_ak.ctx <span class="se">\</span>
        <span class="nt">--key-algorithm</span> rsa <span class="se">\</span>
        <span class="nt">--hash-algorithm</span> sha256 <span class="se">\</span>
        <span class="nt">--signing-algorithm</span> rsassa <span class="se">\</span>
        <span class="nt">--public</span> rsa_ak.pub <span class="se">\</span>
        <span class="nt">--private</span> rsa_ak.priv <span class="se">\</span>
        <span class="nt">--ak-name</span> rsa_ak.name <span class="se">\</span>
        <span class="nt">-Q</span>
    tpm2_readpublic <span class="nt">-c</span> rsa_ak.ctx <span class="nt">-f</span> pem <span class="nt">-o</span> rsa_ak.pub <span class="nt">-Q</span>

    <span class="nb">touch </span>fake_ek_certificate.txt

    <span class="nb">touch </span>d_p_device_ready.txt
    <span class="nb">cp </span>d_p_device_ready.txt <span class="nv">$privacy_ca_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> d_p_device_ready.txt

    <span class="nv">registration_status_string</span><span class="o">=</span><span class="s2">"Credential activation challenge."</span>
    await_and_compelete_credential_challenge
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_INFO <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
        <span class="nb">cp </span>actcred.out <span class="nv">$privacy_ca_location</span>/.
        <span class="nb">rm</span> <span class="nt">-f</span> actcred.out
        <span class="k">return </span>0
    <span class="k">else
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi</span>
<span class="o">}</span>

request_device_registration <span class="o">()</span> <span class="o">{</span>

    device_registration
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        return </span>1
    <span class="k">fi

    </span><span class="nv">device_registration_status_string</span><span class="o">=</span><span class="s2">"Registration token receipt from Privacy-CA."</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> p_d_registration_token.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$device_registration_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$device_registration_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nb">cp </span>p_d_registration_token.txt <span class="se">\</span>
    <span class="nv">$service_provider_location</span>/d_s_registration_token.txt
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_registration_token.txt

    <span class="k">return </span>0
<span class="o">}</span>

<span class="c">#</span>
<span class="c"># Request service with the Service-Provider</span>
<span class="c"># Read the Privacy-CA location from Service-Provider</span>
<span class="c"># Deliver EK, AIK, EKcertificate to the Privacy-CA</span>
<span class="c"># Complete credential challenge with the Privacy-CA</span>
<span class="c"># Retrieve the SERVICE-TOKEN from the Privacy-CA</span>
<span class="c"># Present the SEVICE-TOKEN to the Service-Provider</span>
<span class="c">#</span>
process_device_anonymous_identity_challenge<span class="o">()</span> <span class="o">{</span>

   <span class="c"># Start device service</span>
   <span class="nb">test</span> <span class="nt">-f</span> <span class="nv">$device_service_aik</span>
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"Aborting service request - AIK could not be found."</span>
      <span class="k">return </span>1
   <span class="k">else
      </span><span class="nb">echo</span> <span class="s2">"device_location: </span><span class="nv">$device_location</span><span class="s2">"</span> <span class="o">&gt;</span> d_s_service.txt
      <span class="nb">cp </span>d_s_service.txt <span class="nv">$service_provider_location</span>/.
      <span class="nb">rm</span> <span class="nt">-f</span> d_s_service.txt
      <span class="nb">cp</span> <span class="nv">$device_service_aik</span> <span class="nv">$service_provider_location</span>/d_s_service_aik.pub
   <span class="k">fi

   </span><span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Privacy-CA information receipt from Service-Provider."</span>
   <span class="nv">max_wait</span><span class="o">=</span>60
   wait_loop <span class="nv">$max_wait</span> s_d_service.txt
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
    </span><span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nv">privacy_ca_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>privacy_ca_location s_d_service.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_service.txt
    LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
   <span class="k">else
    </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
    <span class="k">return </span>1
   <span class="k">fi

    </span><span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Acknowledgement receipt from Privacy-CA."</span>
    wait_loop <span class="nv">$max_wait</span> p_d_pca_ready.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi

    </span>LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_pca_ready.txt

    <span class="nb">touch </span>d_p_device_ready.txt
    <span class="nb">cp </span>d_p_device_ready.txt <span class="nv">$privacy_ca_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> d_p_device_ready.txt

    <span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Credential activation challenge."</span>
    await_and_compelete_credential_challenge
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
        <span class="nb">cp </span>actcred.out <span class="nv">$privacy_ca_location</span>/.
        <span class="nb">rm</span> <span class="nt">-f</span> actcred.out
    <span class="k">else
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
        <span class="nb">rm</span> <span class="nt">-f</span> actcred.out
        <span class="k">return </span>1
    <span class="k">fi

    </span><span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Service-Token receipt from Privacy-CA."</span>
    wait_loop <span class="nv">$max_wait</span> p_d_service_token.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nb">cp </span>p_d_service_token.txt <span class="se">\</span>
    <span class="nv">$service_provider_location</span>/d_s_service_token.txt
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_service_token.txt

   <span class="k">return </span>0
<span class="o">}</span>

process_device_software_state_validation_request<span class="o">()</span> <span class="o">{</span>

    <span class="nv">software_state_string</span><span class="o">=</span><span class="s2">"PCR selection list receipt from Service-Provider"</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> s_d_pcrlist.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$software_state_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$software_state_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nv">pcr_selection</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>pcr-selection s_d_pcrlist.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nv">service_provider_nonce</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>nonce s_d_pcrlist.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_pcrlist.txt

    tpm2_quote <span class="nt">--key-context</span> rsa_ak.ctx <span class="nt">--message</span> attestation_quote.dat <span class="se">\</span>
    <span class="nt">--signature</span> attestation_quote.signature <span class="se">\</span>
    <span class="nt">--qualification</span> <span class="s2">"</span><span class="nv">$service_provider_nonce</span><span class="s2">"</span> <span class="se">\</span>
    <span class="nt">--pcr-list</span> <span class="s2">"</span><span class="nv">$pcr_selection</span><span class="s2">"</span> <span class="se">\</span>
    <span class="nt">--pcr</span> pcr.bin <span class="nt">-Q</span>

    <span class="nb">cp </span>attestation_quote.dat attestation_quote.signature pcr.bin <span class="se">\</span>
    <span class="nv">$service_provider_location</span>/.

    <span class="k">return </span>0
<span class="o">}</span>

process_encrypted_service_data_content<span class="o">()</span> <span class="o">{</span>

    <span class="nv">service_data_status_string</span><span class="o">=</span><span class="s2">"Encrypted service-data-content receipt from Service-Provider"</span>
    <span class="nv">max_wait</span><span class="o">=</span>6
    wait_loop <span class="nv">$max_wait</span> s_d_service_content.encrypted
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$service_data_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$service_data_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0

    <span class="nv">service_data_status_string</span><span class="o">=</span><span class="s2">"Decryption of service-data-content receipt from Service-Provider"</span>
    tpm2 rsadecrypt <span class="nt">-c</span> service_content_key.ctx <span class="nt">-o</span> s_d_service_content.decrypted <span class="se">\</span>
    s_d_service_content.encrypted <span class="nt">-Q</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$service_data_status_string</span><span class="s2">"</span>
        <span class="nb">rm</span> <span class="nt">-f</span> s_d_service_content.encrypted
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$service_data_status_string</span><span class="s2">"</span>

    <span class="nv">SERVICE_CONTENT</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat </span>s_d_service_content.decrypted<span class="sb">`</span>
    LOG_INFO <span class="s2">"Service-content: </span><span class="se">\e</span><span class="s2">[5m</span><span class="nv">$SERVICE_CONTENT</span><span class="s2">"</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_service_content.<span class="k">*</span>

    <span class="k">return </span>0
<span class="o">}</span>

process_generate_service_content_key<span class="o">()</span> <span class="o">{</span>

    tpm2_create <span class="se">\</span>
        <span class="nt">-C</span> n <span class="se">\</span>
        <span class="nt">-c</span> service_content_key.ctx <span class="se">\</span>
        <span class="nt">-u</span> service_content_key.pub <span class="se">\</span>
        <span class="nt">-r</span> service_content_key.priv <span class="se">\</span>
        <span class="nt">-Q</span>

    tpm2_readpublic <span class="se">\</span>
        <span class="nt">-c</span> service_content_key.ctx <span class="se">\</span>
        <span class="nt">-f</span> pem <span class="se">\</span>
        <span class="nt">-o</span> d_s_service_content_key.pub <span class="se">\</span>
        <span class="nt">-Q</span>
    <span class="nb">cp </span>d_s_service_content_key.pub <span class="nv">$service_provider_location</span>/.

    tpm2_sign <span class="se">\</span>
        <span class="nt">-c</span> rsa_ak.ctx <span class="se">\</span>
        <span class="nt">-g</span> sha256 <span class="se">\</span>
        <span class="nt">-s</span> rsassa <span class="se">\</span>
        <span class="nt">-f</span> plain <span class="se">\</span>
        <span class="nt">-o</span> d_s_service_content_key_pub.sig <span class="se">\</span>
        d_s_service_content_key.pub
    <span class="nb">cp </span>d_s_service_content_key_pub.sig <span class="nv">$service_provider_location</span>/.

    <span class="k">return </span>0
<span class="o">}</span>

request_device_service<span class="o">()</span> <span class="o">{</span>

    <span class="nv">request_service_status_string</span><span class="o">=</span><span class="s2">"Device anonymous identity challenge."</span>
    process_device_anonymous_identity_challenge
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>

    <span class="nv">request_service_status_string</span><span class="o">=</span><span class="s2">"Device software state validation"</span>
    process_device_software_state_validation_request
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>

    <span class="nv">request_service_status_string</span><span class="o">=</span><span class="s2">"Generating certified service key"</span>
    process_generate_service_content_key
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>

    <span class="nv">request_service_status_string</span><span class="o">=</span><span class="s2">"Service data content processing"</span>
    process_encrypted_service_data_content
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi

    return </span>0
<span class="o">}</span>

tput sc
<span class="nb">read</span> <span class="nt">-r</span> <span class="nt">-p</span> <span class="s2">"Demonstration purpose only, not for production. Continue? [y/N] "</span> response
tput rc
tput el
<span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$response</span><span class="s2">"</span> <span class="o">=</span>~ ^<span class="o">([</span>yY][eE][sS]|[yY]<span class="o">)</span><span class="nv">$ </span><span class="o">]]</span>
<span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"===================== DEVICE-NODE ====================="</span>
<span class="k">else
    </span><span class="nb">exit
</span><span class="k">fi


while </span><span class="nb">getopts</span> <span class="s2">":hrt:"</span> opt<span class="p">;</span> <span class="k">do
  case</span> <span class="k">${</span><span class="nv">opt</span><span class="k">}</span> <span class="k">in
    </span>h <span class="p">)</span>
      <span class="nb">echo</span> <span class="s2">"Pass 'r' for registration or 't' for service request"</span>
      <span class="p">;;</span>
    r <span class="p">)</span>
      <span class="nv">device_registration_request</span><span class="o">=</span>1
      <span class="p">;;</span>
    t <span class="p">)</span>
      <span class="nv">device_service_request</span><span class="o">=</span>1
      <span class="nv">device_service_aik</span><span class="o">=</span><span class="nv">$OPTARG</span>
      <span class="p">;;</span>
  <span class="k">esac</span>
<span class="k">done
</span><span class="nb">shift</span> <span class="k">$((</span> OPTIND <span class="o">-</span> <span class="m">1</span> <span class="k">))</span>

<span class="k">if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
   if</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span><span class="nb">echo</span> <span class="s2">"Specify either 'registration' or 'service' request not both"</span>
      <span class="nb">exit </span>1
   <span class="k">fi
fi

</span><span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device registration request."</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
   </span>request_device_registration
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">exit </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
<span class="k">fi

</span><span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device service request."</span>
<span class="k">if</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
   </span>request_device_service
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">exit </span>1
   <span class="k">fi
fi

if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
   if</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span><span class="nb">echo</span> <span class="s2">"Usage: device-node.sh [-h] [-r] [-t AIK.pub]"</span>
      <span class="nb">exit </span>1
   <span class="k">fi
fi</span>

<span class="c"># No errors</span>
<span class="nb">exit </span>0
</code></pre></div></div>

<h2 id="service-provider">Service-Provider</h2>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Fixed location</span>
<span class="nv">pca_location</span><span class="o">=</span><span class="s2">"</span><span class="nv">$PWD</span><span class="s2">/../PCA"</span>

<span class="c"># Device Location not fixed</span>
<span class="nv">device_location</span><span class="o">=</span><span class="s2">""</span>

<span class="c"># State</span>
<span class="nv">event_file_found</span><span class="o">=</span>0
<span class="nv">device_registration_request</span><span class="o">=</span>0
<span class="nv">device_service_request</span><span class="o">=</span>0

<span class="c"># Attestation Data</span>
<span class="nv">GOLDEN_PCR_SELECTION</span><span class="o">=</span><span class="s2">"sha1:0,1,2+sha256:0,1,2"</span>
<span class="nv">GOLDEN_PCR</span><span class="o">=</span><span class="s2">"59bf9091f4cbbd2a8796bfe086a501c57226c42739dcf8ad323e7493ad51e38f"</span>

<span class="c"># Service Data</span>
<span class="nv">SERVICE_CONTENT</span><span class="o">=</span><span class="s2">"Hello world!"</span>

wait_loop<span class="o">()</span> <span class="o">{</span>
    <span class="nv">counter</span><span class="o">=</span>1
    <span class="k">until</span> <span class="o">[</span> <span class="nv">$counter</span> <span class="nt">-gt</span> <span class="nv">$1</span> <span class="o">]</span>
    <span class="k">do
       </span><span class="nb">test</span> <span class="nt">-f</span> <span class="nv">$2</span>
       <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
          </span><span class="nv">event_file_found</span><span class="o">=</span>1
          <span class="nb">break
       </span><span class="k">else
          </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"Waiting </span><span class="nv">$1</span><span class="s2"> seconds: </span><span class="nv">$counter</span><span class="s2">"</span><span class="s1">'\r'</span>
       <span class="k">fi</span>
       <span class="o">((</span>counter++<span class="o">))</span>
       <span class="nb">sleep </span>1
    <span class="k">done</span>
<span class="o">}</span>

LOG_ERROR<span class="o">()</span> <span class="o">{</span>
    <span class="nv">errorstring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[31mFAIL: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">errorstring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

LOG_INFO<span class="o">()</span> <span class="o">{</span>
    <span class="nv">messagestring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[93mPASS: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">messagestring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

device_registration<span class="o">()</span> <span class="o">{</span>

    <span class="nv">REGISTRATION_TOKEN</span><span class="o">=</span><span class="sb">`</span><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">bs</span><span class="o">=</span>1 <span class="nv">count</span><span class="o">=</span>32 <span class="nv">status</span><span class="o">=</span>none | <span class="se">\</span>
    xxd <span class="nt">-p</span> <span class="nt">-c32</span><span class="sb">`</span>

    <span class="nv">device_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>device_location d_s_registration.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_registration.txt

    <span class="nv">data_to_privacy_ca</span><span class="o">=</span><span class="s2">"
    device_location: </span><span class="nv">$device_location</span><span class="s2">
    registration_token: </span><span class="nv">$REGISTRATION_TOKEN</span><span class="s2">
    "</span>

    <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$data_to_privacy_ca</span><span class="s2">"</span> <span class="o">&gt;</span> s_p_registration.txt
    <span class="nb">cp </span>s_p_registration.txt <span class="nv">$pca_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> s_p_registration.txt

    <span class="c"># Send privacy-CA information to device</span>
    <span class="nb">echo</span> <span class="s2">"privacy_ca_location: </span><span class="nv">$pca_location</span><span class="s2">"</span> <span class="o">&gt;</span> s_d_registration.txt
    <span class="nb">cp </span>s_d_registration.txt <span class="nv">$device_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_registration.txt

    <span class="c"># Wait for device_registration_token from device</span>
    <span class="nv">registration_status_string</span><span class="o">=</span><span class="s2">"Registration-Token reciept from device."</span>
    wait_loop <span class="nv">$max_wait</span> d_s_registration_token.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nv">test_registration_token</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>registration_token <span class="se">\</span>
    d_s_registration_token.txt | <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_registration_token.txt

    <span class="nv">registration_status_string</span><span class="o">=</span><span class="s2">"Registration-Token validation"</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$test_registration_token</span> <span class="o">==</span> <span class="nv">$REGISTRATION_TOKEN</span> <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
      <span class="k">return </span>0
    <span class="k">else
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
    <span class="k">fi</span>
<span class="o">}</span>

device_node_identity_challenge<span class="o">()</span> <span class="o">{</span>
    <span class="nv">SERVICE_TOKEN</span><span class="o">=</span><span class="sb">`</span><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">bs</span><span class="o">=</span>1 <span class="nv">count</span><span class="o">=</span>32 <span class="nv">status</span><span class="o">=</span>none | <span class="se">\</span>
    xxd <span class="nt">-p</span> <span class="nt">-c32</span><span class="sb">`</span>

    <span class="nv">device_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>device_location d_s_service.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_service.txt

    <span class="nv">data_to_privacy_ca</span><span class="o">=</span><span class="s2">"
    device_location: </span><span class="nv">$device_location</span><span class="s2">
    service_token: </span><span class="nv">$SERVICE_TOKEN</span><span class="s2">
    "</span>

    <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$data_to_privacy_ca</span><span class="s2">"</span> <span class="o">&gt;</span> s_p_service.txt
    <span class="nb">cp </span>s_p_service.txt <span class="nv">$pca_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> s_p_service.txt

    <span class="c"># Send privacy-CA information to device</span>
    <span class="nb">echo</span> <span class="s2">"privacy_ca_location: </span><span class="nv">$pca_location</span><span class="s2">"</span> <span class="o">&gt;</span> s_d_service.txt
    <span class="nb">cp </span>s_d_service.txt <span class="nv">$device_location</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_service.txt

   <span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Aborting service request - AIK not found."</span>
   <span class="nb">test</span> <span class="nt">-f</span> d_s_service_aik.pub
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
   <span class="k">else
      </span><span class="nb">cp </span>d_s_service_aik.pub <span class="nv">$pca_location</span>/s_p_service_aik.pub
   <span class="k">fi

   </span><span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Service-Token receipt from device."</span>
   wait_loop <span class="nv">$max_wait</span> d_s_service_token.txt
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
     </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
     <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
   <span class="nv">event_file_found</span><span class="o">=</span>0
   <span class="nv">test_service_token</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>service-token <span class="se">\</span>
   d_s_service_token.txt | <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
   <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_token.txt

   <span class="nv">identity_challenge_status_string</span><span class="o">=</span><span class="s2">"Service-Token validation."</span>
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$test_service_token</span> <span class="o">==</span> <span class="nv">$SERVICE_TOKEN</span> <span class="o">]</span><span class="p">;</span><span class="k">then
     </span>LOG_INFO <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>
     <span class="k">return </span>0
   <span class="k">fi
   </span>LOG_ERROR <span class="s2">"</span><span class="nv">$identity_challenge_status_string</span><span class="s2">"</span>

   <span class="k">return </span>1
<span class="o">}</span>

system_software_state_validation<span class="o">()</span> <span class="o">{</span>

   <span class="nb">rm</span> <span class="nt">-f</span> attestation_quote.dat attestation_quote.signature
   <span class="nb">echo</span> <span class="s2">"pcr-selection: </span><span class="nv">$GOLDEN_PCR_SELECTION</span><span class="s2">"</span> <span class="o">&gt;</span> s_d_pcrlist.txt
   <span class="nv">NONCE</span><span class="o">=</span><span class="sb">`</span><span class="nb">dd </span><span class="k">if</span><span class="o">=</span>/dev/urandom <span class="nv">bs</span><span class="o">=</span>1 <span class="nv">count</span><span class="o">=</span>32 <span class="nv">status</span><span class="o">=</span>none | xxd <span class="nt">-p</span> <span class="nt">-c32</span><span class="sb">`</span>
   <span class="nb">echo</span> <span class="s2">"nonce: </span><span class="nv">$NONCE</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> s_d_pcrlist.txt
   <span class="nb">cp </span>s_d_pcrlist.txt <span class="nv">$device_location</span>/.
   <span class="nb">rm</span> <span class="nt">-f</span> s_d_pcrlist.txt

   <span class="nv">software_status_string</span><span class="o">=</span><span class="s2">"Attestation data receipt from device"</span>
   <span class="nv">max_wait</span><span class="o">=</span>60
   wait_loop <span class="nv">$max_wait</span> attestation_quote.dat
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
   <span class="nv">event_file_found</span><span class="o">=</span>0

   <span class="nv">software_status_string</span><span class="o">=</span><span class="s2">"Attestation signature receipt from device"</span>
   <span class="nv">max_wait</span><span class="o">=</span>60
   wait_loop <span class="nv">$max_wait</span> attestation_quote.signature
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
   <span class="nv">event_file_found</span><span class="o">=</span>0

   <span class="nv">software_status_string</span><span class="o">=</span><span class="s2">"Attestation quote signature validation"</span>
   tpm2_checkquote <span class="nt">--public</span> d_s_service_aik.pub  <span class="nt">--qualification</span> <span class="s2">"</span><span class="nv">$NONCE</span><span class="s2">"</span> <span class="se">\</span>
   <span class="nt">--message</span> attestation_quote.dat <span class="nt">--signature</span> attestation_quote.signature <span class="se">\</span>
   <span class="nt">--pcr</span> pcr.bin <span class="nt">-Q</span>
   <span class="nv">retval</span><span class="o">=</span><span class="nv">$?</span>
   <span class="nb">rm</span> <span class="nt">-f</span> attestation_quote.signature
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$retval</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>

   <span class="nv">software_status_string</span><span class="o">=</span><span class="s2">"Verification of PCR from quote against golden reference"</span>
   <span class="nv">testpcr</span><span class="o">=</span><span class="sb">`</span>tpm2_print <span class="nt">-t</span> TPMS_ATTEST attestation_quote.dat | <span class="se">\</span>
   <span class="nb">grep </span>pcrDigest | <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
   <span class="nb">rm</span> <span class="nt">-f</span> attestation_quote.dat
   <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$testpcr</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">"</span><span class="nv">$GOLDEN_PCR</span><span class="s2">"</span> <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
   <span class="k">else
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$software_status_string</span><span class="s2">"</span>
      <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"      </span><span class="se">\e</span><span class="s2">[97mDevice-PCR: </span><span class="nv">$testpcr</span><span class="se">\e</span><span class="s2">[0m"</span>
      <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"      </span><span class="se">\e</span><span class="s2">[97mGolden-PCR: </span><span class="nv">$GOLDEN_PCR</span><span class="se">\e</span><span class="s2">[0m"</span>
      <span class="k">return </span>1
   <span class="k">fi

   return </span>0
<span class="o">}</span>

device_service_content_key_validation<span class="o">()</span> <span class="o">{</span>
   <span class="nv">request_service_content_key_string</span><span class="o">=</span><span class="s2">"Retrieving service content key from device"</span>
   <span class="nv">max_wait</span><span class="o">=</span>60
   wait_loop <span class="nv">$max_wait</span> d_s_service_content_key.pub
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
       </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_content_key_string</span><span class="s2">"</span>
       <span class="k">return </span>1
   <span class="k">fi
   </span><span class="nv">event_file_found</span><span class="o">=</span>0
   LOG_INFO <span class="s2">"</span><span class="nv">$request_service_content_key_string</span><span class="s2">"</span>

   <span class="nv">max_wait</span><span class="o">=</span>60
   wait_loop <span class="nv">$max_wait</span> d_s_service_content_key_pub.sig
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
       </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_service_content_key_string</span><span class="s2">"</span>
       <span class="k">return </span>1
   <span class="k">fi
   </span><span class="nv">event_file_found</span><span class="o">=</span>0
   LOG_INFO <span class="s2">"</span><span class="nv">$request_service_content_key_string</span><span class="s2">"</span>

   openssl dgst <span class="nt">-sha256</span> <span class="nt">-binary</span> d_s_service_content_key.pub <span class="o">&gt;</span> service_content_key.pub.digest

   openssl pkeyutl <span class="se">\</span>
      <span class="nt">-verify</span> <span class="se">\</span>
      <span class="nt">-in</span> service_content_key.pub.digest <span class="se">\</span>
      <span class="nt">-sigfile</span> d_s_service_content_key_pub.sig <span class="se">\</span>
      <span class="nt">-pubin</span> <span class="se">\</span>
      <span class="nt">-inkey</span> d_s_service_aik.pub <span class="se">\</span>
      <span class="nt">-keyform</span> pem <span class="se">\</span>
      <span class="nt">-pkeyopt</span> digest:sha256
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      return </span>1
   <span class="k">fi

   return </span>0
<span class="o">}</span>

request_device_service<span class="o">()</span> <span class="o">{</span>
   <span class="c"># Start device service registration with device identity challenge</span>
   <span class="nv">request_device_service_status_string</span><span class="o">=</span><span class="s2">"Anonymous identity validation by Privacy-CA."</span>
   device_node_identity_challenge
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>
      <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_aik.pub
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>

   <span class="c"># Check the device software state by getting a device quote</span>
   <span class="nv">request_device_service_status_string</span><span class="o">=</span><span class="s2">"Device system software validation."</span>
   system_software_state_validation
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>
      <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_aik.pub
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>

   <span class="c"># Verify service content key from the device</span>
   <span class="nv">request_device_service_status_string</span><span class="o">=</span><span class="s2">"Device service content key validation."</span>
   device_service_content_key_validation
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>
      <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_aik.pub
      <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_content_key.pub
      <span class="k">return </span>1
   <span class="k">fi
   </span>LOG_INFO <span class="s2">"</span><span class="nv">$request_device_service_status_string</span><span class="s2">"</span>

   <span class="c"># Encrypt service data content and deliver</span>
   <span class="nb">echo</span> <span class="s2">"</span><span class="nv">$SERVICE_CONTENT</span><span class="s2">"</span> <span class="o">&gt;</span> service-content.plain
    openssl rsautl <span class="nt">-encrypt</span> <span class="nt">-inkey</span> d_s_service_content_key.pub <span class="nt">-pubin</span> <span class="se">\</span>
    <span class="nt">-in</span> service-content.plain <span class="nt">-out</span> s_d_service_content.encrypted

    <span class="nb">cp </span>s_d_service_content.encrypted <span class="nv">$device_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_aik.pub
    <span class="nb">rm</span> <span class="nt">-f</span> d_s_service_content_key.pub
    <span class="nb">rm</span> <span class="nt">-f</span> s_d_service_content.encrypted
    <span class="nb">rm</span> <span class="nt">-f</span> service-content.plain
    LOG_INFO <span class="s2">"Sending service-content: </span><span class="se">\e</span><span class="s2">[5m</span><span class="nv">$SERVICE_CONTENT</span><span class="s2">"</span>

   <span class="k">return </span>0
<span class="o">}</span>

tput sc
<span class="nb">read</span> <span class="nt">-r</span> <span class="nt">-p</span> <span class="s2">"Demonstration purpose only, not for production. Continue? [y/N] "</span> response
tput rc
tput el
<span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$response</span><span class="s2">"</span> <span class="o">=</span>~ ^<span class="o">([</span>yY][eE][sS]|[yY]<span class="o">)</span><span class="nv">$ </span><span class="o">]]</span>
<span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"===================== SERVICE-PROVIDER ====================="</span>
<span class="k">else
    </span><span class="nb">exit
</span><span class="k">fi

</span><span class="nv">counter</span><span class="o">=</span>1
<span class="nv">max_wait</span><span class="o">=</span>60
<span class="k">until</span> <span class="o">[</span> <span class="nv">$counter</span> <span class="nt">-gt</span> <span class="nv">$max_wait</span> <span class="o">]</span>
<span class="k">do</span>
   <span class="o">!</span> <span class="nb">test</span> <span class="nt">-f</span> d_s_registration.txt
   <span class="nv">device_registration_request</span><span class="o">=</span><span class="nv">$?</span>
   <span class="o">!</span> <span class="nb">test</span> <span class="nt">-f</span> d_s_service.txt
   <span class="nv">device_service_request</span><span class="o">=</span><span class="nv">$?</span>

   <span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device registration request."</span>
   <span class="k">if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>device_registration
      <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
         </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
         <span class="nb">exit </span>1
      <span class="k">fi
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">break
   </span><span class="k">elif</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span><span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device service request."</span>
      request_device_service
      <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
         </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
         <span class="nb">exit </span>1
      <span class="k">fi
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">break
   </span><span class="k">else
      </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"Waiting </span><span class="nv">$1</span><span class="s2"> seconds: </span><span class="nv">$counter</span><span class="s2">"</span><span class="s1">'\r'</span>
   <span class="k">fi</span>
   <span class="o">((</span>counter++<span class="o">))</span>
   <span class="nb">sleep </span>1
<span class="k">done

if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
   if</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"Exiting as there are no device requests to process"</span>
      <span class="nb">exit </span>1
   <span class="k">fi
fi</span>

<span class="c"># No errors</span>
<span class="nb">exit </span>0
</code></pre></div></div>

<h2 id="privacy-ca">Privacy-CA</h2>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Fixed location</span>
<span class="nv">service_provider_location</span><span class="o">=</span><span class="s2">"</span><span class="nv">$PWD</span><span class="s2">/../SP"</span>

<span class="c"># Location for node 1, node 2, etc.</span>
<span class="nv">device_location</span><span class="o">=</span><span class="s2">""</span>
<span class="nv">registration_token</span><span class="o">=</span><span class="s2">""</span>

<span class="c"># State</span>
<span class="nv">event_file_found</span><span class="o">=</span>0

wait_loop<span class="o">()</span> <span class="o">{</span>
    <span class="nv">counter</span><span class="o">=</span>1
    <span class="k">until</span> <span class="o">[</span> <span class="nv">$counter</span> <span class="nt">-gt</span> <span class="nv">$1</span> <span class="o">]</span>
    <span class="k">do
       </span><span class="nb">test</span> <span class="nt">-f</span> <span class="nv">$2</span>
       <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
          </span><span class="nv">event_file_found</span><span class="o">=</span>1
          <span class="nb">break
       </span><span class="k">else
          </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"Waiting </span><span class="nv">$1</span><span class="s2"> seconds: </span><span class="nv">$counter</span><span class="s2">"</span><span class="s1">'\r'</span>
       <span class="k">fi</span>
       <span class="o">((</span>counter++<span class="o">))</span>
       <span class="nb">sleep </span>1
    <span class="k">done</span>
<span class="o">}</span>

LOG_ERROR<span class="o">()</span> <span class="o">{</span>
    <span class="nv">errorstring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[31mFAIL: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">errorstring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

LOG_INFO<span class="o">()</span> <span class="o">{</span>
    <span class="nv">messagestring</span><span class="o">=</span><span class="nv">$1</span>
    <span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\0</span><span class="s2">33[93mPASS: </span><span class="se">\e</span><span class="s2">[97m</span><span class="k">${</span><span class="nv">messagestring</span><span class="k">}</span><span class="se">\e</span><span class="s2">[0m"</span>
<span class="o">}</span>

process_device_registration_request_from_service_provider<span class="o">()</span> <span class="o">{</span>

    <span class="nv">device_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>device_location s_p_registration.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nv">registration_token</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>registration_token s_p_registration.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_p_registration.txt

    <span class="k">return </span>0
<span class="o">}</span>

credential_challenge<span class="o">()</span> <span class="o">{</span>

    <span class="nv">file_size</span><span class="o">=</span><span class="sb">`</span><span class="nb">stat</span> <span class="nt">--printf</span><span class="o">=</span><span class="s2">"%s"</span> rsa_ak.name<span class="sb">`</span>
    <span class="nv">loaded_key_name</span><span class="o">=</span><span class="sb">`</span><span class="nb">cat </span>rsa_ak.name | xxd <span class="nt">-p</span> <span class="nt">-c</span> <span class="nv">$file_size</span><span class="sb">`</span>

    <span class="nb">echo</span> <span class="s2">"this is my secret"</span> <span class="o">&gt;</span> file_input.data
    tpm2_makecredential <span class="se">\</span>
        <span class="nt">--tcti</span> none <span class="se">\</span>
        <span class="nt">--encryption-key</span> rsa_ek.pub <span class="se">\</span>
        <span class="nt">--secret</span> file_input.data <span class="se">\</span>
        <span class="nt">--name</span> <span class="nv">$loaded_key_name</span> <span class="se">\</span>
        <span class="nt">--credential-blob</span> cred.out <span class="se">\</span>
        <span class="nt">-Q</span>
    
    <span class="nb">cp </span>cred.out <span class="nv">$device_location</span>/.

    <span class="nv">credential_status_string</span><span class="o">=</span><span class="s2">"Activated credential receipt from device."</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> actcred.out
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$credential_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$credential_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0

    diff file_input.data actcred.out
    <span class="nb">test</span><span class="o">=</span><span class="nv">$?</span>
    <span class="nb">rm</span> <span class="nt">-f</span> rsa_ak.<span class="k">*</span> file_input.data actcred.out cred.out
    <span class="nv">credential_status_string</span><span class="o">=</span><span class="s2">"Credential activation challenge."</span>
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$test</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_INFO <span class="s2">"</span><span class="nv">$credential_status_string</span><span class="s2">"</span>
        <span class="k">return </span>0
    <span class="k">else
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$credential_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi</span>
<span class="o">}</span>

process_device_registration_processing_with_device<span class="o">()</span> <span class="o">{</span>

    <span class="nb">touch </span>p_d_pca_ready.txt
    <span class="nb">cp </span>p_d_pca_ready.txt <span class="nv">$device_location</span>/.
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_pca_ready.txt

    <span class="nv">process_registration_status_string</span><span class="o">=</span><span class="s2">"Device-ready acknowledgement receipt from device."</span>
    <span class="nv">max_wait</span><span class="o">=</span>60
    wait_loop <span class="nv">$max_wait</span> d_p_device_ready.txt
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$event_file_found</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$process_registration_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$process_registration_status_string</span><span class="s2">"</span>
    <span class="nv">event_file_found</span><span class="o">=</span>0
    <span class="nb">rm</span> <span class="nt">-f</span> d_p_device_ready.txt

    <span class="nb">cp</span> <span class="nv">$device_location</span>/rsa_ek.pub <span class="nb">.</span>
    <span class="c">#cp $device_location/rsa_ak.pub .</span>
    <span class="nb">cp</span> <span class="nv">$device_location</span>/rsa_ak.name <span class="nb">.</span>
    LOG_INFO <span class="s2">"Received EKcertificate EK and AIK from device"</span>

    credential_challenge
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        return </span>1
    <span class="k">fi

    return </span>0
<span class="o">}</span>

request_device_registration<span class="o">()</span> <span class="o">{</span>

    <span class="nb">mkdir</span> <span class="nt">-p</span> Registered_EK_Pool

    <span class="nv">registration_request_status_string</span><span class="o">=</span><span class="s2">"Device info and registration-token receipt from service-provider."</span>
    process_device_registration_request_from_service_provider
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_request_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">fi
    </span>LOG_INFO <span class="s2">"</span><span class="nv">$registration_request_status_string</span><span class="s2">"</span>

    <span class="nv">registration_request_status_string</span><span class="o">=</span><span class="s2">"Registration-token dispatch to device."</span>
    process_device_registration_processing_with_device
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$registration_request_status_string</span><span class="s2">"</span>
        <span class="k">return </span>1
    <span class="k">else
        </span>LOG_INFO <span class="s2">"</span><span class="nv">$registration_request_status_string</span><span class="s2">"</span>
        <span class="nb">echo</span> <span class="s2">"registration_token: </span><span class="nv">$registration_token</span><span class="s2">"</span> <span class="o">&gt;</span> <span class="se">\</span>
        p_d_registration_token.txt
        <span class="nb">cp </span>p_d_registration_token.txt <span class="nv">$device_location</span>/.
        <span class="nb">rm</span> <span class="nt">-f</span> p_d_registration_token.txt
    <span class="k">fi

    </span><span class="nb">mv </span>rsa_ek.pub Registered_EK_Pool/<span class="nv">$registration_token</span>
    fdupes <span class="nt">--recurse</span> <span class="nt">--omitfirst</span> <span class="nt">--noprompt</span> <span class="nt">--delete</span> <span class="nt">--quiet</span> <span class="se">\</span>
    Registered_EK_Pool | <span class="nb">grep</span> <span class="nt">-q</span> rsa_ek.pub

    <span class="k">return </span>0
<span class="o">}</span>

request_device_service<span class="o">()</span> <span class="o">{</span>

    <span class="nv">device_location</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>device_location s_p_service.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nv">service_token</span><span class="o">=</span><span class="sb">`</span><span class="nb">grep </span>service_token s_p_service.txt | <span class="se">\</span>
    <span class="nb">awk</span> <span class="s1">'{print $2}'</span><span class="sb">`</span>
    <span class="nb">rm</span> <span class="nt">-f</span> s_p_service.txt

    <span class="nb">cp </span>s_p_service_aik.pub <span class="nv">$device_location</span>/rsa_ak.pub
    <span class="nb">rm</span> <span class="nt">-f</span> s_p_service_aik.pub
    process_device_registration_processing_with_device
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"AIK received from service provider is not on the device"</span>
        <span class="k">return </span>1
    <span class="k">fi

    </span><span class="nb">cp </span>rsa_ek.pub Registered_EK_Pool
    fdupes <span class="nt">--recurse</span> <span class="nt">--omitfirst</span> <span class="nt">--noprompt</span> <span class="nt">--delete</span> <span class="nt">--quiet</span> <span class="se">\</span>
    Registered_EK_Pool | <span class="nb">grep</span> <span class="nt">-q</span> rsa_ek.pub
    <span class="nv">retval</span><span class="o">=</span><span class="nv">$?</span>
    <span class="nb">rm</span> <span class="nt">-f</span> rsa_ek.pub Registered_EK_Pool/rsa_ek.pub
    <span class="k">if</span> <span class="o">[</span> <span class="nv">$retval</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"EK from device does not belong to the registered EK pool"</span>
        <span class="k">return </span>1
    <span class="k">fi

    </span><span class="nb">echo</span> <span class="s2">"service-token: </span><span class="nv">$service_token</span><span class="s2">"</span> <span class="o">&gt;</span> p_d_service_token.txt
    <span class="nb">cp </span>p_d_service_token.txt <span class="nv">$device_location</span>
    <span class="nb">rm</span> <span class="nt">-f</span> p_d_service_token.txt

    <span class="k">return </span>0
<span class="o">}</span>

tput sc
<span class="nb">read</span> <span class="nt">-r</span> <span class="nt">-p</span> <span class="s2">"Demonstration purpose only, not for production. Continue? [y/N] "</span> response
tput rc
tput el
<span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="nv">$response</span><span class="s2">"</span> <span class="o">=</span>~ ^<span class="o">([</span>yY][eE][sS]|[yY]<span class="o">)</span><span class="nv">$ </span><span class="o">]]</span>
<span class="k">then
    </span><span class="nb">echo</span> <span class="s2">"===================== PRIVACY-CA ====================="</span>
<span class="k">else
    </span><span class="nb">exit
</span><span class="k">fi


</span><span class="nv">device_registration_request</span><span class="o">=</span>0
<span class="nv">device_service_request</span><span class="o">=</span>0
<span class="nv">counter</span><span class="o">=</span>1
<span class="nv">max_wait</span><span class="o">=</span>60
<span class="k">until</span> <span class="o">[</span> <span class="nv">$counter</span> <span class="nt">-gt</span> <span class="nv">$max_wait</span> <span class="o">]</span>
<span class="k">do</span>
   <span class="o">!</span> <span class="nb">test</span> <span class="nt">-f</span> s_p_registration.txt
   <span class="nv">device_registration_request</span><span class="o">=</span><span class="nv">$?</span>
   <span class="o">!</span> <span class="nb">test</span> <span class="nt">-f</span> s_p_service.txt
   <span class="nv">device_service_request</span><span class="o">=</span><span class="nv">$?</span>

   <span class="k">if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span><span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device registration request."</span>
      request_device_registration
      <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
        <span class="nb">exit </span>1
      <span class="k">fi
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">break
   </span><span class="k">elif</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span><span class="nv">status_string</span><span class="o">=</span><span class="s2">"Device service request received."</span>
      request_device_service
      <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> <span class="o">==</span> 1 <span class="o">]</span><span class="p">;</span><span class="k">then
        </span>LOG_ERROR <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
        <span class="nb">exit </span>1
      <span class="k">fi
      </span>LOG_INFO <span class="s2">"</span><span class="nv">$status_string</span><span class="s2">"</span>
      <span class="nb">break
   </span><span class="k">else
      </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"Waiting </span><span class="nv">$1</span><span class="s2"> seconds: </span><span class="nv">$counter</span><span class="s2">"</span><span class="s1">'\r'</span>
   <span class="k">fi</span>
   <span class="o">((</span>counter++<span class="o">))</span>
   <span class="nb">sleep </span>1
<span class="k">done

if</span> <span class="o">[</span> <span class="nv">$device_registration_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
   if</span> <span class="o">[</span> <span class="nv">$device_service_request</span> <span class="o">==</span> 0 <span class="o">]</span><span class="p">;</span><span class="k">then
      </span>LOG_ERROR <span class="s2">"Exiting as there are no service provider requests to process."</span>
      <span class="nb">exit </span>1
   <span class="k">fi
fi</span>

<span class="c"># No errors</span>
<span class="nb">exit </span>0
</code></pre></div></div>

<h1 id="faq">FAQ</h1>

<ol>
  <li>
    <p><strong><em>If the EK or AIK had already been generated but the public key file isn’t
available, is there a way to generate the public key?</em></strong></p>

    <p>It is possible to recreate public key from an already created EK or AIK key.
There are two possible forms for a TPM object to reside on the TPM. Both of
these eventually translate as a TPM handle number that can be invoked by
specific TPM commands.</p>

    <p>Persistent-handles: As the term implies, these reside in the TPM and can be
invoked using TPM persistent-handle at location range 81xxxxxxx. Since these
reside on the TPM NV, they survive TPM resets and restarts.</p>

    <p>Transient handles, on the contrary, do not reside on the TPM NV. However, they
are still protected objects that need additional steps of loading and validating
integrity prior to their use. Such an object has 3 important parts before it is
translated into a usable handle.
a. The wrapped sensitive portion of the key object (termed as private in the
tpm2-tools).
b. The non-sensitive portion which includes key attributes, authorization policy
digest, etc (termed as public in the tpm2-tools).
c. A context blob that is generated when such an object is successfully
created–&gt;loaded–&gt;offloaded from the TPM. Once ready to use the
object, the context blob is referenced in the tpm2 commands that then get
assigned a transient handle for use just like the persistent handles but at
location range 80xxxxxx.</p>

    <p>In either of the cases above, a tool called [tpm2_readpublic](<a href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/tpm2_readpublic.1.md">tpm2_readpublic</a>
can be used to view and or dump a public portion in tss or pem format by passing
the persistent handle or the context file as an input. In fact, this tool has
been used in the device-node.sh scripts in this tutorial as well to generate a
pem formatted file.</p>
  </li>
</ol>

<h1 id="author">Author</h1>
<p>Imran Desai</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Table of Contents]]></summary></entry><entry><title type="html">Disk Encryption</title><link href="https://tpm2-software.github.io/2020/04/13/Disk-Encryption.html" rel="alternate" type="text/html" title="Disk Encryption" /><published>2020-04-13T00:00:00+00:00</published><updated>2020-04-13T00:00:00+00:00</updated><id>https://tpm2-software.github.io/2020/04/13/Disk-Encryption</id><content type="html" xml:base="https://tpm2-software.github.io/2020/04/13/Disk-Encryption.html"><![CDATA[<h1 id="introduction">Introduction</h1>
<p>In an increasingly data heavy world we live in today, data security has become
critical for connected-devices, corporations, and individuals alike. It is
important to keep data protected at rest especially at source and also in
transit. Hence digital encryption schemes have become paramount for protecting
the confidentiality and integrity of the data. Of the multitude of encryption
mechanisms for protecting the confidentiality AES XTS (cipher text stealing)
mode is most commonly used. Encryption schemes function by virtue of protecting
the encryption secret which is also termed encryption key.</p>

<h1 id="trusted-platform-module-tpm">Trusted Platform Module (TPM)</h1>
<p>The robustness rules for protecting the  encryption secret or keys involves both
physical access protection to the key data as well as access restrictions
to sensitive operations with the key like decryption and digital signing
enforced through authentication mechanisms. These requirements were termed as
root of trust for storage (RTS) and root of trust for reporting (RTR) by the
Trusted Computing Group (TCG). TCG is a consortium of industry and academic
expertise coming together to define specifications for a security module that
achieves these objectives. This security module is called the Trusted Platform
Module or TPM. The TPM came about in two major standard specifications, the 1.2
and the now 2.0. Algorithm flexibility and enhanced authorization schemes are of
the major advancements in 2.0. Secure persistent storage, platform configuration
register or PCR for recording system software state(more on this later), a per
TPM unique certified key for digital identity, and hierarchies for partitioning
roles based access to TPM objects are of the notable TPM properties. TPM is a
limited resourced device.</p>

<h1 id="trusted-software-stack-tss-and-tpm2-software-tpm2-software">Trusted Software Stack (TSS) and TPM2 Software (tpm2-software):</h1>
<p>TPMs have a secure persistent storage of about 14KB and a smaller fast memory or
RAM to support a maximum 3 sessions that quickly exhaust depending on the
application requirement. In addition to the TPM specifications, TCG also created
a specification for a software stack to optimally function with the limited
resourced TPM device. This is called the Trusted Software Stack or TSS. The spec
defines not only the mechanisms and interfaces to manage the TPM resources, it
also details how the software partitions the stack into well defined interfaces
for device communication, command response buffer transport, access brokering,
resource management, session management and feature profiles for most common use
cases.<br /></p>

<p>Feature API or FAPI:The abstraction should profile common use cases and
provides context management.<br /></p>

<p>Enhanced System API or ESAPI or ESYS: Provides cryptographic functions for
sessions and session management.<br /></p>

<p>System API or SAPI: A one to one mapping of all the available TPM2 commands.
While sufficient it requires expert TPM knowledge for managing sessions,
contexts and cryptographic functions. Marshalling and unmarshalling of command
and response buffer is also handled here.<br /></p>

<p>Trusted Access Broker and Resource Manager or TAB/RM: Abstracts resource
limitation. In a multi application setup vying from TPM access, it ensures TPM
commands are singularly processed. There is a user space dbus based
implementation as well an in kernel implementation.<br /></p>

<p>TPM Command Transmission Interface or TCTI: Decouples the API generating the
TPM command and responses and instead focuses on the transport mechanism.<br /></p>

<p>Trusted Device Driver or TDD: This is the primary device interface handling
the command-response buffering, control registers and interface management. This
is part of the mainline kernel tree in the character device driver category.<br /></p>

<h2 id="tpm2-software">TPM2 Software:</h2>
<p>The community supported tpm2-software project on github is an implementation of
the trusted software stack specification by TCG. It is getting widespread
adoption in the linux community and mainstream distributions. Following is a
growing list of the tpm2-software projects:<br /></p>

<ul>
  <li><a href="https://github.com/tpm2-software/tpm2-tss">tpm2-tss</a>: OSS implementation of
the TCG TPM2 Software Stack (TSS2).</li>
  <li><a href="https://github.com/tpm2-software/tpm2-abrmd">tpm2-abrmd</a>: TPM2 Access Broker
&amp; Resource Management Daemon implementing the TCG specification.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-tools">tpm2-tools</a>: The source
repository for the Trusted Platform Module (TPM2.0) tools.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-pkcs11">tpm2-pkcs11</a>: A PKCS#11
interface for TPM2 hardware.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-tss-engine">tpm2-tss-engine</a>: OpenSSL
Engine for TPM2 devices.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-tcti-uefi">tpm2-tcti-uefi</a>: TCTI
module for use with TSS2 libraries in UEFI environment.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-pytss">tpm2-pytss</a>: Python bindings for
TSS.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-swig">tpm2-swig</a>: SWIG interface for
high level language bindings.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-totp">tpm2-totp</a>: Attest the
trustworthiness of a device against a human using time-based one-time passwords.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-software-container">tpm2-software-container</a>:
Metadata and scripts used to generate the container images used for continuous
integration (CI) by the various tpm2-software projects.</li>
  <li><a href="https://github.com/tpm2-software/tpm2-software.github.io">tpm2-software.github.io</a>:
This is the source for the community website of the tpm2-software namespace on
GitHub. It uses github pages (with Jekyl).</li>
</ul>

<p>All the projects use <em>autotools</em> since it follows the normal build conventions
and  to make it easier to distribute code portably by creating automatic
dependency generation. For all the projects above: <em>bootstrap</em>, <em>configure</em>
<em>make</em> and <em>make install</em> are generally sufficient. The bootstrap and configure
scripts should inform the user of missing libraries and packages. The user can
then install them using the package manager specific to the distribution in use.</p>

<h1 id="a-simple-use-case---creating-an-rsa-key-pair-and-securely-persisting-in-tpm">A simple use case - Creating an RSA Key pair and securely persisting in TPM</h1>

<p>Once you have all the necessary tpm2 software installed, it is fairly simple to
create an RSA key pair and store it in the TPM persitent memory.<br /></p>

<p>Create the RSA key<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_createprimary --hierarchy=o --key-algorithm=rsa --key-context=prim.ctx</code><br /></li>
</ol>

<p>Save it to the TPM persistent memory<br />
{:start=”2”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol --hierarchy=o --object-context=prim.ctx 0x81010001</code><br /></li>
</ol>

<p>NOTE:</p>
<ul>
  <li>The sensitive portion of the key is never released outside of the TPM2 device.
This makes it a more secure way of generating and protecting the key compared to
the conventional way of using system software like openssl.</li>
  <li>Once the key is generated and persisted in the TPM2 device, it can now be used
throughout the boot sequence as soon as TPM becomes available which is much
earlier than the operating system loads.</li>
</ul>

<h1 id="use-case---disk-encryption-using-linux-unified-key-setup-luks-with-tpm2-as-the-encryption-key-protector">Use case - Disk encryption using Linux Unified Key Setup (LUKS) with TPM2 as the encryption key protector:</h1>

<h2 id="the-need-for-disk-encryption">The need for Disk Encryption:</h2>

<p>Disk encryption protects storage devices from an attacker with intention to dump
sensitive information by mounting the storage device on alternative operating
environments under attacker control. Of the objectives for disk encryption are:</p>

<ul>
  <li>Make it difficult for attacker to dump sensitive plain text on disk.</li>
  <li>Choose a strong pass-phrase &amp; a vetted disk encryption software.</li>
  <li>Protect the disk encryption pass-phrase on the platform: Just-in-time OR
secure-key-store.</li>
  <li>Protect pass-phrase access with restricted access to specific platform and
specific system software state</li>
  <li>Flexibility in unsealing pass-phrase during intended system software state
updates/ changes.</li>
</ul>

<p>To elicit the importance of protecting disk encryption keys on a TPM, let’s
first setup a disk image without encryption and see if we can extract user
generated content.<br /></p>

<p>Create a disk image and write some content:<br />
{:start=”3”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">dd if=/dev/zero of=plain.disk bs=1M count=10</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">mkfs.ext4 plain.disk</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">mkdir -p mountpoint</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mount plain.disk mountpoint</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo touch mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo chmod 777 mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo echo "This is my plain text" &gt; mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo umount mountpoint</code><br /></li>
</ol>

<p>At this point we have a disk with a file plain.txt which has the content “This
is my plain text”. Let’s suppose this is our private and sensitive data. We can
see that it is not protected by dumping the disk and looking at the content to
find the plain.txt. To do this simply do the following:<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">strings plain.disk</code><br /></li>
</ol>

<p>NOTE:</p>
<ul>
  <li>Having a week authentication mechanism for login control is not mitigated by
disk encryption. Mounted encrypted volumes without user intervention are
available in clear to the logged in user.</li>
  <li>Data assets especially storage must remain confidential either with disk/ file
 encryption. Choosing and protecting a strong pass-phrase for encryption is
 paramount.</li>
</ul>

<h2 id="simple-disk-encryption-scheme-using-linux-unified-key-setup-luks---plaintext-pass-phrase-on-disk">Simple disk encryption scheme using Linux Unified Key Setup (LUKS) - Plaintext pass-phrase on disk:</h2>

<p>Most standard Linux implementations use the LUKS specification. LUKS ensures
storage data confidentiality at rest. LUKS stores setup info in partition header
to aid easy migration. LUKS uses the kernel device mapper subsystem. 8 separate
authentication slots can be specified for single volume with support for
revocation. LUKS volumes can be automatically mounted at startup with standard
linux provisions like services, daemons, etc. Authentication/ Passphrase can be
provided as a password just in time (default) and or specified as key file
(command line argument). The cryptsetup user space utility aids creating and
managing LUKS volumes.<br /></p>

<p>Let’s setup a new LUKS volume with a simple passphrase as key protector:<br />
{:start=”12”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">dd if=/dev/zero of=enc.disk bs=1M count=10</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">dd if=/dev/urandom of=disk.key bs=1 count=32</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">loopdevice=$(losetup -f) &amp;&amp; sudo losetup $loopdevice enc.disk</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo cryptsetup luksFormat --key-file=disk.key $loopdevice</code><br /></li>
</ol>

<p>At this point you have setup the luks volume and it should pop a warning about
overriding the data. Next let’s open the LUKS volume by authenticating with the
disk.key and complete the setting up the disk with a filesystem.<br />
{:start=”16”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo cryptsetup luksOpen --key-file=disk.key $loopdevice enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mkfs.ext4 -j /dev/mapper/enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mount /dev/mapper/enc_volume mountpoint</code><br /></li>
</ol>

<p>Now lets create a plain text file again and add user content to it:<br />
{:start=”19”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo touch mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo chmod 777 mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo echo "This is my plain text" &gt; mountpoint/plain.txt</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo umount mountpoint</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo cryptsetup remove enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo losetup -d $loopdevice</code><br /></li>
</ol>

<dl>
  <dt>You will now see that you cannot dump the information from the disk image simply</dt>
  <dd><br />
{:start=”25”}<br />
    <ol>
      <li><code class="language-plaintext highlighter-rouge">strings enc.disk | grep -i plain</code><br /></li>
    </ol>
  </dd>
</dl>

<p>NOTE:</p>
<ul>
  <li>Do not store the pass-phrase in clear on the disk. In this case the disk.key
passphrase file needs to be secured.</li>
  <li>Either securely provide it  just-in-time or seal it on a security token that
anchors to the platform, like a TPM.</li>
</ul>

<h2 id="luks-disk-encryption-scheme-with-pass-phrase-stored-in-tpm2-as-the-protector">LUKS disk encryption scheme with pass-phrase stored in TPM2 as the protector.</h2>

<p>Auto mount would necessitate providing pass-phrase/ key to cryptsetup at runtime
without user intervention, hence the secret has to be provided to LUKS in clear.
The goal then to prevent an attacker mount the storage on another system can be
trivially defeated by giving access to the encryption secret in clear on the
file-system.<br /></p>

<p>Solution:<br />
a. Seal the secret into a TPM device.<br />
b. Unseal the secret in memory and pass it to cryptsetup.<br /></p>

<p>Let’s start with creating and persisting a sealing object and sealing a random
byte sequence as the disk key.<br />
{:start=”26”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_createprimary -Q -C o -c prim.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">dd if=/dev/urandom bs=1 count=32 status=none | tpm2_create -Q -g sha256 -u seal.pub -r seal.priv -i- -C prim.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_load -Q -C prim.ctx -u seal.pub -r seal.priv -n seal.name -c seal.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol -C o -c seal.ctx 0x81010001</code><br /></li>
</ol>

<p start="30">Now lets change the authentication from previously created disk.key to the new
sealed secret and after that shred the disk.key since it’s no longer useful:<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -Q -c 0x81010001 | sudo cryptsetup luksChangeKey enc.disk --key-file disk.key</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">shred disk.key; rm -f disk.key</code><br /></li>
</ol>

<p>Now let’s mount the volume with the new authentication sealed up in the tpm:<br />
{:start=”32”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo losetup $loopdevice enc.disk</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -Q -c 0x81010001 |sudo cryptsetup luksOpen --key-file=- $loopdevice enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mount /dev/mapper/enc_volume mountpoint</code><br /></li>
</ol>

<p>You can now see that disk access is granted with the new secret:<br />
{:start=”35”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">ls mountpoint</code>
<br /></li>
</ol>

<p>Finally unmount the disk:<br />
{:start=”36”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo umount mountpoint</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo cryptsetup remove enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo losetup -d $loopdevice</code><br /></li>
</ol>

<p>Attacker now additionally needs the TPM on platform along with the disk since
decryption key isn’t on the disk, its safely stored on the TPM anchored to the
specific platform.</p>

<p>NOTE:</p>
<ul>
  <li>Access control to security token has similar challenges as protecting
pass-phrases especially if it needs to be provided just-in-time.</li>
  <li>An authentication mechanism  that anchors to trusted system state and the
platform can be achieved with a TPM and it’s PCR sealing provision.</li>
</ul>

<h2 id="pcr-policy-authentication---access-control-of-sealed-pass-phrase-on-tpm2-with-pcr-sealing">PCR policy authentication - Access control of sealed pass-phrase on TPM2 with PCR sealing</h2>

<p>We can add a passphrase to the sealing object. But that necessitates storing it
in clear on the file-system. TPM cannot tell apart who presents the
authentication if any is set for a TPM object; and access is simply granted. At
a higher robustness level, the concern may also be that the attacker can now on
the same system, boot to an alternative OS whose login credentials are fully
controlled by the attacker. In this scenario, the sealing object without any
authentication defeats the security objective of keeping pass-phrase a secret to
the system.<br /></p>

<p>Solution:<br />
a. Implement Measured boot in pre-boot software and measure critical components
including OS-bootloader, kernel, initrd, etc. to PCRs so any changes would
reflect in PCR0.<br />
b. Use PCR as proxy authentication for the TPM sealing object.<br />
c. After unsealing the pass-phrase; extend the sealing PCRs so that the
pass-phrase cannot be unsealed gain.<br /></p>

<p>Let’s begin with creating a pcr policy with current value in PCR0 sha256 bank<br />
{:start=”39”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession -S session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policypcr -Q -S session.ctx -l sha256:0 -L pcr0.sha256.policy</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx</code><br /></li>
</ol>

<p>Now replace the seal object in TPM NV memory protecting the disk encryption
secret with a new one that adds the pcr policy we just created as an
authentication mechanism to access the sealed secret.<br />
{:start=”42”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -c 0x81010001 | tpm2_create -Q -g sha256 -u pcr_seal_key.pub -r pcr_seal_key.priv -i- -C prim.ctx -L pcr0.sha256.policy </code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol -C o -c 0x81010001</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_load -Q -C prim.ctx -u pcr_seal_key.pub  -r pcr_seal_key.priv -n pcr_seal_key.name -c pcr_seal_key.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol -c pcr_seal_key.ctx 0x81010001 -C o</code><br /></li>
</ol>

<p>Now let’s try to mount the encrypted disk again but this time the secret is
unsealed off a TPM object whose unsealing operation can only be accessed by
satisfying the PCR policy; in other words authenticating by virtue of intended
system software state being unchanged as reflected by the PCR value.<br />
{:start=”46”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo losetup $loopdevice enc.disk</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession --policy-session -S session.ctx </code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policypcr -Q -S session.ctx -l sha256:0</code><br /></li>
</ol>

<p>At this point ideally you would want unseal the secret in memory and pipe it
directly to the cryptsetup app like this –&gt; “tpm2_unseal -p session:session.ctx
-c 0x81010001 | sudo cryptsetup luksOpen –key-file=- $loopdevice enc_volume”.
However for the purpose of demonstrating flexible PCR in a later section we will
make a copy of the unsealed secret at this point to seal it with a new object
with flexible pcr policy. This breakdown to two steps<br />
{:start=”49”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -p session:session.ctx -c 0x81010001 &gt; disk_secret.bkup</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">cat disk_secret.bkup | sudo cryptsetup luksOpen --key-file=- $loopdevice enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx </code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mount /dev/mapper/enc_volume mountpoint/</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">ls mountpoint/</code><br /></li>
</ol>

<p>To prevent further attempts of unsealing the disk encryption secret, at this
point the RTM (trusted system software) is expected to extend a random value to
the PCR to prevent further unsealing. This is the same consequence of unintended
or malicious software state reflecting in the PCR. Thus causing the intended
consequence of failed policy check and thus a failed unsealing attempt.<br />
<br /></p>

<p>Let’s look at the PCR state prior to extending it and then again after
extending: <br />
{:start=”54”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_pcrlist -l sha256:0</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_pcrlist -l sha256:0</code><br /></li>
</ol>

<p>Now let’s try to unseal the sealed disk encryption secret with the dirty
PCR:<br />
{:start=”57”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession --policy-session -S session.ctx </code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policypcr -Q -S session.ctx -l sha256:0</code><br />
The following operation should result in policy check failure preventing the
unseal operation:<br />
{:start=”59”}<br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -p session:session.ctx -c 0x81010001</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx</code><br /></li>
</ol>

<p>NOTE:</p>
<ul>
  <li>The goal is to prevent unsealing of the secret during unintended software
change causing resulting PCR changes.</li>
  <li>However this scheme would break with intended software change and resulting
PCR changes.</li>
</ul>

<h2 id="addressing-pcr-brittleness-from-intentional-software-updates-with-authorized-policies">Addressing PCR brittleness from intentional software updates with authorized policies</h2>

<p>System software updates is an indispensable part of sane system design. However,
it presents a problem when it comes to sealing secrets to PCR reflecting a
specific system software state. In that, you now are in state where you have a
new set of valid PCRs value that cannot be known ahead of time and yet the 
authentication of the TPM sealing object must be tied to the PCR somehow.<br /></p>

<p>Solution:<br />
Authorized PCR policy as an authentication mechanism for the TPM sealing object.
Instead of using a rigid PCR policy tied to raw PCR values we now seal it to a
PCR signature. The PCR sets are signed by the system designer and verified by
the TPM. This is achieved in following steps:</p>

<p><strong>a. Get the new set of PCR and sign the pcr policy with signer private key.</strong><br />
{:start=”61”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession -S session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policypcr -Q -S session.ctx -l sha256:0 -L set2.pcr.policy</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">openssl genrsa -out signing_key_private.pem 2048</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">openssl rsa -in signing_key_private.pem -out signing_key_public.pem -pubout</code><br /></li>
</ol>

<p>We now need the name which is a digest of the TCG public key format of the
public key to include in the policy. We can use the loadexternal tool for this:<br />
{:start=”66”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_loadexternal -G rsa -C o -u signing_key_public.pem -c signing_key.ctx -n signing_key.name</code><br /></li>
</ol>

<p>Let’s now create the signer policy:<br />
{:start=”67”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession -S session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policyauthorize -S session.ctx -L authorized.policy -n signing_key.name -i set2.pcr.policy</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx</code><br /></li>
</ol>

<p>Let’s create a new sealing object with the authorized policy which will also
require the sealing secret for which we will use the disk_secret.bkup we created
at #49 earlier to avoid rebooting the platform to match the PCR we originally
had prior to extending.<br />
{:start=”70”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">cat disk_secret.bkup | tpm2_create -g sha256 -u auth_pcr_seal_key.pub -r auth_pcr_seal_key.priv -i- -C prim.ctx -L authorized.policy</code><br /></li>
</ol>

<p>Let’s replace the old persistent sealing object with the one we created
above with policy_authorize policy associated with signer public key:<br />
{:start=”71”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol -C o -c 0x81010001</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_load -Q -C prim.ctx -u auth_pcr_seal_key.pub  -r auth_pcr_seal_key.priv -n auth_pcr_seal_key.name -c auth_pcr_seal_key.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_evictcontrol -c auth_pcr_seal_key.ctx 0x81010001 -C o</code><br />
Let’s now sign the pcr_policy with the signer private key:<br /></li>
  <li><code class="language-plaintext highlighter-rouge">openssl dgst -sha256 -sign signing_key_private.pem -out set2.pcr.signature set2.pcr.policy</code><br /></li>
</ol>

<p><strong>b. Load the signer public key to the tpm and verify the signature on the pcr 
and get the tpm verification tkt:</strong><br />
{:start=”75”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_loadexternal -G rsa -C o -u signing_key_public.pem -c signing_key.ctx -n signing_key.name</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_verifysignature -c signing_key.ctx -g sha256 -m set2.pcr.policy  -s set2.pcr.signature -t verification.tkt -f rsassa</code><br /></li>
</ol>

<p><strong>c. Satisfy the authorized policy and then run policyauthorize:</strong><br />
{:start=”77”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">tpm2_startauthsession --policy-session -S session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policypcr -l sha256:0 -S session.ctx</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_policyauthorize -S session.ctx -i set2.pcr.policy -n signing_key.name -t verification.tkt</code><br /></li>
</ol>

<p><strong>d. Pipe unseal output to the cryptsetup application:</strong><br />
{:start=”80”}<br /></p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">sudo losetup $loopdevice enc.disk</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_unseal -p session:session.ctx -c 0x81010001 | sudo cryptsetup luksOpen --key-file=- $loopdevice enc_volume</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">tpm2_flushcontext session.ctx </code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">sudo mount /dev/mapper/enc_volume mountpoint/</code><br /></li>
  <li><code class="language-plaintext highlighter-rouge">ls mountpoint/</code><br /></li>
</ol>

<h1 id="summarizing-the-various-roles-in-setting-up-the-disk-encryption">Summarizing the various roles in setting up the disk encryption</h1>

<p>Disk encryption is a system designer’s liability. Loss of the encryption key is
an unintended consequence of denial of service since in this scenario an
attacker cannot be told apart. It may generally be a good idea to save a rescue
key; LUKS affords this flexibility by providing up to 8 slots of authentication
token, all of which can decrypt the disk. Look in to cryptsetup luksAdd option.</p>

<h2 id="platform-provisioning">Platform Provisioning<br /></h2>
<p><strong>a. Initialize disk with LUKS :</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #12 through #21</code><br />
<strong>b. Create pcr policy.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #61, #62, #63</code><br />
<strong>c. Create signing authority for signing the policies and provision public key in system.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #64, #65</code><br />
<strong>d. Create authorized policy for creating the sealing object.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: $67, #68, #69</code><br />
<strong>e. Create secure passphrase and seal to the sealing object.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #70</code><br /></p>

<h2 id="system-software-integrator">System/ Software integrator<br /></h2>
<p><strong>a. Sign valid pcr policies and provide the policy and the signature.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #74</code><br /></p>

<h2 id="platform-runtime">Platform runtime<br /></h2>
<p><strong>a. Load signer public key</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #75</code><br />
<strong>b. Verify signature on the PCR policy and generate verification ticket.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #76</code><br />
<strong>c. Satisfy PCR policy and authorized policy.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #77, #78, #79</code><br />
<strong>d. Unseal the secret and pipe to cryptsetup to open the LUKS encrypted volume.</strong><br />
   <code class="language-plaintext highlighter-rouge">commands: #80, #81, #82, #83</code><br /></p>

<h1 id="author">Author</h1>
<p>Imran Desai</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Introduction In an increasingly data heavy world we live in today, data security has become critical for connected-devices, corporations, and individuals alike. It is important to keep data protected at rest especially at source and also in transit. Hence digital encryption schemes have become paramount for protecting the confidentiality and integrity of the data. Of the multitude of encryption mechanisms for protecting the confidentiality AES XTS (cipher text stealing) mode is most commonly used. Encryption schemes function by virtue of protecting the encryption secret which is also termed encryption key.]]></summary></entry><entry><title type="html">Remote Attestation</title><link href="https://tpm2-software.github.io/tpm2-tss/getting-started/2019/12/18/Remote-Attestation.html" rel="alternate" type="text/html" title="Remote Attestation" /><published>2019-12-18T12:24:05+00:00</published><updated>2019-12-18T12:24:05+00:00</updated><id>https://tpm2-software.github.io/tpm2-tss/getting-started/2019/12/18/Remote-Attestation</id><content type="html" xml:base="https://tpm2-software.github.io/tpm2-tss/getting-started/2019/12/18/Remote-Attestation.html"><![CDATA[<h1 id="remote-attestation-best-known-methods">Remote Attestation Best Known Methods</h1>

<h2 id="introduction">Introduction</h2>
<p>There are many cases where it is crucial to verify the correctness of software
and hardware configuration of a computer system. For instance, to improve the
security of a corporate network, companies need to ensure that the systems that
are allowed to connect to the corporate network are legitimate, and that the
software that runs on the system is in a valid, known state. There are many
different methods to ensure the above. This document describes a method that
uses a Trusted Platform Module (TPM). TPM device can be used to validate a system
integrity by implementing an attestation protocol. Trusted Computing Group (TCG)
published a Trusted Attestation Protocol Information Model (TAP), which
can be found at [1]. The TCG specification describes roles and message flows.
The specific data format and binding to a protocol require additional “binding”
specifications. The two main roles in this scenario are Verifier and Attester.
A Verifier sends a challenge query to a system that selects the scope of
attestation. The Attester collects attestation evidence (within the expected
scope) that is to be verified (Attester). The Attester typically describes its
boot state, current configuration and identity. Machine identities can establish
supply chain provenance if the machine identity credentials are provisioned
during manufacturing. One of the identities is known as the Endorsement Key
(EK) certificate. The EK key may be used to provision attestation identities
known as an Attestation Key certificate. Alternatively, the manufacturer may
pre-provision an Attestation Key known as an Initial Attestation Key (IAK)
which avoids having to provision it at onboarding or deployment.
The Attestation Key is used to sign attestation evidence that is conveyed to the
Verifier. After receiving the response, the Verifier can cryptographically check
if the evidence satisfies the Verifier’s trust appraisal policy and if the
device originated from an approved manufacturer. The manufacturer embedded EK
and/or IAK and associated certificate path is what establishes device provenance
to a vendor.</p>

<h2 id="key-provisioning">Key Provisioning</h2>
<p>A platform with a TPM root-of-trust may be pre-provisioned with attestation and
identities or they may be provisioned as part of device onboarding and deployment.
Pre-provisioned keys and credentials are typically referred to as “Initial”
while credentials provisioned at onboarding typically are referred to as “local”.
However, a TPM pre-provisioned with only an EK may provision “Initial” keys at
different stages in the supply chain including as part of device onboarding.
Hence, TPM supports provisioning that happens over different stages.
There are keys that are instantiated during manufacturing time by the TPM Vendor,
other keys need to be instantiated during system assembly by the OEM, and other
keys are instantiated by the system owner or user.  TCG Provisioning Guidance [2]
specification provides recommendations for key provisioning.
Usually, TPM vendors provision the TPM device with a Primary Endorsement Key (PEK),
and generate a certificate for that key (EK cert) in x.509 format at the time of
manufacture. The EK Certificate contains the public part of the PEK, as well as
other useful fields, such as TPM manufacturer name, part model, part version,
key id, etc. This information can be used to uniquely identify the TPM and if
the device OEM securely attaches a TPM to the device it can be used as a device
identifier. The EK certificate may be stored in the TPM Non Volatile Memory (NVM),
where it can be made available to client software or it could be made available
online via the OEM’s website.
The EK certificate is issued (cryptographically signed) by the TPM vendor’s CA
and verifiers are assumed to trust the vendor’s root certificate. It is important
to note that the private part of the EK key is expected to never be exposed
outside of the TPM hardware. This ensures an attack TPM cannot easily masquerade
as coming from a trusted vendor. To improve interoperability between vendors and
adopters TCG also provides recommendations and guidelines for EK Credential
values, which can be found in the TCG EK Credential Profile [3].
The Vendor may also instantiate an IDevID Key, that is used to uniquely identify
the TPM device. At a later point the user may create more keys in the Endorsement
hierarchy, that will be protected (wrapped) by the Primary EK. Tpm2_createek
command can be used to generate a new EK. Note that Tpm2_createek will create
the same key when invoked with the same template and the same Endorsement
Primary Seed. Next, when the TPM is integrated into a system, the OEM generates
a Primary Attestation Key (PAK) that is also stored in the TPM’s Non Volatile
Memory and Attestation Key certificate, which references the Primary EK stored
in the TPM. The OEM may also generate Initial Attestation Key (IAK) and IAK
Certificate, which along with IDevID Key are used to platform identification,
and signs it with the OEM’s preferred CA. Provisioning of other keys, such as
Primary Storage Key (PSK), that are not used in attestation process are out of
scope of this document. These keys can be generated on demand by the owner/user,
don’t need to be signed by third party (Vendor, OEM), and no certificates are
needed for them. Diagram 1 depictures the steps how a new TPM device is
provisioned when it is installed in a system.</p>

<p><img src="/images/diag1.png" alt="Diagram 1:  Attestation key provisioning" /></p>

<h2 id="attestation-procedure">Attestation Procedure</h2>
<p>Before a system can be attested the owner needs to obtain the public key of the
TPM Vendor generated Endorsement Key and OEM generated Attestation Key along with
the appropriate certificates. Certificates can be obtained by reading the TPM
NonVolatile memory at a predefined location, or by obtaining them from Vendor/OEM websites.
The Verifier normally stores these keys and certificates in a local database,
usually integrated with the corporate PKI infrastructure.
Another object typically stored in the Verifier’s local database is a policy that
identifies an expected initial state of the device as defined by the software installed
on the Attester system. The various vendor(s) of boot software contribute digests
of the software to Verifiers to be used as a reference for comparing digests to
attestation evidence.
Boot software needs to be measured during platform setup stage, and include
measurements (digests) for the bootloader, OS, drivers, and appropriate user
space applications. The measurements are stored in a local database and are used later,
during attestation, to make determination if a system is in a good state.
The user may also create a policy that will make the Attestation Key bound,
or sealed to the initial state of the system.
For a data center deployments, where many nodes run on similar hardware configuration
and run the same software, this can be measured for a single platform and then used
as base measurement for different systems with similar hardware and software configuration.
Another piece of functionality that needs to be enabled on the to be attested
systems is measured boot. If it is enabled the system software will measure the
images of every software module, on different levels during the boot process,
record the measured values in the Platform Configuration Registers (PCRs) within
the TPM, and created a system Event Log with a separate entry for every software
image measured. First ‘Secure Boot’ option needs to be enabled in the BIOS configuration,
and it also needs to be supported by the bootloader and the Operation System.
Most of the recent UEFI based platforms, bootloaders and Operating Systems do
support measured/secure boot.
The attestation operation is initialized by the verifier.
It can be started on a time based interval or in response to a network resource
access request. The verifier requests the attester’s AK and EK certificates,
validate them against the corporate Root CA, and if they are valid it creates a
challenge including key id, PCR selection, and random nonce. The attestor loads
the Endorsement Key (EK) and Attestation Key (AK), if  they are not already loaded,
and issues a TPM2_Quote command to the TPM, referencing the Attestation Key.
TPM will only be able to use the key if the given PCRs will be in a valid state,
defined at the time when the PCR policy is created. After that TPM creates and
signs an instance of TPMS_ATTEST structure as defined by [5] and sends it back
to the verifier. The Verifier uses the information included in the TPMS_ATTEST
structure to perform appraisal by validating the public part of the AK and comparing
the software measurement logs (Event Log) against the good-know-state of the system
software configuration stored in the local database. Diagram 2 shows the
attestation challenge flow.</p>

<p><img src="/images/diag2.png" alt="Diagram 2:  Attestation challenge" /></p>

<p>The verify can compare every entry in the event log stored in the database with
the corresponding entry in the TPMS_ATTEST structure to verify the state of
bootloader, Operating System, user applications, and make arbitrary decisions
based on the results of the verification process. The Diagram 3 shows the
verification step performed by the verifier.</p>

<p><img src="/images/diag3.png" alt="Diagram 3: Verification of the quote" /></p>

<h2 id="field-upgrade-and-disaster-recovery">Field upgrade and disaster recovery</h2>
<p>When planning the implementation of the attestation in the corporate infrastructure
it is also important to plan for platform firmware upgrades, operating system,
or user space application updates. It is also important to plan recovery procedures
in case of major failures, 0-days vulnerability disclosures, etc. Just as any other
piece of corporate infrastructure TPM can become a target for an attack.
Recently published TPM fail [6] paper showed that even some hardware TPMs can
be vulnerable to timing attacks. In case of any of the mentioned situations it might
be required to re-instantiate the affected TPM keys, and even the TPM modules itself,
measure the system hardware and software configuration state and make appropriate
adjustments in the local database, in which the measurements, keys, and key
certificates are stored. TPM key upgrade and recovery should be part of an
enterprise key management strategy. TPM device can generate and store keys that
are non-migratable, and EK is an example of a non-migratable key.
In this case it is recommended to follow the TPM vendor’s recommendations and
procedures for managing the keys. When making a decision on what TPM vendor to
choose it is important to check beforehand what level of support is provided,
and what are the recommended recovery procedures [7].</p>

<h2 id="references">References</h2>
<ol>
  <li><a href="https://trustedcomputinggroup.org/wp-content/uploads/TNC_TAP_Information_Model_v1.00_r0.29A_publicreview.pdf">TCG, Trusted Attestation Protocol (TAP)</a></li>
  <li><a href="https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-v2.0-Provisioning-Guidance-Published-v1r1.pdf">TCG, TPM v2.0 Provisioning Guidance</a></li>
  <li><a href="https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_Credential_Profile_EK_V2.1_R13.pdf">TCG, EK Credential Profile</a></li>
  <li><a href="https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-1-Architecture-01.38.pdf">TCG, TPM2.0 Library Specification, part 1- Architecture</a></li>
  <li><a href="https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-2-Structures-01.38.pdf">TCG, TPM2.0 Library Specification, part 2- Structures</a></li>
  <li><a href="https://tpm.fail/tpmfail.pdf">Timing and Lattice Attacks on the TPM</a></li>
  <li><a href="https://www.infineon.com/dgdl/Infineon-TPM_Key_Backup_and_Recovery-AP-v01_00-EN.pdf?fileId=db3a304412b407950112b41656d7203a">Infineon, TPM Key backup and recovery</a></li>
</ol>]]></content><author><name></name></author><category term="tpm2-tss" /><category term="getting-started" /><category term="attestation" /><summary type="html"><![CDATA[Remote Attestation Best Known Methods]]></summary></entry><entry><title type="html">Getting Started</title><link href="https://tpm2-software.github.io/tpm2-tss/getting-started/2019/02/05/Getting-Started.html" rel="alternate" type="text/html" title="Getting Started" /><published>2019-02-05T17:28:05+00:00</published><updated>2019-02-05T17:28:05+00:00</updated><id>https://tpm2-software.github.io/tpm2-tss/getting-started/2019/02/05/Getting-Started</id><content type="html" xml:base="https://tpm2-software.github.io/tpm2-tss/getting-started/2019/02/05/Getting-Started.html"><![CDATA[<p>This tutorial is pretty much just a placeholder to show how future tutorials can be created here inside jekyll.</p>

<p>Stay put for future updates.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">git clone https://github.com/tpm2-software/tpm2-tss
<span class="nb">cd </span>tpm2-tss
./bootstrap
./configure <span class="nt">--enable-integration</span>
make <span class="nt">-j</span><span class="si">$(</span><span class="nb">nproc</span><span class="si">)</span>
make check</code></pre></figure>

<p>Check out the <a href="https://github.com/tpm2-software/tpm2-tss/blob/master/README.md">tpm2-tss README</a> and <a href="https://github.com/tpm2-software/tpm2-tss/blob/master/INSTALL.md">tpm2-tss INSTALL</a> for more information.</p>

<p>After successful installation a standalone application using ESAPI can be compiled as follows:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">gcc standalone-example.c <span class="nt">-L</span><span class="o">=</span>/usr/local/lib/ <span class="nt">-ltss2-esys</span> <span class="nt">-o</span> standalone-example</code></pre></figure>

<p>Simple example standalone application:</p>

<figure class="highlight"><pre><code class="language-c" data-lang="c"><span class="cp">#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;tss2/tss2_esys.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>

    <span class="n">TSS2_RC</span> <span class="n">r</span><span class="p">;</span>

    <span class="cm">/* Initialize the ESAPI context */</span>
    <span class="n">ESYS_CONTEXT</span> <span class="o">*</span><span class="n">ctx</span><span class="p">;</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">Esys_Initialize</span><span class="p">(</span><span class="o">&amp;</span><span class="n">ctx</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">!=</span> <span class="n">TSS2_RC_SUCCESS</span><span class="p">){</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Error: Esys_Initializen</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="cm">/* Get random data */</span>
    <span class="n">TPM2B_DIGEST</span> <span class="o">*</span><span class="n">random_bytes</span><span class="p">;</span>
    <span class="n">r</span> <span class="o">=</span> <span class="n">Esys_GetRandom</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">ESYS_TR_NONE</span><span class="p">,</span> <span class="n">ESYS_TR_NONE</span><span class="p">,</span> <span class="n">ESYS_TR_NONE</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span>
                       <span class="o">&amp;</span><span class="n">random_bytes</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">r</span> <span class="o">!=</span> <span class="n">TSS2_RC_SUCCESS</span><span class="p">){</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Error: Esys_GetRandom</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
        <span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">random_bytes</span><span class="o">-&gt;</span><span class="n">size</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">printf</span><span class="p">(</span><span class="s">"0x%x "</span><span class="p">,</span> <span class="n">random_bytes</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
    <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span></code></pre></figure>]]></content><author><name></name></author><category term="tpm2-tss" /><category term="getting-started" /><category term="bash" /><category term="make" /><category term="code" /><summary type="html"><![CDATA[This tutorial is pretty much just a placeholder to show how future tutorials can be created here inside jekyll.]]></summary></entry></feed>