Sealing and NVRAM¶
A TPM 2.0 can act as a secure vault. This page covers sealing secrets to a key or to PCR values, storing keys and data in TPM non-volatile memory (NVRAM), and the secure boot root of trust example built on both. All examples are built with the rest of the wolfTPM examples and run from the root of the wolfTPM source tree.
Seal and unseal overview¶
TPM 2.0 can protect secrets using a standard Seal/Unseal procedure. A seal can be created using a TPM 2.0 key or against a set of PCR values.
Note
Secret data sealed in a key is limited to a maximum size of 128 bytes.
The simplest pair of examples is seal/seal and seal/unseal. Demo usage is shown when they are run without parameters.
Sealing data into a TPM 2.0 key¶
The seal example stores data securely in a newly generated TPM 2.0 key. Only when this key is loaded into the TPM can the secret data be read back.
Example output from sealing and unsealing a secret message:
$ ./examples/seal/seal keyblob.bin mySecretMessage
TPM2.0 Simple Seal example
Key Blob: keyblob.bin
Use Parameter Encryption: NULL
Loading SRK: Storage 0x81000200 (282 bytes)
Sealing the user secret into a new TPM key
Created new TPM seal key (pub 46, priv 141 bytes)
Wrote 193 bytes to keyblob.bin
Key Public Blob 46
Key Private Blob 141
$ ./examples/keygen/keyload -persistent
TPM2.0 Key load example
Key Blob: keyblob.bin
Use Parameter Encryption: NULL
Loading SRK: Storage 0x81000200 (282 bytes)
Reading 193 bytes from keyblob.bin
Reading the private part of the key
Loaded key to 0x80000001
Key was made persistent at 0x81000202
$ ./examples/seal/unseal message.raw
Example how to unseal data using TPM2.0
wolfTPM2_Init: success
Unsealing succeeded
Stored unsealed data to file = message.raw
$ cat message.raw
mySecretMessage
After a successful unsealing, the data is stored into a new file. If no filename is provided, the unseal tool stores the data in unseal.bin.
Sealing to PCRs with a signed policy¶
To seal a secret to PCRs without the brittleness of a fixed PCR value, an external key signs the expected PCR state. See Secure boot root of trust below, and the seal_policy_auth example in the next section.
Seal examples¶
The examples/seal/ directory contains examples of TPM 2.0 seal and unseal operations with different authorization policies, listed from simplest to most flexible.
seal and unseal (password policy)¶
The simplest seal and unseal, using a password-based authorization policy.
./examples/seal/seal keyblob.bin mySecretData
./examples/seal/unseal output.bin keyblob.bin
seal_pcr (PCR-only policy)¶
Seals a secret bound to specific PCR values. The secret can only be unsealed when the PCR values match what was measured at seal time. No password or signing key is required.
Use case: Static Root of Trust, binding secrets to a specific boot state.
# Seal and unseal in one step
./examples/seal/seal_pcr -both -pcr=16 -secretstr="MySecret"
# Separate seal/unseal (for example, seal on first boot, unseal on later boots)
./examples/seal/seal_pcr -seal -pcr=16 -secretstr="MySecret"
./examples/seal/seal_pcr -unseal -pcr=16
# With parameter encryption
./examples/seal/seal_pcr -both -pcr=16 -xor -secretstr="MySecret"
./examples/seal/seal_pcr -both -pcr=16 -aes -secretstr="MySecret"
# Custom sealed blob filename
./examples/seal/seal_pcr -seal -sealblob=myblob.bin -secretstr="MySecret"
./examples/seal/seal_pcr -unseal -sealblob=myblob.bin
seal_policy_auth (PolicyAuthorize and PCR)¶
Seals a secret using PolicyAuthorize with a TPM-resident signing key and a PCR policy. The signing key can re-authorize the policy for new PCR values, so secrets can survive authorized changes such as OS updates.
Use case: flexible measured boot with authorized policy updates.
Note
authkey.bin and sealblob.bin must be kept together. If the signing key is regenerated, the sealed blob can no longer be unsealed.
# ECC signing key (default)
./examples/seal/seal_policy_auth -both -ecc -pcr=16 -secretstr="MySecret"
# RSA signing key
./examples/seal/seal_policy_auth -both -rsa -pcr=16 -secretstr="MySecret"
# Separate seal/unseal
./examples/seal/seal_policy_auth -seal -ecc -pcr=16 -secretstr="MySecret"
./examples/seal/seal_policy_auth -unseal -ecc -pcr=16
# With parameter encryption
./examples/seal/seal_policy_auth -both -ecc -pcr=16 -xor -secretstr="MySecret"
./examples/seal/seal_policy_auth -both -rsa -pcr=16 -aes -secretstr="MySecret"
seal_nv (NV storage and PCR policy)¶
Stores a secret in TPM NV (non-volatile) memory protected by a PCR policy. Unlike file-based sealed blobs, the secret lives entirely inside the TPM. The program is located at examples/nvram/seal_nv.
Use case: secrets that must persist in TPM hardware without external files.
# Store, read, delete lifecycle
./examples/nvram/seal_nv -store -pcr=16 -secretstr="MySecret"
./examples/nvram/seal_nv -read -pcr=16
./examples/nvram/seal_nv -delete
# Custom NV index
./examples/nvram/seal_nv -store -pcr=16 -nvindex=0x01800204 -secretstr="MySecret"
./examples/nvram/seal_nv -read -pcr=16 -nvindex=0x01800204
./examples/nvram/seal_nv -delete -nvindex=0x01800204
Testing¶
seal_test.sh runs 28 tests across all three seal example groups:
bash examples/seal/seal_test.sh
The tests include positive cases (seal and unseal lifecycle, secret verification), negative cases (PCR mismatch, missing auth key), parameter encryption variants (XOR, AES), and custom filenames and NV indices. Output uses colored PASS, FAIL and SKIP markers with a summary. Verbose output is saved to seal_test.log.
| Variable | Default | Description |
|---|---|---|
WOLFCRYPT_ENABLE |
1 | wolfCrypt support compiled in |
WOLFCRYPT_DEFAULT |
0 | Using the default (reduced) wolfCrypt config |
WOLFCRYPT_ECC |
1 | ECC support available |
WOLFCRYPT_RSA |
1 | RSA support available |
The seal examples are also tested as part of examples/run_examples.sh, which runs during make check.
Policy comparison¶
| Feature | seal (password) | seal_pcr | seal_policy_auth | seal_nv |
|---|---|---|---|---|
| Authorization | Password | PCR values | Signing key + PCR | PCR values |
| Complexity | Low | Low | High | Medium |
| Survives PCR change | N/A | No | Yes (with auth key) | No |
| Storage | File | File | File (blob + key) | TPM NV |
| Parameter Encryption | Yes | Yes | Yes | Yes |
Storing keys in NVRAM¶
These examples show how to use the TPM as a secure vault for keys. There are two programs: one stores a TPM key into the TPM's NVRAM, and the other extracts the key from NVRAM. Both can use parameter encryption to protect against MITM attacks. The NV location is protected with a password authorization that is passed in encrypted form when -aes is given on the command line.
Before running the examples, make sure a keyblob.bin was generated using the keygen tool. The key can be of any type: RSA, ECC or symmetric. The example stores the private and public part. For a symmetric key the public part is metadata from the TPM.
Typical output for storing and then reading an RSA key with parameter encryption enabled:
$ ./examples/nvram/store -aes
Parameter Encryption: Enabled (AES CFB).
TPM2_StartAuthSession: sessionHandle 0x2000000
Reading 840 bytes from keyblob.bin
Storing key at TPM NV index 0x1800202 with password protection
Public part = 616 bytes
NV write of public part succeeded
Private part = 222 bytes
Stored 2-byte size marker before the private part
NV write of private part succeeded
$ ./examples/nvram/read -aes
Parameter Encryption: Enabled (AES CFB).
TPM2_StartAuthSession: sessionHandle 0x2000000
Trying to read 616 bytes of public key part from NV
Successfully read public key part from NV
Trying to read size marker of the private key part from NV
Successfully read size marker from NV
Trying to read 222 bytes of private key part from NV
Successfully read private key part from NV
Extraction of key from NVRAM at index 0x1800202 succeeded
Loading SRK: Storage 0x81000200 (282 bytes)
Trying to load the key extracted from NVRAM
Loaded key to 0x80000001
The read example tries to load the extracted key if both the public and private part were stored in NVRAM. The -aes switch turns on parameter encryption.
The examples can work with partial key material, private or public only, using the -priv and -pub options. Typical output of storing only the private part of an RSA key pair without parameter encryption:
$ ./examples/nvram/store -priv
Parameter Encryption: Not enabled (try -aes or -xor).
Reading 506 bytes from keyblob.bin
Reading the private part of the key
Storing key at TPM NV index 0x1800202 with password protection
Private part = 222 bytes
Stored 2-byte size marker before the private part
NV write of private part succeeded
$ ./examples/nvram/read -priv
Parameter Encryption: Not enabled (try -aes or -xor).
Trying to read size marker of the private key part from NV
Successfully read size marker from NV
Trying to read 222 bytes of private key part from NV
Successfully read private key part from NV
Extraction of key from NVRAM at index 0x1800202 succeeded
After a successful key extraction with read, the NV index is destroyed. To use read again, run store again first.
NVRAM programs¶
All programs are in examples/nvram/.
| Program | Purpose |
|---|---|
store.c |
Stores a TPM key (private part, public part, or both) into an NV index. |
read.c |
Reads a key back from NV, loads it, and can delete the NV index. |
counter.c |
Creates and increments an NV counter. |
extend.c |
NV extend example showing bus protection with a PolicyOR. |
policy_nv.c |
Stores data in NV and tests a TPM2_PolicyNV based authorization. |
seal_nv.c |
Stores a secret in NV protected by a PCR policy (see Seal examples). |
Secure boot root of trust¶
The examples/boot/ directory holds a TPM based root of trust design for secure boot, such as wolfBoot.
Secure boot ROT¶
The design for storing a public key based root of trust in the TPM:
- Use AES-CFB parameter encryption for all communication (salted and bound).
- Derive a password from unique device parameters and use it as the "auth" to load the NV (authenticate).
- The NV contains a hash of the public key (the hash matches the
.configsetting). - wolfBoot still has the public key internally and programs the TPM NV if it is not populated.
- The NV is locked and created under the platform hierarchy.
Example:
$ ./examples/boot/secure_rot -write=../wolfBoot/wolfboot_signing_public_key.der -lock
TPM2: Caps 0x00000000, Did 0x0000, Vid 0x0000, Rid 0x 0
TPM2_Startup pass
TPM2_SelfTest pass
NV Auth (32)
19 3f bf 0c bb 90 ca a1 40 96 a6 ee 8e fc 7c 3f | .?......@.....|?
c1 c2 7f 1d c3 e0 a2 5e c7 72 5a a1 94 76 63 53 | .......^.rZ..vcS
Parameter Encryption: Enabled. (AES CFB)
TPM2_StartAuthSession: handle 0x2000000, algorithm AES
TPM2_StartAuthSession: sessionHandle 0x2000000
Storing hash of public key file ../wolfBoot/wolfboot_signing_public_key.der to NV index 0x1400200 with password protection
Public Key Hash (32)
e3 29 f9 9e 56 93 6e 24 02 34 13 81 0f 7c 73 4d | .)..V.n$.4...|sM
8f 9d 63 b8 8f 43 39 7b e5 46 93 dd 77 58 77 29 | ..c..C9{.F..wXw)
TPM2_NV_ReadPublic: Sz 14, Idx 0x1400200, nameAlg 11, Attr 0x42072005, authPol 0, dataSz 32, name 34
TPM2_NV_DefineSpace: Auth 0x4000000c, Idx 0x1400200, Attribs 0x1107763205, Size 32
TPM2_NV_Write: Auth 0x1400200, Idx 0x1400200, Offset 0, Size 32
Wrote 32 bytes to NV 0x1400200
Reading NV 0x1400200 public key hash
TPM2_NV_ReadPublic: Sz 14, Idx 0x1400200, nameAlg 11, Attr 0x62072005, authPol 0, dataSz 32, name 34
TPM2_NV_Read: Auth 0x1400200, Idx 0x1400200, Offset 0, Size 32
Read Public Key Hash (32)
e3 29 f9 9e 56 93 6e 24 02 34 13 81 0f 7c 73 4d | .)..V.n$.4...|sM
8f 9d 63 b8 8f 43 39 7b e5 46 93 dd 77 58 77 29 | ..c..C9{.F..wXw)
Locking NV index 0x1400200
NV 0x1400200 locked
TPM2_FlushContext: Closed handle 0x2000000
Secure boot encryption key storage¶
To seal a secret to PCRs without the brittleness issue, an external key signs the state of the PCRs.
| Tool | Purpose |
|---|---|
./examples/pcr/policy_sign |
Signs a digest for a PCR policy. Outputs the signature and, with -outpolicy, the policy authorization digest for the public key. |
./examples/boot/secret_seal |
Seals a secret using the authorization policy digest for the public key. If no secret is provided, a random value is generated and sealed. |
./examples/boot/secret_unseal |
Unseals a secret using the signed authorization policy and the public key. |
Create a signed PCR policy:
# Extend "aaa" to test PCR 16
echo aaa > aaa.bin
./examples/pcr/reset 16
./examples/pcr/extend 16 aaa.bin
# RSA sign this PCR (result to pcrsig.bin), also creates policyauth.bin from the public key
./examples/pcr/policy_sign -pcr=16 -rsa -key=./certs/example-rsa2048-key.der -out=pcrsig.bin -outpolicy=policyauth.bin
# OR
# ECC sign
./examples/pcr/policy_sign -pcr=16 -ecc -key=./certs/example-ecc256-key.der -out=pcrsig.bin -outpolicy=policyauth.bin
Create a sealed secret using that signed policy, based on the public key:
# Create a keyed hash sealed object using the policy authorization for the public key
./examples/boot/secret_seal -rsa -policy=policyauth.bin -out=sealblob.bin
./examples/boot/secret_seal -ecc -policy=policyauth.bin -out=sealblob.bin
# OR
# Provide the public key for policy authorization (instead of -policy=)
./examples/boot/secret_seal -rsa -publickey=./certs/example-rsa2048-key-pub.der -out=sealblob.bin
./examples/boot/secret_seal -ecc -publickey=./certs/example-ecc256-key-pub.der -out=sealblob.bin
Unseal:
# Unseal using the public key
./examples/boot/secret_unseal -pcr=16 -pcrsig=pcrsig.bin -rsa -publickey=./certs/example-rsa2048-key-pub.der -seal=sealblob.bin
./examples/boot/secret_unseal -pcr=16 -pcrsig=pcrsig.bin -ecc -publickey=./certs/example-ecc256-key-pub.der -seal=sealblob.bin