Skip to content

Commit

Permalink
Support for sealing/unseal a secret based on an externally signed PCR…
Browse files Browse the repository at this point in the history
… policy.

* Added new `WOLFBOOT_TPM_SEAL` and `WOLFBOOT_TPM_SEAL_NV_BASE` config options.
* Added new `tools/tpm/policy_create` tool for assisting with creation of a policy digest. The sign keytool `--policy=file` signs the policy.
* Added new `WOLFBOOT_TPM_VERIFY` option to enable offloading of the asymmetric verification to the TPM. By default wolfCrypt will be used.
* Added example seal/unseal to update_flash for ARCH_SIM.
* Renamed `WOLFBOOT_TPM_KEYSTORE_NV_INDEX` to `WOLFBOOT_TPM_KEYSTORE_NV_BASE` to support multiple public keys.
* Refactored most TPM code into tpm.c.
* Refactored the keystore ROT to use new `wolfBoot_check_rot` API.
* Refactored the sign keytool to have a sign_digest function to allow signing firmware and policy for sealing/unsealing.
* Fix for make distclean && make using the wrong key tools.
  • Loading branch information
dgarske committed Sep 7, 2023
1 parent 938e6c2 commit 28f9ec5
Show file tree
Hide file tree
Showing 38 changed files with 2,099 additions and 722 deletions.
15 changes: 13 additions & 2 deletions .github/workflows/test-build-sim-tpm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ jobs:
run: |
make -C tools/keytools && make -C tools/bin-assemble
- name: Build wolfboot
# needed for tpm tools
- name: Build keystore.c
run: |
make ${{inputs.make-args}} WOLFBOOT_TPM_KEYSTORE_AUTH="${{inputs.authstr}}"
make keys ${{inputs.make-args}}
- name: Build TPM tools
run: |
Expand All @@ -65,6 +66,16 @@ jobs:
run: |
./tools/tpm/rot -write ${{inputs.rot-args}} -auth="${{inputs.authstr}}"
- name: Create a PCR Policy
run: |
echo aaa > aaa.bin
./tools/tpm/pcr_extend 0 aaa.bin
./tools/tpm/policy_create -pcr=0 -out=policy.bin
- name: Build wolfboot
run: |
make ${{inputs.make-args}} WOLFBOOT_TPM_KEYSTORE_AUTH="${{inputs.authstr}}"
- name: Run wolfBoot
run: |
./wolfboot.elf get_version
27 changes: 27 additions & 0 deletions .github/workflows/test-tpm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
config-file: ./config/examples/sim-tpm.config
make-args: SIGN=RSA2048 HASH=SHA256


sim_tpm_measured_ecc256:
uses: ./.github/workflows/test-build-sim-tpm.yml
with:
Expand Down Expand Up @@ -82,3 +83,29 @@ jobs:
config-file: ./config/examples/sim-tpm-keystore.config
make-args: SIGN=RSA2048 HASH=SHA256
authstr: TestAuth


sim_tpm_seal_ecc256:
uses: ./.github/workflows/test-build-sim-tpm.yml
with:
arch: host
config-file: ./config/examples/sim-tpm-seal.config
make-args: SIGN=ECC256 HASH=SHA256 POLICY_FILE=policy.bin
authstr: TestAuth

sim_tpm_seal_ecc384:
uses: ./.github/workflows/test-build-sim-tpm.yml
with:
arch: host
config-file: ./config/examples/sim-tpm-seal.config
make-args: SIGN=ECC384 HASH=SHA384 POLICY_FILE=policy.bin
rot-args: -sha384
authstr: TestAuth

sim_tpm_seal_rsa2048:
uses: ./.github/workflows/test-build-sim-tpm.yml
with:
arch: host
config-file: ./config/examples/sim-tpm-seal.config
make-args: SIGN=RSA2048 HASH=SHA256 POLICY_FILE=policy.bin
authstr: TestAuth
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ tools/unit-tests/unit-parser
tools/bin-assemble/bin-assemble
tools/elf-parser/elf-parser
tools/tpm/rot
tools/tpm/pcr_read
tools/tpm/pcr_reset
tools/tpm/pcr_extend
tools/tpm/policy_create
config/*.ld

# Generated confiuguration file
Expand Down
3 changes: 2 additions & 1 deletion IDE/XilinxSDK/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Note: If not using Position Independent Code (PIC) the linker script `ldscript.l
## Signing Example

```sh
python3 ./tools/keytools/sign.py --rsa4096 --sha3 ../helloworld/Debug/helloworld.elf ./rsa4096.der 1
make keytools
./tools/keytools/sign --rsa4096 --sha3 ../helloworld/Debug/helloworld.elf ./rsa4096.der 1
```

## Bootgen
Expand Down
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,8 @@ include tools/test-enc.mk
include tools/test-delta.mk
include tools/test-renode.mk

PYTHON?=python3
keytools_check: keytools FORCE


$(PRIVATE_KEY):
$(Q)$(MAKE) keytools_check
$(Q)(test $(SIGN) = NONE) || ("$(KEYGEN_TOOL)" $(KEYGEN_OPTIONS) -g $(PRIVATE_KEY)) || true
Expand Down
2 changes: 1 addition & 1 deletion config/examples/sim-tpm-keystore.config
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ WOLFBOOT_FIXED_PARTITIONS=1

# Use NV for TPM based Root of Trust
WOLFBOOT_TPM_KEYSTORE?=1
WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=0x01400200
WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01400200
#WOLFBOOT_TPM_KEYSTORE_AUTH?=TestAuth

# TPM Logging
Expand Down
35 changes: 35 additions & 0 deletions config/examples/sim-tpm-seal.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ARCH=sim
TARGET=sim
SIGN?=ECC256
HASH?=SHA256
SPI_FLASH=0
DEBUG=0
WOLFTPM=1

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
# if on external flash, it should be multiple of system page size
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1

# Use NV for TPM based Root of Trust
WOLFBOOT_TPM_KEYSTORE?=1
WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01400200
#WOLFBOOT_TPM_KEYSTORE_AUTH?=TestAuth

# Measured boot at test PCR index 16
MEASURED_BOOT?=1
MEASURED_PCR_A?=16

# Sealing a secret into TPM based on external PCR policy signed by the sign tool
WOLFBOOT_TPM_SEAL?=1
WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300

# TPM Logging
#CFLAGS_EXTRA+=-DDEBUG_WOLFTPM
#CFLAGS_EXTRA+=-DWOLFTPM_DEBUG_VERBOSE
2 changes: 2 additions & 0 deletions config/examples/sim-tpm.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ HASH?=SHA256
SPI_FLASH=0
DEBUG=0
WOLFTPM=1
# enable offloading of asymmetric verify to TPM
WOLFBOOT_TPM_VERIFY?=1

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
Expand Down
2 changes: 1 addition & 1 deletion config/examples/x86_fsp_qemu.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WOLFTPM=0

# TPM Keystore options
#WOLFBOOT_TPM_KEYSTORE?=1
#WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=0x01800200
#WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01800200
#WOLFBOOT_TPM_POLICY_NV_INDEX?=0x01800201

# 4gb - 8mb
Expand Down
2 changes: 1 addition & 1 deletion config/examples/x86_fsp_qemu_stage1_auth.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WOLFTPM=0

# TPM Keystore options
#WOLFBOOT_TPM_KEYSTORE?=1
#WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=0x01800200
#WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01800200
#WOLFBOOT_TPM_POLICY_NV_INDEX?=0x01800201

# 4gb - 8mb
Expand Down
2 changes: 1 addition & 1 deletion config/examples/x86_fsp_qemu_tpm.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WOLFTPM=1

# TPM Keystore options
#WOLFBOOT_TPM_KEYSTORE?=1
#WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=0x01800200
#WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01800200
#WOLFBOOT_TPM_POLICY_NV_INDEX?=0x01800201

# 4gb - 8mb
Expand Down
2 changes: 1 addition & 1 deletion config/examples/x86_fsp_qemu_tpm_keystore.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WOLFTPM=1

# TPM Keystore options
WOLFBOOT_TPM_KEYSTORE?=1
WOLFBOOT_TPM_KEYSTORE_NV_INDEX?=0x01800200
WOLFBOOT_TPM_KEYSTORE_NV_BASE?=0x01800200
WOLFBOOT_TPM_POLICY_NV_INDEX?=0x01800201

# 4gb - 8mb
Expand Down
15 changes: 12 additions & 3 deletions docs/Signing.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ be used for the key, 16 for the initialization of the IV.
SHAREDKEY.BIN is expected to be exactly 48 bytes in size, of which 32 will
be used for the key, 16 for the initialization of the IV.


#### Delta updates (incremental updates from a known version)

An incremental update is created using the sign tool when the following option
Expand All @@ -167,6 +166,16 @@ is provided:
`BASE_SIGNED_IMG.BIN` and the new image signed starting from `IMAGE.BIN`. The
result is stored in a file ending in `_signed_diff.bin`.

#### Policy signing (for sealing/unsealing with a TPM)

Provides a PCR mask and digest to be signed and included in the header. The signing key is used to sign the digest.

* `--policy policy.bin`: This argument is multi-purpose.
By default the file should contain a 4-byte PCR mask and SHA2-256 PCR digest to be signed.
If using `--manual-sign` then the file should contain the 4-byte PCR mask and signature.
The PCR mask and signature will be included in the `HDR_POLICY_SIGNATURE` header tag.
Note: This may require increasing the `IMAGE_HEADER_SIZE` as two signatures will be stored in the header.

#### Three-steps signing using external provisioning tools

If the private key is not accessible, while it's possible to sign payloads using
Expand Down Expand Up @@ -222,13 +231,13 @@ openssl rsa -inform DER -outform DER -in my_key.der -out rsa2048_pub.der -pubout
./tools/keytools/keygen --rsa2048 -i rsa2048_pub.der

# Generate Hash to Sign
./tools/keytools/sign --rsa2048 --sha-only --sha256 test-app/image.bin rsa2048_pub.der 1
./tools/keytools/sign --rsa2048 --sha-only --sha256 test-app/image.bin rsa2048_pub.der 1

# Sign hash Example (here is where you would use an HSM)
openssl pkeyutl -sign -keyform der -inkey my_key.der -in test-app/image_v1_digest.bin > test-app/image_v1.sig

# Generate final signed binary
./tools/keytools/sign --rsa2048 --sha256 --manual-sign test-app/image.bin rsa2048_pub.der 1 test-app/image_v1.sig
./tools/keytools/sign --rsa2048 --sha256 --manual-sign test-app/image.bin rsa2048_pub.der 1 test-app/image_v1.sig

# Combine into factory image (0xc0000 is the WOLFBOOT_PARTITION_BOOT_ADDRESS)
tools/bin-assemble/bin-assemble factory.bin 0x0 wolfboot.bin \
Expand Down
143 changes: 137 additions & 6 deletions docs/TPM.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ In wolfBoot we support TPM based root of trust, sealing/unsealing, cryptographic

| Config Option | Preprocessor Macro | Description |
| ------------- | ------------------ | ----------------------------------- |
| `WOLFTPM=1` | `WOLFBOOT_TPM` | Enables wolfTPM support and cryptographic offloading for RSA2048 and ECC256/384 |
| `WOLFTPM=1` | `WOLFBOOT_TPM` | Enables wolfTPM support |
| `WOLFBOOT_TPM_VERIFY=1` | `WOLFBOOT_TPM_VERIFY` | Enables cryptographic offloading for RSA2048 and ECC256/384 to the TPM. |
| `WOLFBOOT_TPM_KEYSTORE=1` | `WOLFBOOT_TPM_KEYSTORE` | Enables TPM based root of trust. NV Index must store a hash of the trusted public key. |
| `WOLFBOOT_TPM_KEYSTORE_NV_INDEX=0x` | `WOLFBOOT_TPM_KEYSTORE_NV_INDEX=0x` | NV index in platform range 0x1400000 - 0x17FFFFF |
| `WOLFBOOT_TPM_KEYSTORE_NV_BASE=0x` | `WOLFBOOT_TPM_KEYSTORE_NV_BASE=0x` | NV index in platform range 0x1400000 - 0x17FFFFF. |
| `MEASURED_BOOT=1` | `WOLFBOOT_MEASURED_BOOT` | Enable measured boot. Extend PCR with wolfBoot hash. |
| `MEASURED_PCR_A=16` | `WOLFBOOT_MEASURED_PCR_A=16` | The PCR index to use. See [docs/measured_boot.md](/docs/measured_boot.md) |
| `MEASURED_PCR_A=16` | `WOLFBOOT_MEASURED_PCR_A=16` | The PCR index to use. See [docs/measured_boot.md](/docs/measured_boot.md). |
| `WOLFBOOT_TPM_SEAL=1` | `WOLFBOOT_TPM_SEAL` | Enables support for sealing/unsealing based on PCR policy signed externally. |
| `WOLFBOOT_TPM_SEAL_NV_BASE=0x01400300` | `WOLFBOOT_TPM_SEAL_NV_BASE` | To override the default sealed blob storage location in the platform hierarchy. |

## Root of Trust (ROT)

Expand All @@ -20,12 +23,140 @@ The design uses a platform NV handle that has been locked. The NV stores a hash

## Cryptographic offloading

The RSA2048 and ECC256/384 bit verification can be offloaded to a TPM for code size reduction or performance improvement.
The RSA2048 and ECC256/384 bit verification can be offloaded to a TPM for code size reduction or performance improvement. Enabled using `WOLFBOOT_TPM_VERIFY`

## Measured Boot

The wolfBoot image is hashed and extended to the indicated PCR. This can be used later in the application to prove the boot process was not tampered with.
The wolfBoot image is hashed and extended to the indicated PCR. This can be used later in the application to prove the boot process was not tampered with. Enabled with `WOLFBOOT_MEASURED_BOOT` and exposes API `wolfBoot_tpm2_extend`.

## Sealing and Unsealing a secret

API's for this will be available soon.
See the wolfTPM Sealing/Unsealing example [here](https://github.com/wolfSSL/wolfTPM/tree/secret_seal/examples/boot#secure-boot-encryption-key-storage)

Known PCR values must be signed to seal/unseal a secret. The signature for the authorization policy resides in the signed header using the `--policy` argument.
If a signed policy is not in the header then a value cannot be sealed. Instead the PCR(s) and a digest to sign will be printed for use with the sign tool.

This exposes two new wolfBoot API's for sealing and unsealing data with blob stored to NV index:
```c
int wolfBoot_seal(struct wolfBoot_image* img, int index, const uint8_t* secret, int secret_sz);
int wolfBoot_unseal(struct wolfBoot_image* img, int index, uint8_t* secret, int* secret_sz);
```
By default this index will be based on an NV Index at `(0x01400300 + index)`.
The default NV base can be overridden with `WOLFBOOT_TPM_SEAL_NV_BASE`.
### Testing seal/unseal with simulator
```sh
cp config/examples/sim-tpm-seal.config .config
make keytools
make tpmtools
echo aaa > aaa.bin
./tools/tpm/pcr_extend 0 aaa.bin
./tools/tpm/policy_create -pcr=0
# if ROT enabled
./tools/tpm/rot -write
make clean && make POLICY_FILE=policy.bin
./wolfboot.elf get_version
Simulator assigned ./internal_flash.dd to base 0x103797000
Mfg IBM (0), Vendor SW TPM, Fw 8217.4131 (0x163636), FIPS 140-2 1, CC-EAL4 0
Unlocking disk...
Boot partition: 0x103817000
Image size 54400
Sealing 32 bytes
11c6ac0ec972ae567c541750c6ecccd426f131dad3eeca5e6540d901d9f0c336
Unsealed 32 bytes
11c6ac0ec972ae567c541750c6ecccd426f131dad3eeca5e6540d901d9f0c336
Boot partition: 0x103817000
Image size 54400
TPM Root of Trust valid (id 0)
Simulator assigned ./internal_flash.dd to base 0x103962000
1
```

### Testing seal/unseal on actual hardware

1) Get the actual PCR digest for policy.
2) Sign policy and include in firmware image header.


#### Getting PCR values

If no signed policy exists, then the seal function will generate and display the active PCR's, PCR digest and policy digest (to sign)

```sh
% make tpmtools
% ./tools/tpm/rot -write
% ./tools/tpm/pcr_reset 16
% ./wolfboot.elf get_version
Simulator assigned ./internal_flash.dd to base 0x101a64000
Mfg IBM (0), Vendor SW TPM, Fw 8217.4131 (0x163636), FIPS 140-2 1, CC-EAL4 0
Boot partition: 0x101ae4000
Image size 57192
Policy header not found!
Generating policy based on active PCR's!
Getting active PCR's (0-16)
PCR 16 (counter 20)
8f7ac1d5a5eac58a2305ca459f27c35705a9212c0fb2a9088b1df761f3d5f842
Found 1 active PCR's (mask 0x00010000)
PCR Digest (32 bytes):
f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c
PCR Mask (0x00010000) and PCR Policy Digest (36 bytes):
0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec
Use this policy with the sign tool (--policy arg) or POLICY_FILE config
Image policy signature missing!
Boot partition: 0x101ae4000
Image size 57192
TPM Root of Trust valid (id 0)
Simulator assigned ./internal_flash.dd to base 0x101c2f000
1
```
The `0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec` above can be directly used by the keytool. The
`echo "0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec" | xxd -r -p > policy.bin`
OR use the `tools/tpm/policy_create` tool to generate a digest to be signed. The used PCR(s) must be set using "-pcr=#". The PCR digest can be supplied using "-pcrdigest=" or if not supplied will be read from the TPM directly.
```sh
% ./tools/tpm/policy_create -pcr=16 -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -out=policy.bin
# OR
% ./tools/tpm/policy_create -pcrmask=0x00010000 -pcrdigest=f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c -out=policy.bin
Policy Create Tool
PCR Index(s) (SHA256): 16 (mask 0x00010000)
PCR Digest (32 bytes):
f84085631f85333ad0338b06c82f16888b7923abaccffb881d5416e389be256c
PCR Mask (0x00010000) and PCR Policy Digest (36 bytes):
0000010034ba061436aba2e9a167a1ee46af4a9578a8c6b9f71fdece21607a0cb40468ec
Wrote 36 bytes to policy.bin
```
#### Signing Policy
Building firmware with the policy digest to sign:
```sh
% make POLICY_FILE=policy.bin
```
OR manually using:
```sh
% ./tools/keytools/sign --ecc256 --policy policy.bin test-app/image.elf wolfboot_signing_private_key.der 1
wolfBoot KeyTools (Compiled C version)
wolfBoot version 1100000
Update type: Firmware
Input image: test-app/image.elf
Selected cipher: ECC256
Selected hash : SHA256
Public key: wolfboot_signing_private_key.der
Output image: test-app/image_v1_signed.bin
Target partition id : 1
image header size calculated at runtime (256 bytes)
Calculating SHA256 digest...
Signing the digest...
Opening policy file policy.bin
Signing the policy digest...
Output image(s) successfully created.
```
Loading

0 comments on commit 28f9ec5

Please sign in to comment.