<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Davis Muro</title>
      <link>https://davisraym.com</link>
      <description>Rants and Other Stuff</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://davisraym.com/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 24 Jan 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>Talking to a TPM 2.0: Startup, Provisioning, and Reading Raw Commands</title>
          <pubDate>Sat, 24 Jan 2026 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/blog/tpm-startup-and-provisioning/</link>
          <guid>https://davisraym.com/blog/tpm-startup-and-provisioning/</guid>
          <description xml:base="https://davisraym.com/blog/tpm-startup-and-provisioning/">&lt;p&gt;TPM 2.0 is often treated as a magic switch you “turn on in BIOS.” In reality,
it’s just a device on a bus that speaks a very concrete binary protocol.&lt;&#x2F;p&gt;
&lt;p&gt;If you’ve ever wondered:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What actually happens when the TPM “starts”&lt;&#x2F;li&gt;
&lt;li&gt;How to tell whether a TPM is really provisioned&#x2F;manufactured&lt;&#x2F;li&gt;
&lt;li&gt;What all those handles (0x4000… &#x2F; 0x8000…) mean&lt;&#x2F;li&gt;
&lt;li&gt;How to read a raw TPM command&#x2F;response at the byte level&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;this post walks through those pieces using real command dumps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-startup-tpm-init-vs-tpm2-startup&quot;&gt;1. Startup: _TPM_Init() vs TPM2_Startup()&lt;&#x2F;h2&gt;
&lt;p&gt;Before you can send “normal” commands (like &lt;code&gt;GetRandom&lt;&#x2F;code&gt; or &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt;), the
TPM has to go through a startup sequence.&lt;&#x2F;p&gt;
&lt;p&gt;There are two distinct layers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;_TPM_Init()&lt;&#x2F;code&gt;
A hardware&#x2F;firmware signal that the TPM was just powered on or reset.
Think of this like pulling the reset line: volatile state is lost, transient
objects are gone, and the TPM expects a startup command.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TPM2_Startup(SU_CLEAR | SU_STATE)&lt;&#x2F;code&gt;
A &lt;em&gt;command&lt;&#x2F;em&gt; you send over the TPM’s interface to tell it what type of startup
to perform:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SU_CLEAR&lt;&#x2F;code&gt;: cold boot, initialize everything from scratch&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;SU_STATE&lt;&#x2F;code&gt;: resume from a previously saved state (e.g., sleep), if supported&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;On typical PCs, firmware (UEFI&#x2F;BIOS) issues &lt;code&gt;TPM2_Startup&lt;&#x2F;code&gt; for you. On dev
boards, embedded systems, or some test setups, you may be responsible for
sending it yourself. If you skip it, the TPM won’t behave like a normal device.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-1-what-happens-if-you-skip-startup&quot;&gt;1.1 What Happens If You Skip Startup&lt;&#x2F;h3&gt;
&lt;p&gt;If you try to send a command before &lt;code&gt;TPM2_Startup&lt;&#x2F;code&gt;, you’ll run into error
codes like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TPM_RC_INITIALIZE&lt;&#x2F;code&gt; — “I haven’t been started yet.”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here’s an example using &lt;code&gt;TPM2_GetRandom&lt;&#x2F;code&gt; before startup. The request is:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
            REQUEST
==============================

TPM Command Tag (hex): 0x8001
- TPM_ST_NO_SESSIONS: command has no session area.

TPM Command Length (hex): 0x0000000c
- 0x0c = 12 bytes total command size.

TPM Command Code (hex): 0x0000017b
- TPM_CC_GetRandom.

TPM Command (hex), annotated:

Offset  Bytes          Meaning
------  -----          -------
00      80 01          tag = 0x8001 (command, no sessions)
02      00 00 00 0c    length = 0x0000000c (12 bytes)
06      00 00 01 7b    commandCode = 0x0000017b (GetRandom)
0a      00 10          bytesRequested = 0x0010 (16 bytes)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The TPM’s response:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
            RESPONSE
==============================

TPM Response Tag (hex): 0x8001
- Response without sessions.

TPM Response Size (hex): 0x0000000a
- 0x0a = 10 bytes total response size (minimal error response).

TPM Error Response core: 00 00 01 00
- responseCode = 0x00000100 = TPM_RC_INITIALIZE.

Offset  Bytes          Meaning
------  -----          -------
00      80 01          tag = 0x8001 (response, no sessions)
02      00 00 00 0a    length = 0x0000000a (10 bytes)
06      00 00 01 00    responseCode = 0x00000100 (TPM_RC_INITIALIZE)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The takeaway: until &lt;code&gt;_TPM_Init()&lt;&#x2F;code&gt; has occurred &lt;em&gt;and&lt;&#x2F;em&gt; a successful
&lt;code&gt;TPM2_Startup(SU_CLEAR or SU_STATE)&lt;&#x2F;code&gt; has been processed, the TPM refuses to act
like a fully initialized device.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;2-is-this-tpm-manufactured-provisioning-and-hierarchies&quot;&gt;2. “Is This TPM Manufactured?” — Provisioning and Hierarchies&lt;&#x2F;h2&gt;
&lt;p&gt;With “normal” PCs, the TPM you see is usually already provisioned by the
platform vendor. With raw TPM modules or engineering samples, that’s not always
true.&lt;&#x2F;p&gt;
&lt;p&gt;When people say a TPM is “manufactured” or “provisioned,” they usually mean:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;endorsement hierarchy&lt;&#x2F;strong&gt; is configured (and may have vendor certificates).&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;strong&gt;storage (owner) hierarchy&lt;&#x2F;strong&gt; has a valid primary seed.&lt;&#x2F;li&gt;
&lt;li&gt;Default or vendor-defined authorization values are set.&lt;&#x2F;li&gt;
&lt;li&gt;Commands like &lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt; work as expected under those hierarchies.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-1-commands-involved-in-provisioning&quot;&gt;2.1 Commands Involved in Provisioning&lt;&#x2F;h3&gt;
&lt;p&gt;Depending on the vendor, provisioning flows may involve:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TPM2_Clear&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Reset owner and endorsement hierarchies to a factory-like state
(subject to platform policy).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TPM2_HierarchyChangeAuth&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Set new authorization values (passwords or policies) for:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Owner (storage) hierarchy&lt;&#x2F;li&gt;
&lt;li&gt;Endorsement hierarchy&lt;&#x2F;li&gt;
&lt;li&gt;Lockout hierarchy&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Vendor tools that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Create and persist an Endorsement Key (EK)&lt;&#x2F;li&gt;
&lt;li&gt;Create an SRK-like primary key in the storage hierarchy&lt;&#x2F;li&gt;
&lt;li&gt;Populate NV indices with vendor data&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;On many motherboards or laptops, UEFI&#x2F;BIOS runs all of this once, then exposes a
“Ready to use” TPM to the OS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-2-how-to-tell-if-a-tpm-is-provisioned&quot;&gt;2.2 How to Tell If a TPM Is Provisioned&lt;&#x2F;h3&gt;
&lt;p&gt;You can probe TPM state with capability and property queries:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TPM2_GetCapability(TPM_CAP_TPM_PROPERTIES, ...)&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
For things like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TPM_PT_PERMANENT&lt;&#x2F;code&gt; (flags about hierarchy enablement and lockout)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TPM_PT_STARTUP_CLEAR&lt;&#x2F;code&gt; (what clears on startup)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TPM2_GetCapability(TPM_CAP_HANDLES, ...)&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
To see whether certain handle ranges are in use.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A very practical test is: &lt;strong&gt;try to create a primary in the storage or
endorsement hierarchy&lt;&#x2F;strong&gt;. If the TPM is correctly manufactured, a simple
&lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt; under the storage hierarchy (&lt;code&gt;0x40000001&lt;&#x2F;code&gt;) should succeed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-handles-and-object-creation-createprimary-vs-create&quot;&gt;3. Handles and Object Creation: CreatePrimary vs Create&lt;&#x2F;h2&gt;
&lt;p&gt;Handles are where a lot of people get confused. They look like arbitrary 32‑bit
numbers, but the ranges are meaningful.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-1-handle-types-quick-reference&quot;&gt;3.1 Handle Types (Quick Reference)&lt;&#x2F;h3&gt;
&lt;p&gt;For this post, the main ones are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hierarchies&lt;&#x2F;strong&gt; (fixed handles)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Storage&#x2F;Owner: &lt;code&gt;0x40000001&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Endorsement:   &lt;code&gt;0x4000000B&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Platform:      &lt;code&gt;0x4000000C&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Null:          &lt;code&gt;0x40000007&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transient objects&lt;&#x2F;strong&gt;: &lt;code&gt;0x8000_0000&lt;&#x2F;code&gt;–&lt;code&gt;0x80FF_FFFF&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Live in TPM RAM.&lt;&#x2F;li&gt;
&lt;li&gt;Disappear on reset&#x2F;power loss.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Persistent objects&lt;&#x2F;strong&gt;: &lt;code&gt;0x8100_0000&lt;&#x2F;code&gt;–&lt;code&gt;0x81FF_FFFF&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Survive across resets.&lt;&#x2F;li&gt;
&lt;li&gt;You “pin” a transient object with &lt;code&gt;TPM2_EvictControl&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In typical flows you:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use a &lt;strong&gt;hierarchy handle&lt;&#x2F;strong&gt; as the parent when calling &lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Get back a &lt;strong&gt;transient object handle&lt;&#x2F;strong&gt; in the &lt;code&gt;0x8000_0000&lt;&#x2F;code&gt; range.&lt;&#x2F;li&gt;
&lt;li&gt;Use that transient handle as parent in &lt;code&gt;TPM2_Create&lt;&#x2F;code&gt;, &lt;code&gt;TPM2_Load&lt;&#x2F;code&gt;, etc.&lt;&#x2F;li&gt;
&lt;li&gt;Optionally turn that transient handle into a &lt;strong&gt;persistent&lt;&#x2F;strong&gt; one with
&lt;code&gt;TPM2_EvictControl&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3-2-tpm2-createprimary-getting-a-first-handle&quot;&gt;3.2 &lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt;: Getting a First Handle&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt; creates a primary object directly under a hierarchy
(storage, endorsement, etc.):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Input:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hierarchy handle (e.g. &lt;code&gt;0x40000001&lt;&#x2F;code&gt; for storage)&lt;&#x2F;li&gt;
&lt;li&gt;Authorization for that hierarchy (often empty during initial provisioning)&lt;&#x2F;li&gt;
&lt;li&gt;Template for the new object (type, algorithms, attributes)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Output:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;transient object handle&lt;&#x2F;strong&gt; (e.g. &lt;code&gt;0x80000000&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;The object’s public area (&lt;code&gt;TPM2B_PUBLIC&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Creation data, hash, and ticket (metadata about how&#x2F;where it was created)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;a real &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt; command dump (simplified and annotated).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-2-1-example-raw-createprimary-command-success-and-error&quot;&gt;3.2.1 Example: Raw &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt; Command, Success, and Error&lt;&#x2F;h4&gt;
&lt;p&gt;Command:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
            REQUEST
==============================

TPM Command Tag (hex): 0x8002
- TPM_ST_SESSIONS: command includes a session area (for auth).

TPM Command Length (hex): 0x0000003f
- 0x3f = 63 bytes total command size.

TPM Command Code (hex): 0x00000131
- TPM_CC_CreatePrimary.

TPM Command (hex):
80 02 00 00 00 3f 00 00 01 31 40 00 00 01 00 00 00 09
40 00 00 09 00 00 00 00 00 00 00 00 1a 00 01 00 0b 00
03 00 72 00 00 00 06 00 80 00 43 00 10 08 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Breaking down just the key fields:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;Offset  Bytes              Meaning
------  -----              -------
00      80 02              tag = 0x8002 (command with sessions)
02      00 00 00 3f        length = 0x0000003f (63 bytes)
06      00 00 01 31        commandCode = 0x00000131 (CreatePrimary)

0A      40 00 00 01        parent = 0x40000001 (storage hierarchy)

0E      00 00 00 09        authSize = 9 bytes in auth area

12      40 00 00 09        sessionHandle = 0x40000009
                          (simple auth session handle here)

16      00 00              nonceSize = 0 (no nonce)
18      00                 sessionAttributes = 0
19      00 00              hmacSize = 0 (empty auth)

1B      00 1a              inPublic.size = 0x001a (26 bytes)

1D      00 01              type = TPM_ALG_RSA (0x0001)
1F      00 0b              nameAlg = TPM_ALG_SHA256 (0x000B)

21      00 03 00 72        objectAttributes (bitfield)
25      00 00              authPolicy.size = 0 (no policy)

27      00 06              parameter size &#x2F; start of RSA params
29      00 80 00 43 00 10 08  ...
                          (RSA keyBits, exponent, scheme, symmetric info)

...     (rest of template &#x2F; padding)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h5 id=&quot;successful-createprimary-response-annotated&quot;&gt;Successful &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt; Response (Annotated)&lt;&#x2F;h5&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
            RESPONSE          
==============================

TPM Response Tag (hex): 0x8002
- TPM_ST_SESSIONS: response includes a session area.

TPM Response Size (hex): 0x000001ea
- 0x1ea = 490 bytes total response size.

TPM Response Code (hex): 0x00000000
- TPM_RC_SUCCESS.

TPM Response (hex):
80 02 00 00 01 ea 00 00 00 00 80 00 00 00 00 00 
01 d3 01 1a 00 01 00 0b 00 03 04 72 00 00 00 06 
00 80 00 43 00 10 08 00 00 00 00 00 01 00 cc f4 
c7 e3 16 f1 63 41 80 93 d2 19 7d 52 5a 90 9e 54 
82 ea 4a 5e 47 52 f7 12 7a 59 18 bf a1 d5 62 1e 
44 ca 2d 40 de 0b 3d 64 e4 51 e6 f0 f5 f6 a4 e1 
a3 6f 22 cf 9e 63 56 4d e2 78 57 21 68 51 d7 aa 
cf 28 59 48 61 6c 63 c1 46 b6 cb a8 14 25 af d8 
23 1b c2 03 62 1c c5 7e 1a ab c3 b4 76 6c 71 fa 
4c 61 54 c6 f6 18 0e 33 65 fa 1c 0c ab fa 20 07 
f8 37 2a e5 15 00 7e 87 95 cf ca f7 75 87 5c c6 
f9 f2 76 27 58 28 2f c7 d7 e7 df 68 93 14 e7 4d 
fb 8e 4f a2 d9 da c8 d3 90 69 f3 84 8c c2 ff 85 
c1 23 cb c6 61 60 a5 7e 82 9c 83 5b 1e 05 1f 77 
68 c8 32 6d 91 e5 da 02 52 de 43 e3 2a d7 52 d6 
da f4 c6 5d 87 c1 ba 2f 74 c8 87 fe 09 ca ba 40 
e9 f8 df 96 17 d0 a7 7a dc 13 4f 08 f1 a7 30 c8 
3f d0 04 0d be 9a a9 be ad 4d 3f 6e 33 2b 98 b4 
e9 3d 08 1a ea 20 ca d0 7e d3 66 7c e2 ef 00 37 
00 00 00 00 00 20 e3 b0 c4 42 98 fc 1c 14 9a fb 
f4 c8 99 6f b9 24 27 ae 41 e4 64 9b 93 4c a4 95 
99 1b 78 52 b8 55 01 00 10 00 04 40 00 00 01 00 
04 40 00 00 01 00 00 00 20 5d a0 41 ba c0 ee 31 
35 ae bb 0c ad fb a4 97 c6 a1 87 7f ae 83 2d d3 
d1 f8 f7 a8 71 b8 25 e8 54 80 21 40 00 00 01 00 
30 f3 79 37 38 d5 69 6c 1c 36 59 9e ec 09 bf 22 
9e 92 aa 3a 9d 76 59 69 1e 1f ca 41 5d d0 db a3 
6b 6b ed 5e 38 98 6b 19 76 d7 64 6b 47 e9 4c e0 
9f 00 22 00 0b 4a 08 3c 3b 94 77 e9 82 76 05 11 
87 bc f5 3d ef ef af 5d 97 56 bd fa df 6f a9 32 
14 ce 8b 00 85 00 00 01 00 00 
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Breaking down the key parts of the successful response:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;Offset  Bytes              Meaning
------  -----              -------
00      80 02              tag = 0x8002 (response with sessions)
02      00 00 01 ea        length = 0x000001ea (490 bytes)
06      00 00 00 00        responseCode = 0x00000000 (TPM_RC_SUCCESS)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The next fields are the normal &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt; return parameters:&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;0A      80 00 00 00        handle = 0x80000000
                          - Transient handle for the new primary object.

0E      00 00              outPublic.size MSB
10      00 01 d3 01 ...    outPublic (TPM2B_PUBLIC)
                          - Public area for the created key:
                            * type = TPM_ALG_RSA (0x0001)
                            * nameAlg = TPM_ALG_SHA256 (0x000B)
                            * objectAttributes = 0x00030472
                            * RSA parameters (key size, exponent, scheme)
                            * public modulus (unique.rsa)

...                        outCreationData (TPM2B_CREATION_DATA)
                          - Creation-time state and locality info.

...                        creationHash (TPM2B_DIGEST)
                          - Hash of the creation data.

...                        creationTicket (TPMT_TK_CREATION)
                          - Ticket proving this object was created by the TPM.

...                        outName (TPM2B_NAME)
                          - The computed name of the new object.

...                        sessionArea
                          - Session response (auth, nonce, attributes, HMAC if used).
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The exact byte offsets for &lt;code&gt;outPublic&lt;&#x2F;code&gt;, &lt;code&gt;outCreationData&lt;&#x2F;code&gt;, &lt;code&gt;creationHash&lt;&#x2F;code&gt;,
&lt;code&gt;creationTicket&lt;&#x2F;code&gt;, and &lt;code&gt;outName&lt;&#x2F;code&gt; depend on their internal size fields, but the
important pattern is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;After the 10‑byte header, &lt;code&gt;CreatePrimary&lt;&#x2F;code&gt; returns:
&lt;ol&gt;
&lt;li&gt;A transient handle for the new key.&lt;&#x2F;li&gt;
&lt;li&gt;A fully encoded &lt;code&gt;TPM2B_PUBLIC&lt;&#x2F;code&gt; structure.&lt;&#x2F;li&gt;
&lt;li&gt;Creation metadata and integrity (creation data, hash, ticket).&lt;&#x2F;li&gt;
&lt;li&gt;The object name.&lt;&#x2F;li&gt;
&lt;li&gt;Optional session response data.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is the “happy path” layout you want to see when debugging:
header → handle → public template → creation info → sessions.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;error-response-for-contrast&quot;&gt;Error Response for Contrast&lt;&#x2F;h5&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
            RESPONSE
==============================

TPM Response Tag (hex): 0x8002
- Response without sessions (minimal error response).

TPM Response Size (hex): 0x0000000a
- 0x0a = 10 bytes total.

TPM Response (hex):
80 01 00 00 00 0a 00 00 01 d5

Offset  Bytes              Meaning
------  -----              -------
00      80 01              tag = 0x8001 (no session area)
02      00 00 00 0a        length = 0x0000000a
06      00 00 01 d5        responseCode = 0x000001d5 (error)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;0x000001D5&lt;&#x2F;code&gt; is a non‑success &lt;code&gt;TPM_RC_*&lt;&#x2F;code&gt; code (the exact symbolic name depends
on the spec revision and context). The important contrast is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Successful commands:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tag = 0x8002&lt;&#x2F;code&gt; (with sessions),&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;responseCode = 0x00000000&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;full parameter area (handle, public, creation data, name, session).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Errors:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tag = 0x8002&lt;&#x2F;code&gt; (often similar to request),&lt;&#x2F;li&gt;
&lt;li&gt;non‑zero &lt;code&gt;responseCode&lt;&#x2F;code&gt;,&lt;&#x2F;li&gt;
&lt;li&gt;often only the 10‑byte header (tag, length, code), with no parameters.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3-3-tpm2-create-child-objects-under-a-parent&quot;&gt;3.3 &lt;code&gt;TPM2_Create&lt;&#x2F;code&gt;: Child Objects Under a Parent&lt;&#x2F;h3&gt;
&lt;p&gt;Once you have a primary key handle (e.g., &lt;code&gt;0x80000000&lt;&#x2F;code&gt;), you can call
&lt;code&gt;TPM2_Create&lt;&#x2F;code&gt; to create child objects under that parent.&lt;&#x2F;p&gt;
&lt;p&gt;The flow:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt; under &lt;code&gt;0x40000001&lt;&#x2F;code&gt; → returns &lt;code&gt;0x80000000&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TPM2_Create(parent = 0x80000000, template, inSensitive)&lt;&#x2F;code&gt; →
returns &lt;code&gt;outPrivate&lt;&#x2F;code&gt; and &lt;code&gt;outPublic&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TPM2_Load(parent = 0x80000000, outPrivate, outPublic)&lt;&#x2F;code&gt; →
returns a new transient handle (e.g., &lt;code&gt;0x80000001&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;High level:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parent handle&lt;&#x2F;strong&gt;: defines which hierarchy&#x2F;tree your object lives under.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;outPrivate&lt;&#x2F;strong&gt;: opaque blob encrypted under the parent.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;outPublic&lt;&#x2F;strong&gt;: the object’s public description.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Handle returned by Load&lt;&#x2F;strong&gt;: what you’ll use in subsequent commands (sign,
decrypt, etc.).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;tpm2-create-example-request&quot;&gt;TPM2_Create – Example Request&lt;&#x2F;h4&gt;
&lt;p&gt;High‑level description:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Parent handle: 0x80000000 (loaded parent key)&lt;&#x2F;li&gt;
&lt;li&gt;New object: 2048‑bit RSA key, sign usage&lt;&#x2F;li&gt;
&lt;li&gt;Auth&#x2F;session: simple password session with empty auth&lt;&#x2F;li&gt;
&lt;li&gt;Sensitive data: empty userAuth, no extra data&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
          REQUEST
==============================
TPM Command Tag (hex):    0x8002      ; TPM_ST_SESSIONS
TPM Command Length (hex): 0x0000004A  ; 74 bytes total (example)
TPM Command Code (hex):   0x00000153  ; TPM_CC_Create

TPM Command (hex):
80 02                         ; tag = TPM_ST_SESSIONS
00 00 00 4A                   ; commandSize = 0x4A (74 bytes)
00 00 01 53                   ; commandCode = TPM_CC_Create

80 00 00 00 00 01             ; parentHandle = 0x80000001 (example)

00 09                         ; authAreaSize = 9 bytes
40 00 00 09                   ; sessionHandle = TPM_RS_PW (password session)
00                            ; nonceSize = 0
00                            ; sessionAttributes = 0
00                            ; hmacSize = 0 (no password)

; inSensitive (TPM2B_SENSITIVE_CREATE)
00 00                         ; size of inSensitive (0, no auth&#x2F;user data)

; inPublic (TPM2B_PUBLIC)
00 1E                         ; size = 30 bytes (example, truncated)
00 01                         ; type = TPM_ALG_RSA
00 10                         ; nameAlg = TPM_ALG_SHA256
00 00                         ; objectAttributes (part1, truncated)
00 72                         ; objectAttributes (part2, truncated, e.g. sign, userWithAuth)
00 00                         ; authPolicy size = 0
00 01 00 01                   ; parameters: keyBits = 2048, exponent = 0x00010001
00 00                         ; unique (RSA modulus) size = 0 (TPM will generate)

; outsideInfo (TPM2B_DATA)
00 00                         ; size = 0

; creationPCR (TPML_PCR_SELECTION)
00 00 00 00                   ; count = 0 (no PCR selection)

TPM Command (binary – truncated, corresponding to hex above):
10000000 00000010 ...
...                           ; omitted: direct binary equivalent of the hex above
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;tpm2-create-example-successful-response&quot;&gt;TPM2_Create – Example Successful Response&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Tag: TPM_ST_SESSIONS&lt;&#x2F;li&gt;
&lt;li&gt;Response code: TPM_RC_SUCCESS&lt;&#x2F;li&gt;
&lt;li&gt;Returned:
&lt;ul&gt;
&lt;li&gt;outPrivate: the encrypted sensitive portion of the new object&lt;&#x2F;li&gt;
&lt;li&gt;outPublic: the public template of the created key&lt;&#x2F;li&gt;
&lt;li&gt;creationData &#x2F; creationHash &#x2F; creationTicket: data binding object to current state&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre&gt;&lt;code data-lang=&quot;text&quot;&gt;==============================
          RESPONSE
==============================
TPM Response Tag (hex):  0x8002        ; TPM_ST_SESSIONS
TPM Response Size (hex): 0x00000150    ; 336 bytes total (example)
TPM Response Code (hex):0x00000000     ; TPM_RC_SUCCESS

TPM Response (hex):
80 02                         ; tag
00 00 01 50                   ; responseSize
00 00 00 00                   ; responseCode = success

; outPrivate (TPM2B_PRIVATE) – truncated
00 60                         ; size = 0x60 (96 bytes, example)
AA AA AA ... AA               ; private buffer (sensitive, encrypted by TPM)

; outPublic (TPM2B_PUBLIC) – truncated
00 40                         ; size = 0x40 (64 bytes, example)
00 01                         ; type = TPM_ALG_RSA
00 10                         ; nameAlg = TPM_ALG_SHA256
00 00 00 72                   ; objectAttributes (truncated)
00 00                         ; authPolicy size = 0
00 01 00 01                   ; parameters: 2048‑bit, exponent 65537
00 20                         ; unique size = 32 bytes (truncated example)
BB BB BB ... BB               ; beginning of public modulus (truncated)

; creationData (TPM2B_CREATION_DATA) – truncated
00 30                         ; size = 0x30 (48 bytes, example)
CC CC CC ... CC               ; creation data

; creationHash (TPM2B_DIGEST) – truncated
00 20                         ; size = 0x20 (32 bytes, SHA‑256)
DD DD DD ... DD               ; hash of creation data

; creationTicket (TPMT_TK_CREATION) – truncated
80 01                         ; tag = TPM_ST_CREATION
00 00 00 00                   ; hierarchy = TPM_RH_OWNER (example)
00 20                         ; digest size
EE EE EE ... EE               ; ticket digest

TPM Response (binary – truncated, corresponding to hex above):
10000000 00000010 ...
...                           ; omitted: direct binary equivalent of the hex above
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;4-putting-it-all-together&quot;&gt;4. Putting It All Together&lt;&#x2F;h2&gt;
&lt;p&gt;From the TPM’s perspective, a “normal” provisioning flow looks roughly like:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reset &#x2F; power on&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_TPM_Init()&lt;&#x2F;code&gt; is asserted.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Startup&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;Firmware or your code sends &lt;code&gt;TPM2_Startup(SU_CLEAR)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;(Optional) Manufacturing &#x2F; provisioning&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;Vendor or platform runs &lt;code&gt;TPM2_Clear&lt;&#x2F;code&gt;, &lt;code&gt;TPM2_HierarchyChangeAuth&lt;&#x2F;code&gt;, creates
EK&#x2F;SRK, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Your application starts using the TPM&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;Query properties (&lt;code&gt;TPM2_GetCapability&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Create a primary key:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TPM2_CreatePrimary(parent = 0x40000001)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Use that key as a parent for children:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TPM2_Create&lt;&#x2F;code&gt;, &lt;code&gt;TPM2_Load&lt;&#x2F;code&gt;, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;5-a-concrete-example-signing-data-with-a-tpm&quot;&gt;5. A Concrete Example: Signing Data with a TPM&lt;&#x2F;h2&gt;
&lt;p&gt;Everything above can feel abstract until you actually use a TPM for something real.&lt;&#x2F;p&gt;
&lt;p&gt;To make this concrete, I’ve put together a small sample project that walks through a complete, minimal TPM signing flow using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tpm2-tss.readthedocs.io&#x2F;en&#x2F;latest&#x2F;index.html&quot;&gt;TSS&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;👉 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;DavisRayM&#x2F;tpm2-sign&quot;&gt;TPMSign&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-the-project-demonstrates&quot;&gt;What the Project Demonstrates&lt;&#x2F;h3&gt;
&lt;p&gt;The project shows how to:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Initialize and verify TPM state
&lt;ul&gt;
&lt;li&gt;Assumes the TPM has completed &lt;code&gt;_TPM_Init()&lt;&#x2F;code&gt; and &lt;code&gt;TPM2_Startup&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Verifies that a usable storage hierarchy exists.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Create (or reuse) a primary key
&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;TPM2_CreatePrimary&lt;&#x2F;code&gt; under the storage hierarchy (0x40000001).&lt;&#x2F;li&gt;
&lt;li&gt;Produces a transient handle in the 0x8000_0000 range.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Create a signing key under that primary
&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;TPM2_Create&lt;&#x2F;code&gt; + &lt;code&gt;TPM2_Load&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The private portion of the key never leaves the TPM.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Sign user-supplied data
&lt;ul&gt;
&lt;li&gt;Hashes the input message&lt;&#x2F;li&gt;
&lt;li&gt;Uses &lt;code&gt;TPM2_Sign&lt;&#x2F;code&gt; to generate a signature inside the TPM.&lt;&#x2F;li&gt;
&lt;li&gt;Returns a standard RSA signature that can be verified outside the TPM.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;At no point does the signing key’s private material leave the TPM — all
cryptographic operations are bound to TPM handles, exactly as described earlier
in this post.&lt;&#x2F;p&gt;
&lt;p&gt;If you understood the annotated command dumps in this post, the project should
feel familiar — it’s the same flow, just applied to a practical task&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>SuperStarTrek Testing</title>
          <pubDate>Fri, 19 Sep 2025 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/projects/superstartrek-no-show-123120232131/</link>
          <guid>https://davisraym.com/projects/superstartrek-no-show-123120232131/</guid>
          <description xml:base="https://davisraym.com/projects/superstartrek-no-show-123120232131/">&lt;p&gt;Collaborative project focused on creating thorough automated tests (unit, UI, mutation) and measuring coverage for an existing game codebase.&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>Cryo: Part 1</title>
          <pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/projects/cryo-01/</link>
          <guid>https://davisraym.com/projects/cryo-01/</guid>
          <description xml:base="https://davisraym.com/projects/cryo-01/">&lt;p&gt;&lt;em&gt;What does it really take to build a database from scratch?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>Kaznet</title>
          <pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/projects/kaznet/</link>
          <guid>https://davisraym.com/projects/kaznet/</guid>
          <description xml:base="https://davisraym.com/projects/kaznet/">&lt;p&gt;An open-source, micro-tasking platform for remote locations.&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>Steward</title>
          <pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/projects/stwrd-no-show-1231209231/</link>
          <guid>https://davisraym.com/projects/stwrd-no-show-1231209231/</guid>
          <description xml:base="https://davisraym.com/projects/stwrd-no-show-1231209231/">&lt;p&gt;Steward simplifies the management of dotfiles and configurations.&lt;&#x2F;p&gt;</description>
      </item>
      <item>
          <title>TicTacToe</title>
          <pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate>
          <author>Davis Muro</author>
          <link>https://davisraym.com/projects/tictactoe-no-show-123120232131/</link>
          <guid>https://davisraym.com/projects/tictactoe-no-show-123120232131/</guid>
          <description xml:base="https://davisraym.com/projects/tictactoe-no-show-123120232131/">&lt;p&gt;Terminal based Tic-Tac-Toe against AI Opponent using Minimax.&lt;&#x2F;p&gt;</description>
      </item>
    </channel>
</rss>
