diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index c7cc5891..e0888b50 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -34,4 +34,4 @@ jobs: run: | codespell --count \ --skip '.git,./IDE,./certs,./m4,*.der,*.pem,*prebuilt_bindings.rs' \ - --ignore-words-list 'inh,inout,keypair,nd,parm,rcv,ser,loadIn,importIn,certifyIn,bu,fo,daa,pris,hsi,fram,hart,cna' + --ignore-words-list 'inh,inout,keypair,nd,parm,rcv,ser,loadIn,importIn,certifyIn,bu,fo,daa,pris,hsi,fram,hart,cna,challener' diff --git a/.github/workflows/docs-site.yml b/.github/workflows/docs-site.yml new file mode 100644 index 00000000..9289e8d7 --- /dev/null +++ b/.github/workflows/docs-site.yml @@ -0,0 +1,93 @@ +name: Build manual with documentation tooling + +on: + pull_request: + paths: &doc_paths + - 'docs/**' + - 'mkdocs.yml' + - 'mkdocs-ja.yml' + - 'tools/docs_manual.py' + - 'tools/docs-manual/**' + - 'docker/docs/**' + - '.github/workflows/docs-site.yml' + - 'README.md' + - 'docs/Doxyfile' + - 'examples/README.md' + - 'examples/pcr/README.md' + - 'examples/attestation/README.md' + - 'examples/boot/README.md' + - 'hal/README.md' + - 'hal/tpm_io.h' + - 'wolftpm/tpm2.h' + - 'wolftpm/tpm2_wrap.h' + - 'wolftpm/tpm2_crypto.h' + - 'wolftpm/fwtpm/*.h' + push: + branches: [master] + paths: *doc_paths + workflow_dispatch: + +permissions: + contents: read + packages: read + +jobs: + build: + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - name: Select documentation revision + id: documentation + run: echo "sha=$(cat tools/docs-manual/documentation-rev)" >> "$GITHUB_OUTPUT" + - uses: actions/checkout@v4 + with: + repository: wolfSSL/documentation + ref: ${{ steps.documentation.outputs.sha }} + path: build/documentation + submodules: recursive + persist-credentials: false + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Pull documentation builder + run: | + set -euo pipefail + image_sha=$(sha256sum docker/docs/Dockerfile docker/docs/requirements.txt | sha256sum | cut -c1-16) + image="ghcr.io/wolfssl/wolftpm-docs:sha-$image_sha" + if ! docker pull "$image"; then + docker build --pull -t "$image" docker/docs + fi + echo "DOCS_IMAGE=$image" >> "$GITHUB_ENV" + - name: Build and validate HTML and PDF (English and Japanese) + run: | + tools/check-docs-no-internal-links.sh --selftest + tools/check-docs-no-internal-links.sh + docker run --rm --user "$(id -u):$(id -g)" --env HOME=/tmp \ + --mount "type=bind,source=$GITHUB_WORKSPACE,target=/work/wolfTPM" \ + --workdir /work/wolfTPM "$DOCS_IMAGE" \ + sh -c ' + set -e + python3 tools/docs_manual.py build --documentation-root /work/wolfTPM/build/documentation --source-root /work/wolfTPM --target all + test -s build/documentation/wolfTPM/html/index.html + test -s build/documentation/wolfTPM/wolfTPM-Manual.pdf + cp -r build/documentation/wolfTPM/html build/documentation/wolfTPM/html-en + python3 tools/docs_manual.py build --documentation-root /work/wolfTPM/build/documentation --source-root /work/wolfTPM --lang ja --target all + test -s build/documentation/wolfTPM/html/index.html + test -s build/documentation/wolfTPM/wolfTPM-Manual-jp.pdf + cp -r build/documentation/wolfTPM/html build/documentation/wolfTPM/html-ja + ' + test -s build/documentation/wolfTPM/wolfTPM-Manual.pdf + test -s build/documentation/wolfTPM/wolfTPM-Manual-jp.pdf + - uses: actions/upload-artifact@v4 + with: + name: wolftpm-manual + path: | + build/documentation/wolfTPM/html-en/ + build/documentation/wolfTPM/html-ja/ + build/documentation/wolfTPM/wolfTPM-Manual.pdf + build/documentation/wolfTPM/wolfTPM-Manual-jp.pdf + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/publish-docs-image.yml b/.github/workflows/publish-docs-image.yml new file mode 100644 index 00000000..ed1de61f --- /dev/null +++ b/.github/workflows/publish-docs-image.yml @@ -0,0 +1,42 @@ +name: Publish documentation image + +on: + push: + branches: [master] + paths: + - 'docker/docs/**' + - '.github/workflows/publish-docs-image.yml' + workflow_dispatch: + +permissions: + contents: read + packages: write + +concurrency: + group: publish-wolftpm-docs-image + cancel-in-progress: false + +jobs: + publish: + if: github.repository == 'wolfSSL/wolfTPM' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - name: Select image tag + id: image + run: | + image_sha=$(sha256sum docker/docs/Dockerfile docker/docs/requirements.txt | sha256sum | cut -c1-16) + echo "tag=ghcr.io/wolfssl/wolftpm-docs:sha-$image_sha" >> "$GITHUB_OUTPUT" + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/build-push-action@v6 + with: + context: docker/docs + file: docker/docs/Dockerfile + push: true + tags: ${{ steps.image.outputs.tag }} diff --git a/.gitignore b/.gitignore index 4802916d..601474fe 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ libtool Makefile !/wrapper/rust/Makefile !/wrapper/rust/wolftpm/Makefile +!/tools/docs-manual/Makefile wolftpm-config .dirstamp *.la diff --git a/README.md b/README.md index 4e3c46cd..008eab9b 100644 --- a/README.md +++ b/README.md @@ -2,346 +2,92 @@ Portable TPM 2.0 project designed for embedded use. - ## Project Features -* This implementation provides all TPM 2.0 API's in compliance with the specification. -* Wrappers provided to simplify Key Generation/Loading, RSA encrypt/decrypt, ECC sign/verify, ECDH, NV, Hashing/HACM, AES, Sealing/Unsealing, Attestation, PCR Extend/Quote and Secure Root of Trust. -* Any TPM 2.0 compliant module is supported. Tested modules include Infineon SLB9670, SLB9672, SLB9673, STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI, ST33TPHF2XI2C, Microchip ATTPM20, Nations Technologies/NSING Z32H330, NS350, Nuvoton NPCT650, NPCT750, and SealSQ QVault TPM (first TPM with post-quantum ML-DSA/ML-KEM in silicon). -* wolfTPM uses the TPM Interface Specification (TIS) to communicate either over SPI, or using a memory mapped I/O range. -* On Linux, wolfTPM auto-detects between the kernel TPM driver (`/dev/tpmX`) and direct SPI access at runtime - a simple `./configure && make` works with either interface. -* wolfTPM can also use the Linux TPM kernel interface (`/dev/tpmX`) to talk with any physical TPM on SPI, I2C and even LPC bus. -* Platform support for Raspberry Pi (Linux), MMIO, STM32 with CubeMX, Atmel ASF, Xilinx, QNX, Infineon TriCore, wolfHAL and Barebox. -* The design allows for easy portability to different platforms: - * Native C code designed for embedded use. - * Single IO callback for hardware SPI interface. - * No external dependencies. - * Compact code size and minimal memory use. -* Includes example code for: - * Most TPM2 native API's - * All TPM2 wrapper API's - * PKCS 7 - * Certificate Signing Request (CSR) - * TLS Client - * TLS Server - * Use of the TPM's Non-volatile memory - * Attestation (activate and make credential) - * Benchmarking TPM algorithms and TLS - * Key Generation (primary, RSA/ECC and symmetric), loading and storing to flash (NV memory) - * Sealing and Unsealing data with an RSA key or externally signed policy. - * Time signed or set - * PCR read/reset - * GPIO configure, read and write. - * Endorsement Key/Cert retrieval and validation. -* Parameter encryption support using AES-CFB or XOR. -* Support for salted unbound authenticated sessions. -* Support for HMAC Sessions. -* Support for reading Endorsement certificates (EK Credential Profile). -* Includes a portable firmware TPM 2.0 implementation (fwTPM, also known as fTPM / swtpm) for embedded platforms without a discrete TPM chip. See [Firmware TPM (fwTPM / fTPM / swtpm)](#firmware-tpm-fwtpm--ftpm--swtpm) below. -* **Post-quantum cryptography support** via TPM 2.0 Library Specification v1.85: ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation, enabled with `--enable-v185` (full v1.85) or the leaner `--enable-pqc` (ML-DSA / ML-KEM only), with per-operation trimming via `--enable-mldsa`/`--enable-mlkem`. Auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has ML-DSA + ML-KEM. Both the client library and the fwTPM server implement the eight new v1.85 PQC commands. See [Post-Quantum Cryptography (v1.85)](#post-quantum-cryptography-v185) below. -* **SPDM attestation support** (DMTF DSP0274) over the TCG SPDM-over-TPM binding, with a TCG certificate handshake and a DSP0274 pre-shared-key (PSK) handshake, enabled with `--enable-spdm`. The fwTPM server includes an SPDM 1.3 responder so the stack can be exercised end-to-end in CI without discrete silicon. See [SPDM Attestation](#spdm-attestation) below. - -Note: See [examples/README.md](examples/README.md) for details on using the examples. - +* TPM 2.0 API built on the TCG TPM 2.0 Library Specification, including the revision 1.85 post-quantum additions: ML-DSA (FIPS 204) and ML-KEM (FIPS 203). +* Wrappers that simplify Key Generation and Loading, RSA encrypt and decrypt, ECC sign and verify, ECDH, NV, Hashing and HMAC, AES, Sealing and Unsealing, Attestation, PCR Extend and Quote, and Secure Root of Trust. +* TPM Interface Specification (TIS) communication over SPI or a memory mapped I/O range, with I2C and LPC available through the Linux kernel driver. +* Runtime module auto-detection on Linux between the kernel TPM driver (`/dev/tpmX`) and direct SPI access (`--enable-autodetect`). +* Easy portability: native C for embedded use, a single IO callback for the hardware SPI interface, no external dependencies, and a compact code size. +* Parameter encryption using AES-CFB or XOR, salted unbound authenticated sessions, HMAC sessions, and Endorsement certificate reading (EK Credential Profile). +* A portable firmware TPM 2.0 (fwTPM / fTPM / swtpm) for platforms with no discrete TPM, post-quantum cryptography (TPM 2.0 v1.85), and SPDM attestation (see the sections below). +* Example code for the native and wrapper API's, PKCS 7, CSR, TLS client and server, NV storage, attestation, benchmarking, key generation and storage, sealing and unsealing, timestamps, PCR, GPIO, and endorsement key and certificate retrieval. + +## Supported Hardware + +wolfTPM works with any TPM 2.0 compliant module. Tested parts: + +* Infineon OPTIGA SLB9670 (SPI), SLB9672 (SPI), SLB9673 (I2C) +* STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI, ST33TPHF2XI2C +* Microchip ATTPM20 +* Nuvoton NPCT650, NPCT750 +* Nations Technologies / NSING Z32H330, NS350 +* SealSQ QVault TPM (SPI, the first TPM with post-quantum ML-DSA and ML-KEM in silicon) +* NVIDIA Jetson Orin (Tegra234) firmware TPM, reached through the Linux kernel driver +* The wolfCrypt firmware TPM (fwTPM), for platforms with no discrete TPM chip + +Platform support: Raspberry Pi (Linux), Linux `/dev/tpmX`, MMIO, STM32 with CubeMX, +Atmel ASF, Xilinx, QNX, Infineon TriCore, Espressif ESP-IDF, Zephyr, wolfHAL, and +Barebox. See the [Supported Hardware manual](https://www.wolfssl.com/documentation/manuals/wolftpm/supported-hardware.html) +for how to build and wire each part. ## Firmware TPM (fwTPM / fTPM / swtpm) -wolfTPM includes a portable firmware TPM 2.0 implementation (`fwtpm_server`) -built entirely on wolfCrypt. It provides a standards-compliant TPM 2.0 command -processor that can replace a hardware TPM on embedded platforms without a -discrete TPM chip, or serve as a drop-in development and CI/CD replacement for -external simulators like swtpm or the Microsoft TPM simulator. +wolfTPM includes a portable firmware TPM 2.0 implementation (`fwtpm_server`) built +entirely on wolfCrypt. It provides a standards-compliant TPM 2.0 command processor +that can replace a hardware TPM on embedded platforms without a discrete TPM chip, +or serve as a drop-in development and CI/CD replacement for external simulators +like swtpm or the Microsoft TPM simulator. Features: -* 105 TPM 2.0 commands implemented (93% of v1.38 spec) with wolfCrypt cryptography (RSA, ECC, SHA, AES, HMAC) -* Socket transport (Microsoft TPM simulator protocol) compatible with `tpm2-tools` and wolfTPM examples + +* 105 TPM 2.0 commands implemented (93% of the v1.38 spec) with wolfCrypt cryptography (RSA, ECC, SHA, AES, HMAC) +* Socket transport (Microsoft TPM simulator protocol) compatible with tpm2-tools and the wolfTPM examples * TIS register-level transport over shared memory or SPI/I2C for bare-metal integration * HAL abstractions for IO transport and NV storage portability * File-based or custom NV storage via HAL callbacks -* Compile-time algorithm and per-command-group feature selection (e.g., `NO_RSA`, `FWTPM_NO_NV`, and independent per-command-group gates you pick and choose to shrink the fTPM footprint) +* Compile-time algorithm and per-command-group feature selection (for example `NO_RSA`, `FWTPM_NO_NV`, and independent per-command-group gates you pick to shrink the fTPM footprint) * `WOLFTPM_SMALL_STACK` support for constrained environments -See [docs/FWTPM.md](docs/FWTPM.md) for build instructions, configuration, and API reference. - +See the [firmware TPM manual](https://www.wolfssl.com/documentation/manuals/wolftpm/fwtpm/overview.html) +for build instructions, configuration, and API reference. ## Post-Quantum Cryptography (v1.85) -wolfTPM implements the post-quantum algorithms added in **TCG TPM 2.0 -Library Specification v1.85**, built on wolfCrypt's FIPS 203 (ML-KEM) -and FIPS 204 (ML-DSA) modules. - -Supported algorithms: - -| Algorithm | Standard | Parameter sets | -|---|---|---| -| ML-DSA (signing) | FIPS 204 | ML-DSA-44 / 65 / 87 | -| Hash-ML-DSA (pre-hash signing) | FIPS 204 | ML-DSA-44 / 65 / 87 with caller hash | -| ML-KEM (key encapsulation) | FIPS 203 | ML-KEM-512 / 768 / 1024 | - -wolfTPM **officially supports the SealSQ QVault TPM**, the first shipping TPM 2.0 -with these v1.85 PQC algorithms in silicon. See -[Hardware TPM: SealSQ QVault](#hardware-tpm-sealsq-qvault) for its hardware -build. The same PQC API also runs against the in-tree fwTPM server for CI or -when no hardware is present. See the -[TPM2 Benchmarks](#tpm2-benchmarks) section for measured ML-DSA / ML-KEM -performance on the QVault TPM. - -### Building - -**wolfSSL** (ML-DSA and ML-KEM in wolfCrypt): - -``` -./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \ - --enable-mldsa --enable-mlkem \ - --enable-harden CFLAGS="-DWC_RSA_NO_PADDING" -make -sudo make install -``` - -#### fwTPM (software TPM) - -``` -./configure --enable-fwtpm --enable-pqc -make -``` - -The fwTPM server uses the full v1.85 command set, so configure promotes -`--enable-pqc` to `--enable-v185`. If you omit both flags and wolfCrypt has -ML-DSA + ML-KEM, configure auto-enables v1.85. Pass `--disable-pqc` to opt -out explicitly. - -#### Hardware TPM: SealSQ QVault - -SealSQ QVault is the hardware TPM currently supported for v1.85 PQC: - -``` -./configure --enable-sealsq --enable-pqc -make -``` - -On Linux, add `--enable-devtpm` to use the kernel TPM driver. For examples -that pass transient handles between processes, also add -`CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm0"'`: the default `/dev/tpmrm0` virtualizes -and discards those handles when a process closes the device. Keep the inner -double quotes literal inside the single-quoted `CFLAGS` value. See -[docs/DEVTPM.md](docs/DEVTPM.md) for device permissions and details. - -`--enable-pqc` builds the lean ML-DSA / ML-KEM subset (`WOLFTPM_PQC`) for -hardware. Use `--enable-v185` (`WOLFTPM_V185`) for the full v1.85 command set. - -Non-SHA-1 TPM examples include: +wolfTPM implements the TPM 2.0 Library Specification v1.85 post-quantum algorithms: +ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation. Both the client +library and the firmware TPM server implement the eight new v1.85 PQC commands, and +the SealSQ QVault is supported as the first TPM with ML-DSA and ML-KEM in silicon. -``` -./examples/pqc/pqc_ctrl --caps --algs -./examples/pqc/pqc_ctrl --mldsa=65 --mlkem=768 -./examples/wrap/hash "wolfTPM" -sha256 -``` - -#### Trimming the PQC footprint - -To compile only the operations you call (smaller binary, no malloc needed), -mirror the wolfSSL flags: - -``` -# ML-DSA verify-only + ML-KEM encapsulate-only (no sign, no decapsulate) -./configure --enable-pqc --enable-mldsa=verify-only --enable-mlkem=enc -``` - -| Flag | Values | Drops | -|------|--------|-------| -| `--enable-mldsa` | `all` (default) / `sign-only` / `verify-only` / `no` | the unselected ML-DSA operation | -| `--enable-mlkem` | `all` (default) / `enc` / `dec` / `no` | the unselected ML-KEM operation | -| `--disable-hash-mldsa` | — | pre-hash ML-DSA key support | - -These map to `WOLFTPM_NO_MLDSA_SIGN`, `WOLFTPM_NO_MLKEM_DECAP`, etc., which -embedded integrators can also pass directly via `CFLAGS` without autotools. -Existing `--enable-v185` builds are unaffected (every operation defaults on). -Disabling both algorithms (`--enable-mldsa=no --enable-mlkem=no`) is a configure -error — use `--disable-pqc` to build without any post-quantum support. - -The same flags also trim the fwTPM server: `--enable-fwtpm ---enable-mldsa=verify-only` builds a server that implements only ML-DSA verify -(the sign command handlers, dispatch entries, and crypto are compiled out). -fwTPM always builds the full v1.85 spec surface, so the trims apply on top of -`WOLFTPM_V185`. - -### Running the examples - -``` -make check -``` - -`make check` runs the fwTPM tests, including PQC coverage. - -See [examples/pqc/README.md](examples/pqc/README.md) for per-example -details — the `pqc_ctrl` control center (every PQC operation plus board -control in one CLI, with `pqc_ctrl.sh` running the full command set), -`pqc_mssim_e2e`, `mlkem_encap`, and PQC options on the general-purpose -`keygen`/`keyload` tools (`-mldsa`, `-hash_mldsa`, `-mlkem`). - -For the fwTPM server's PQC internals — the eight v1.85 commands, -primary-key derivation, buffer constants, and spec-interpretation -decisions — see -[docs/FWTPM.md](docs/FWTPM.md#tpm-20-v185-post-quantum-support). +Build with `--enable-pqc` (the leaner ML-DSA and ML-KEM subset) or `--enable-v185` +(the full v1.85 feature set), against a wolfCrypt built with ML-DSA and ML-KEM. +Per-operation trimming is available with `--enable-mldsa` and `--enable-mlkem`, and +`make check` runs the PQC tests. +See the [post-quantum manual](https://www.wolfssl.com/documentation/manuals/wolftpm/post-quantum.html) +and the [firmware TPM post-quantum manual](https://www.wolfssl.com/documentation/manuals/wolftpm/fwtpm/post-quantum.html). ## SPDM Attestation -wolfTPM implements SPDM (Security Protocol and Data Model, DMTF DSP0274) -for TPM 2.0 attestation over the TCG SPDM-over-TPM binding. Both the TCG -certificate handshake and the DSP0274 pre-shared-key (PSK) handshake are -supported, negotiating SPDM protocol version 1.3. - -For testing without discrete silicon, the `fwtpm_server` ships an SPDM 1.3 -responder that drives the same handshake the real Nuvoton and Nations -parts use, so the SPDM stack can be exercised end-to-end in CI. - -Build with `--enable-spdm` plus at least one handshake mode -(`--enable-tcg` for the certificate handshake, `--enable-psk` for the PSK -handshake). Vendor wire-format adapters are optional (`--enable-nuvoton`, -`--enable-nations`). - -See [src/spdm/README.md](src/spdm/README.md) and -[src/fwtpm/README.md](src/fwtpm/README.md) for build instructions, -responder modes, and the end-to-end test scripts. - - -## TPM 2.0 Overview - -### Hierarchies - -``` -Platform TPM_RH_PLATFORM -Owner TPM_RH_OWNER -Endorsement TPM_RH_ENDORSEMENT -``` - -Each hierarchy has their own manufacture generated seed. - -The arguments used on `TPM2_Create` or `TPM2_CreatePrimary` create a template, which is fed into a KDF to produce the same key based hierarchy used. The key generated is the same each time; even after reboot. The generation of a new RSA 2048 bit key takes about 15 seconds. Typically these are created and then stored in NV using `TPM2_EvictControl`. Each TPM generates their own keys uniquely based on the seed. - -There is also an Ephemeral hierarchy (`TPM_RH_NULL`), which can be used to create ephemeral keys. - -### Platform Configuration Registers (PCRs) - -PCRs hold hash digests at indices 0-23 in banks supported and allocated by the -TPM. They can be extended to prove the integrity of a boot sequence (secure -boot). - - -### Terminology - -This project uses the terms append vs. marshall and parse vs. unmarshall. - -Acronyms: -* HAL: Hardware Abstraction Layer. -* NV: Non-Volatile memory. -* TPM: Trusted Platform Module. - -## Platform - -The examples in this library are written for use on a Raspberry Pi and use the `spi_dev` interface. - -### IO Callback (HAL) - -See the HAL manual in [hal/README.md](hal/README.md). - -For interfacing to your hardware interface (SPI/I2C) a single HAL callback is used and configuration on initialization when calling `TPM2_Init` or `wolfTPM2_Init`. +wolfTPM implements SPDM (Security Protocol and Data Model, DMTF DSP0274) for TPM 2.0 +attestation over the TCG SPDM-over-TPM binding. Both the TCG certificate handshake +and the DSP0274 pre-shared-key (PSK) handshake are supported, negotiating SPDM +protocol version 1.3. -There are HAL examples in `hal` directory for: +For testing without discrete silicon, the `fwtpm_server` ships an SPDM 1.3 responder +that drives the same handshake the real Nuvoton and Nations parts use, so the SPDM +stack can be exercised end-to-end in CI. -* Atmel ASF -* BareBox -* Espressif ESP-IDF -* Infineon TriCore -* Linux -* STM32 CubeMX -* wolfHAL -* Xilinx +Build with `--enable-spdm` plus at least one handshake mode (`--enable-tcg` for the +certificate handshake, `--enable-psk` for the PSK handshake). Vendor wire-format +adapters are optional (`--enable-nuvoton`, `--enable-nations`). -We also support an advanced IO option (`--enable-advio`/`WOLFTPM_ADV_IO`), which adds the register and read/write flag as parameter to the IO callback. This is required for I2C support. - -### Hardware - -Tested with: - -* Infineon OPTIGA (TM) Trusted Platform Module 2.0 SLB9670, SLB9672 and SLB9673 (I2C). - - LetsTrust: Vendor for TPM development boards [http://letstrust.de](http://letstrust.de). -* STMicro STSAFE-TPM, ST33TPHF2XSPI/2XI2C and ST33KTPM2X (SPI and I2C) -* Microchip ATTPM20 module -* Nuvoton NPCT65X or NPCT75x TPM2.0 modules -* Nations Technologies Z32H330 or NS350 TPM 2.0 modules -* SealSQ QVault TPM 2.0 module (SPI, post-quantum ML-DSA / ML-KEM) -* NVIDIA Jetson Orin (Tegra234) firmware TPM - a TPM 2.0 running as an OP-TEE trusted application, reached through the Linux kernel driver rather than a bus. See [docs/DEVTPM.md](docs/DEVTPM.md#nvidia-jetson-orin-tegra234-firmware-tpm). - -#### Device Identification - -Infineon SLB9670: -TPM2: Caps 0x30000697, Did 0x001b, Vid 0x15d1, Rid 0x10 -Mfg IFX (1), Vendor SLB9670, Fw 7.85 (4555), FIPS 140-2 1, CC-EAL4 1 - -Infineon SLB9672: -TPM2: Caps 0x30000697, Did 0x001d, Vid 0x15d1, Rid 0x36 -Mfg IFX (1), Vendor SLB9672, Fw 16.10 (0x4068), FIPS 140-2 1, CC-EAL4 1 - -Infineon SLB9673: -TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 -Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a), FIPS 140-2 1, CC-EAL4 1 - -STMicro ST33KTPM2XSPI -TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 0 -Mfg STM (2), Vendor ST33KTPM2XSPI, Fw 9.256 (0x0), FIPS 140-2 1, CC-EAL4 0 - -STMicro ST33TPHF2XSPI -TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e -Mfg STM (2), Vendor , Fw 74.8 (1151341959), FIPS 140-2 1, CC-EAL4 0 - -STMicro ST33TPHF2XSPI (newer firmware line) -TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e -Mfg STM (2), Vendor , Fw 1.258 (0x0), FIPS 140-2 1, CC-EAL4 0 - -STMicro ST33TPHF2XI2C -TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e -Mfg STM (2), Vendor , Fw 74.9 (1151341959), FIPS 140-2 1, CC-EAL4 0 - -Microchip ATTPM20 -TPM2: Caps 0x30000695, Did 0x3205, Vid 0x1114, Rid 0x 1 -Mfg MCHP (3), Vendor , Fw 512.20481 (0), FIPS 140-2 0, CC-EAL4 0 - -Note: early ST33TPHF2X 1.x firmware reports `TPM_PT_VENDOR_STRING_1..4` as -binary rather than text, so the `Vendor` field prints empty; later 1.x firmware -reports ASCII such as `ST33TPHF2XSPI`. The firmware major version identifies the line -instead: 1.x and 2.x are ST33TPHF2X (SPI and I2C firmware respectively), 9.x is -ST33KTPM2X and 10.x is ST33KTPM2A. See -[examples/firmware/README.md](examples/firmware/README.md) for how this selects -the firmware update format and command codes. - -Nations Technologies Inc. Z32H330 TPM 2.0 module -Mfg NTZ (0), Vendor Z32H330, Fw 7.51 (419631892), FIPS 140-2 0, CC-EAL4 0 - -Nations Technologies Inc. NS350 TPM 2.0 module -TPM2: Caps 0x30000615, Did 0x0701, Vid 0x9999, Rid 0x 1 -Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 - -Nuvoton NPCT650 TPM2.0 -Mfg NTC (0), Vendor rlsNPCT , Fw 1.3 (65536), FIPS 140-2 0, CC-EAL4 0 - -Nuvoton NPCT750 TPM2.0 -TPM2: Caps 0x30000697, Did 0x00fc, Vid 0x1050, Rid 0x 1 -Mfg NTC (0), Vendor NPCT75x"!!4rls, Fw 7.2 (131072), FIPS 140-2 1, CC-EAL4 0 - -SealSQ QVault TPM 2.0 -TPM2: Caps 0x30000797, Did 0x0083, Vid 0x2406, Rid 0x 3 -Mfg SEAL (6), Vendor QVault TPM, Fw 2.1 (0x3010303), FIPS 140-3, CC-EAL4 0 - -NVIDIA Jetson Orin (Tegra234) OP-TEE firmware TPM, via /dev/tpmrm0 -Mfg MSFT (7), Vendor SSE fTPM, Fw 8216.1808 (0x105300), FIPS 140-2, CC-EAL4 0 - -There is no `Caps/Did/Vid/Rid` line above because those values come from TIS bus registers, which a firmware TPM does not have. The entry was captured with `--enable-autodetect`, where `wolfTPM2_Init_ex` returns as soon as the kernel device opens, so the debug line is never reached; an `--enable-devtpm` build still prints it, reading all zeros. `Fw 8216.1808` is `TPM_PT_FIRMWARE_VERSION_1` = `0x20180710`, which this implementation uses to carry a build date (2018-07-10) rather than a version number. Spec revision is 1.62, and all four PCR banks (SHA-1, SHA-256, SHA-384, SHA-512) are allocated with PCRs 0-23. +See the [SPDM manual](https://www.wolfssl.com/documentation/manuals/wolftpm/spdm.html) +for build instructions, responder modes, and the end-to-end test scripts. ## Building -### Building wolfSSL +### wolfSSL ```bash git clone https://github.com/wolfSSL/wolfssl.git @@ -353,970 +99,85 @@ sudo make install sudo ldconfig ``` -autogen.sh requires: automake and libtool: `sudo apt-get install automake libtool` - -### Building wolfSSL with an alternate directory - -```bash -# cd /your-wolfssl-repo -./autogen.h # as necessary -./configure --prefix=~/workspace/my_wolfssl_bin --enable-all -make install - -# then for some other library such as wolfTPM: - -# cd /your-wolftpm-repo -./configure --enable-swtpm --with-wolfcrypt=~/workspace/my_wolfssl_bin -``` - -### Build options and defines - -```text ---enable-debug Add debug code/turns off optimizations (yes|no|verbose|io) - DEBUG_WOLFTPM, WOLFTPM_DEBUG_VERBOSE, WOLFTPM_DEBUG_IO - WARNING: Define WOLFTPM_DEBUG_SECRETS manually (NOT enabled by default and NOT - exposed via configure) to additionally print sensitive material - auth values, - session keys, bind keys, HMAC keys, hierarchy auth, and encryption secrets. - For developer debugging only. NEVER enable in production builds or on devices - that log stdout to persistent storage. ---enable-examples Enable Examples (default: enabled) ---enable-wrapper Enable wrapper code (default: enabled) - WOLFTPM2_NO_WRAPPER ---enable-wolfcrypt Enable wolfCrypt hooks for RNG, Auth Sessions and Parameter encryption (default: enabled) - WOLFTPM2_NO_WOLFCRYPT ---enable-advio Enable Advanced IO (default: disabled) - WOLFTPM_ADV_IO ---enable-spi Intent signal for SPI hardware build. SPI is the default transport when --enable-i2c is not set; - this flag adds no compile-time macro but disables the auto-enabled swTPM/fwTPM defaults. (default: not set) ---enable-i2c Enable I2C TPM Support (default: disabled, requires advio) - WOLFTPM_I2C ---enable-mmio Enable built-in MMIO callbacks (default: disabled) - WOLFTPM_MMIO ---enable-wolfhal Enable wolfHAL IO callbacks (default: disabled) - WOLFTPM_WOLFHAL - Requires the wolfHAL headers and an application provided board.h. - See hal/README.md for the required BOARD_* definitions. ---enable-checkwaitstate Enable TIS / SPI Check Wait State support (default: depends on chip) - WOLFTPM_CHECK_WAIT_STATE ---enable-smallstack Enable options to reduce stack usage ---enable-tislock Enable Linux Named Semaphore for locking access to SPI device for concurrent access between processes - WOLFTPM_TIS_LOCK ---enable-firmware Enable firmware upgrade support for Infineon SLB9672/SLB9673 and ST ST33 (default: disabled) - WOLFTPM_FIRMWARE_UPGRADE - ---enable-autodetect Enable Runtime Module Detection (default: enable - when no module specified) - WOLFTPM_AUTODETECT - On Linux this also auto-detects /dev/tpmrm0 or /dev/tpm0 at runtime, - falling back to SPI if the kernel driver is not available. ---enable-infineon Enable Infineon SLB9670/SLB9672/SLB9673 TPM Support (default: disabled) - WOLFTPM_SLB9670 / WOLFTPM_SLB9672 ---enable-st Enable ST ST33 Support (default: disabled) - WOLFTPM_ST33 ---enable-microchip Enable Microchip ATTPM20 Support (default: disabled) - WOLFTPM_MICROCHIP ---enable-nuvoton Enable Nuvoton NPCT65x/NPCT75x Support (default: disabled) - WOLFTPM_NUVOTON ---enable-nations Enable Nations Technology NS350 Support (default: disabled) - WOLFTPM_NATIONS ---enable-sealsq Enable SealSQ QVault post-quantum TPM Support (default: disabled) - WOLFTPM_SEALSQ - ---enable-devtpm Enable using Linux kernel driver for /dev/tpmX (default: disabled) - WOLFTPM_LINUX_DEV - Note: With autodetect (default) this is no longer required on Linux; - the kernel driver is tried automatically before SPI. ---enable-swtpm Enable using SWTPM TCP protocol. For use with simulator. (default: enabled on Linux x86_64/aarch64, - disabled elsewhere or when a hardware path is selected via any of - --enable-spi/--enable-i2c/--enable-mmio/--enable-nuvoton/--enable-nations/ - --enable-infineon/--enable-st/--enable-microchip/--enable-devtpm/--enable-autodetect) - WOLFTPM_SWTPM ---enable-swtpm=uart Enable using SWTPM protocol over UART serial. For use with fwTPM on - embedded targets (e.g. STM32H5). Uses termios serial I/O instead of - TCP sockets. - WOLFTPM_SWTPM + WOLFTPM_SWTPM_UART ---enable-fwtpm Enable firmware TPM (fwTPM) server. Same default behavior as --enable-swtpm - (auto-enabled on Linux x86_64/aarch64, auto-disabled when a hardware - path is selected). - WOLFTPM_FWTPM_SERVER ---enable-winapi Use Windows TBS API. (default: disabled) - WOLFTPM_WINAPI - -WOLFTPM_USE_SYMMETRIC Enables symmetric AES/Hashing/HMAC support for TLS examples. -WOLFTPM2_USE_SW_ECDHE Disables use of TPM for ECC ephemeral key generation and shared secret for TLS examples. -WOLFTPM2_ECC_DEFAULT_CURVE Default ECC curve for wrapper key templates that request P256 (SRK/AIK/general ECC). Defaults to TPM_ECC_NIST_P256, or the smallest enabled curve meeting ECC_MIN_KEY_SZ. Override e.g. -DWOLFTPM2_ECC_DEFAULT_CURVE=TPM_ECC_NIST_P384. -TLS_BENCH_MODE Enables TLS benchmarking mode. -NO_TPM_BENCH Disables the TPM benchmarking example. -WOLFTPM_MAX_RETRIES Default number of times a command is transparently resubmitted when the TPM returns TPM_RC_RETRY (momentarily busy, e.g. persisting the daUsed flag on first auth use of an externally provisioned non-noDA AIK/SUDI key). Disabled by default (0); opt in with TPM2_SetCommandRetries() at runtime or -DWOLFTPM_MAX_RETRIES=N at build time. wolfTPM's own key templates set noDA and never trigger it. -WOLFTPM_NO_RETRY Compiles out the TPM_RC_RETRY auto-resubmit handling entirely; TPM_RC_RETRY is returned to the caller for manual handling. -WOLFTPM_LOCALITY_DEFAULT Default TIS locality requested at startup (default 0). Runtime override via wolfTPM2_SetLocality() on SPI/memory-mapped and swtpm transports. The I2C HAL addresses only locality 0 (the TIS locality lives in address bits 12+, which the 8-bit I2C register address cannot carry), so a non-zero wolfTPM2_SetLocality() on I2C returns NOT_COMPILED_IN rather than silently operating at locality 0. -WOLFTPM_TIS_RESET_STALE_LOCALITY At startup, release any other active locality so the default can be granted - recovers a wedge left when a prior session did not return to locality 0. Off by default; single-master buses only, since on a shared bus it could clear a locality another master holds (or use the nRST reset HAL to recover). -WOLFTPM_LOCALITY_TIMEOUT_TRIES Poll attempts when requesting a locality at runtime (default 1000). Kept small so a locality that cannot be granted fails fast. -WOLFTPM_RESET_LINE nRST GPIO line number for the optional reset HAL; set via --enable-hal-reset=LINE and driven with TPM2_IoCb_Reset() (see hal/README.md). -``` - -Note: For the I2C support on Raspberry Pi you may need to enable I2C. Here are the steps: -1. Edit `sudo vim /boot/config.txt` -2. Uncomment `dtparam=i2c_arm=on` -3. Reboot `sudo reboot` - - -### Building Infineon - -Support for SLB9670 or SLB9672 (SPI) / SLB9673 (I2C) +`autogen.sh` requires automake and libtool: `sudo apt-get install automake libtool`. -Build wolfTPM: +### wolfTPM ```bash -git clone https://github.com/wolfSSL/wolfTPM.git -cd wolfTPM ./autogen.sh -./configure --enable-infineon [--enable-i2c] +./configure make +make check ``` -The default is SLB9672/SLB9673 (if I2C). To specify SLB9670 use `--enable-infineon=slb9670`. - -### Building ST ST33 - -Build wolfTPM: - -```bash -./autogen.sh -./configure --enable-st33 [--enable-i2c] [--enable-firmware] -make -``` - -Note: The `--enable-firmware` option enables firmware upgrade support for ST33 TPMs. This adds the `st33_fw_update` example tool for performing firmware updates. - -Raspberry Pi wiring: ST33KTPM2X SPI is on `/dev/spidev0.0` with `nRST` (active low) on GPIO24 (pin 18); Nuvoton uses GPIO4. Optionally drive nRST from code with `--enable-hal-reset` and `TPM2_IoCb_Reset()` (see `hal/README.md`). - -### Building Microchip ATTPM20 - -Build wolfTPM: - -```bash -./autogen.sh -./configure --enable-microchip -make -``` - -### Building Nuvoton - -Build wolfTPM: - -```bash -./autogen.sh -./configure --enable-nuvoton -make -``` - -### Building Nations Tech - -Use `./configure` with defaults. All TPM 2.0 modules are compatible. -The Nations NS350 Raspberry Pi TPM 2.0 module uses `/dev/spidev0.0`. The TPM wait states are required (on by default with WOLFTPM_CHECK_WAIT_STATE). - -### Building Espressif ESP-IDF - -See the wolfTPM-specific settings in the wolfSSL `user_settings.h` file, typically found in `[project]/components/wolfssl/include`. - -```bash -git clone https://github.com/wolfSSL/wolfTPM.git -cd wolfTPM/IDE/Espressif - -# set your path to ESP-IDF, shown here for VisualGDB using v5.2 -WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.2 - -. ${WRK_IDF_PATH}/export.sh -idf.py build -``` - -### Building for "/dev/tpmX" - -**Auto-detection (recommended):** `--enable-autodetect` tries `/dev/tpmrm0` then `/dev/tpm0` at runtime. If the kernel driver is available it will be used; otherwise wolfTPM falls back to direct SPI access. - -```bash -./autogen.sh -./configure --enable-autodetect -make -``` - -**Important:** on Linux `x86_64` and `aarch64`, a bare `./configure` does *not* reach `/dev/tpmX`. On those hosts the software TPMs (swTPM and fwTPM) are auto-enabled so that `make check` works without hardware, and defining `WOLFTPM_SWTPM` suppresses the kernel-device autodetect path. The resulting build talks to a simulator on TCP port 2321, not to your TPM. Selecting any hardware path explicitly - `--enable-autodetect`, `--enable-devtpm`, or any `--enable-` - turns the software defaults back off. This matters on single-board machines with a firmware TPM, such as the NVIDIA Jetson Orin, where the kernel device is the only transport. - -Use `--enable-devtpm` to force kernel-driver-only mode, which disables the SPI fallback: - -```bash -./autogen.sh -./configure --enable-devtpm -make -``` - -To specify a different `/dev/tpmX` device use `CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm1"'` - the inner quotes are required, since the macro is used directly as a C string literal. To pin the resource manager and never fall back to the raw device, build with `-DWOLFTPM_USE_TPMRM`. - -The `TPM2_Init` or `wolfTPM2_Init` calls should use NULL for the HAL IO callback argument. The default HAL IO `TPM2_IoCb` maps to a macro specifying NULL (`#define TPM2_IoCb NULL`) in tpm_io.h for the devtpm option. - -By default the `/dev/tpmX` requires sudo permissions to use it. If using the tpm2-tss it will install a "tss" group that you can add permissions to `sudo adduser [username] tss`. - -To add your own custom wolfTPM rule for /dev/tpm0 do the following: - -1) Create new group and add your user to it (replace "[username]" with yours): - -```bash -sudo addgroup wolftpm -sudo adduser [username] wolftpm -sudo chgrp wolftpm /dev/tpm0 -``` - -2) Create new rule file: `sudo vim /etc/udev/rules.d/wolftpm-udev.rules` - -3) Add the following rule to file: - -``` -KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", GROUP="wolftpm" -``` - -4) Reboot or reload rules: `sudo udevadm control -R` - -For the resource manager (`/dev/tpmrm0`) versus the raw device, which operations the kernel refuses, and firmware-TPM platforms such as the NVIDIA Jetson Orin, see [docs/DEVTPM.md](docs/DEVTPM.md). +On Linux x86_64 and aarch64 a bare `./configure` auto-enables the software TPM +backends, so `make check` runs without hardware. - -### Building for SWTPM - -See `docs/SWTPM.md` - -### Building for Windows TBS API - -See `docs/WindowTBS.md` - -## Building using CMake - -CMake supports compiling in many environments including Visual Studio -if CMake support is installed. The commands below can be run in -`Developer Command Prompt`. +### CMake ```bash mkdir build cd build -# to use installed wolfSSL location (library and headers) +# use an installed wolfSSL (library and headers) cmake .. -DWITH_WOLFSSL=/prefix/to/wolfssl/install/ -# OR to use a wolfSSL source tree +# OR use a wolfSSL source tree cmake .. -DWITH_WOLFSSL_TREE=/path/to/wolfssl/ -# build cmake --build . ``` -## Running Examples +For the full list of configure flags and defines see the +[Build Options manual](https://www.wolfssl.com/documentation/manuals/wolftpm/build-options.html). +To build for a specific TPM, see the +[Supported Hardware manual](https://www.wolfssl.com/documentation/manuals/wolftpm/supported-hardware.html). -These examples demonstrate features of a TPM 2.0 module. The examples create RSA and ECC keys in NV for testing using handles defined in `./hal/tpm_io.h`. The PKCS #7 and TLS examples require generating CSR's and signing them using a test script. See `examples/README.md` for details on using the examples. To run the TLS sever and client on same machine you must build with `WOLFTPM_TIS_LOCK` to enable concurrent access protection. +## Documentation -### TPM2 Capabilities +The full wolfTPM manual is published at +. The sources are kept in +[`docs/`](docs/), with a Japanese translation under [`docs/ja/`](docs/ja/). -Simple test that gets TPM capabilities and search for any persistent handles. +**Overview** -``` -./examples/wrap/caps -TPM2 Get Capabilities -wolfSSL Entering wolfCrypt_Init -Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 -Found 2 persistent handles -``` +* [Introduction](https://www.wolfssl.com/documentation/manuals/wolftpm/index.html): what wolfTPM is, with a map of the manual +* [TPM 2.0 Overview](https://www.wolfssl.com/documentation/manuals/wolftpm/tpm2-overview.html): protocol, hierarchies, PCRs, and device identification +* [Project Structure](https://www.wolfssl.com/documentation/manuals/wolftpm/project-structure.html): the source layout -### TPM2 Wrapper Tests +**Getting started** -``` -./examples/wrap/wrap_test -TPM2 Demo for Wrapper API's -Mfg STM (2), Vendor , Fw 74.8 (1151341959), FIPS 140-2 1, CC-EAL4 0 -RSA Encrypt/Decrypt Test Passed -RSA Encrypt/Decrypt OAEP Test Passed -RSA Key 0x80000000 Exported to wolf RsaKey -wolf RsaKey loaded into TPM: Handle 0x80000000 -RSA Private Key Loaded into TPM: Handle 0x80000000 -ECC Sign/Verify Passed -ECC DH Test Passed -ECC Verify Test Passed -ECC Key 0x80000000 Exported to wolf ecc_key -wolf ecc_key loaded into TPM: Handle 0x80000000 -ECC Private Key Loaded into TPM: Handle 0x80000000 -NV Test on index 0x1800200 with 1024 bytes passed -Hash SHA256 test success -HMAC SHA256 test success -Encrypt/Decrypt (known key) test success -Encrypt/Decrypt test success -``` - -### TPM2 Benchmarks - -Note: Key Generation is using existing template from hierarchy seed. - -Run on Infineon OPTIGA SLB9670 at 43MHz: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 16 KB took 1.140 seconds, 14.033 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -Benchmark symmetric AES-256-CFB-enc not supported! -Benchmark symmetric AES-256-CFB-dec not supported! -SHA1 138 KB took 1.009 seconds, 136.783 KB/s -SHA256 138 KB took 1.009 seconds, 136.763 KB/s -RSA 2048 key gen 5 ops took 10.981 sec, avg 2196.230 ms, 0.455 ops/sec -RSA 2048 Public 113 ops took 1.005 sec, avg 8.893 ms, 112.449 ops/sec -RSA 2048 Private 7 ops took 1.142 sec, avg 163.207 ms, 6.127 ops/sec -RSA 2048 Pub OAEP 73 ops took 1.011 sec, avg 13.848 ms, 72.211 ops/sec -RSA 2048 Priv OAEP 6 ops took 1.004 sec, avg 167.399 ms, 5.974 ops/sec -ECC 256 key gen 5 ops took 1.157 sec, avg 231.350 ms, 4.322 ops/sec -ECDSA 256 sign 15 ops took 1.033 sec, avg 68.865 ms, 14.521 ops/sec -ECDSA 256 verify 9 ops took 1.022 sec, avg 113.539 ms, 8.808 ops/sec -ECDHE 256 agree 5 ops took 1.161 sec, avg 232.144 ms, 4.308 ops/sec -``` - -Run on the SealSQ QVault post-quantum TPM (ML-DSA / ML-KEM) on a Raspberry Pi 5 -over SPI. These are the first post-quantum TPM benchmarks measured on -shipping-class silicon: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 10 KB took 1.061 seconds, 9.428 KB/s -AES-256-CBC-enc 57 KB took 1.000 seconds, 56.994 KB/s -SHA256 43 KB took 1.012 seconds, 42.470 KB/s -SHA384 43 KB took 1.024 seconds, 41.984 KB/s -RSA 2048 key gen 3 ops took 20.536 sec, avg 6845.188 ms, 0.146 ops/sec -RSA 2048 Public 71 ops took 1.015 sec, avg 14.289 ms, 69.985 ops/sec -RSA 2048 Private 7 ops took 1.154 sec, avg 164.827 ms, 6.067 ops/sec -ECC 256 key gen 4 ops took 1.170 sec, avg 292.538 ms, 3.418 ops/sec -ECDSA 256 sign 14 ops took 1.019 sec, avg 72.781 ms, 13.740 ops/sec -ECDSA 256 verify 17 ops took 1.031 sec, avg 60.661 ms, 16.485 ops/sec -ECDHE 256 agree 5 ops took 1.030 sec, avg 206.022 ms, 4.854 ops/sec -ML-DSA 65 key gen 8 ops took 16.357 sec, avg 2044.679 ms, 0.489 ops/sec -ML-DSA 65 sign 2 ops took 1.162 sec, avg 581.025 ms, 1.721 ops/sec -ML-DSA 65 verify 7 ops took 1.142 sec, avg 163.118 ms, 6.131 ops/sec -ML-KEM 768 key gen 19 ops took 15.216 sec, avg 800.819 ms, 1.249 ops/sec -ML-KEM 768 encap 5 ops took 1.059 sec, avg 211.777 ms, 4.722 ops/sec -ML-KEM 768 decap 3 ops took 1.276 sec, avg 425.471 ms, 2.350 ops/sec -``` +* [Getting Started](https://www.wolfssl.com/documentation/manuals/wolftpm/getting-started.html): install, build, and run your first example +* [Building](https://www.wolfssl.com/documentation/manuals/wolftpm/building.html): autotools, CMake, out-of-tree wolfSSL, and bare-metal +* [Build Options](https://www.wolfssl.com/documentation/manuals/wolftpm/build-options.html): every configure flag and define +* [System Interfaces](https://www.wolfssl.com/documentation/manuals/wolftpm/system-interfaces.html): the software simulator (SWTPM), Linux `/dev/tpmX`, and Windows TBS -Run on Infineon OPTIGA SLB9672 at 43MHz: +**Hardware** -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's - Use Parameter Encryption: NULL -Loading SRK: Storage 0x81000200 (282 bytes) -RNG 24 KB took 1.070 seconds, 22.429 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -AES-128-CFB-enc 86 KB took 1.001 seconds, 85.890 KB/s -AES-128-CFB-dec 88 KB took 1.020 seconds, 86.267 KB/s -AES-256-CFB-enc 86 KB took 1.023 seconds, 84.073 KB/s -AES-256-CFB-dec 86 KB took 1.019 seconds, 84.370 KB/s -SHA1 88 KB took 1.021 seconds, 86.155 KB/s -SHA256 86 KB took 1.015 seconds, 84.717 KB/s -SHA384 90 KB took 1.007 seconds, 89.405 KB/s -RSA 2048 key gen 10 ops took 15.677 sec, avg 1567.678 ms, 0.638 ops/sec -RSA 2048 Public 110 ops took 1.000 sec, avg 9.095 ms, 109.951 ops/sec -RSA 2048 Private 14 ops took 1.078 sec, avg 76.996 ms, 12.988 ops/sec -RSA 2048 Pub OAEP 51 ops took 1.012 sec, avg 19.838 ms, 50.408 ops/sec -RSA 2048 Priv OAEP 12 ops took 1.053 sec, avg 87.738 ms, 11.398 ops/sec -ECC 256 key gen 8 ops took 1.088 sec, avg 135.956 ms, 7.355 ops/sec -ECDSA 256 sign 29 ops took 1.033 sec, avg 35.621 ms, 28.073 ops/sec -ECDSA 256 verify 42 ops took 1.013 sec, avg 24.114 ms, 41.470 ops/sec -ECDHE 256 agree 16 ops took 1.055 sec, avg 65.948 ms, 15.164 ops/sec -``` +* [Supported Hardware](https://www.wolfssl.com/documentation/manuals/wolftpm/supported-hardware.html): every supported TPM and how to build for it +* [HAL IO Callback](https://www.wolfssl.com/documentation/manuals/wolftpm/hal-io-callback.html): the single IO callback porting model and wolfHAL -Run on Infineon SLB9673 on I2C at 400kHz: +**Usage** -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's - Use Parameter Encryption: NULL -Loading SRK: Storage 0x81000200 (282 bytes) -RNG 4 KB took 1.429 seconds, 2.799 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -AES-128-CFB-enc 4 KB took 1.022 seconds, 3.914 KB/s -AES-128-CFB-dec 4 KB took 1.021 seconds, 3.916 KB/s -AES-256-CFB-enc 4 KB took 1.023 seconds, 3.911 KB/s -AES-256-CFB-dec 4 KB took 1.023 seconds, 3.912 KB/s -SHA1 8 KB took 1.203 seconds, 6.650 KB/s -SHA256 8 KB took 1.208 seconds, 6.623 KB/s -SHA384 8 KB took 1.209 seconds, 6.617 KB/s -RSA 2048 key gen 10 ops took 19.106 sec, avg 1910.554 ms, 0.523 ops/sec -RSA 2048 Public 14 ops took 1.046 sec, avg 74.740 ms, 13.380 ops/sec -RSA 2048 Private 6 ops took 1.008 sec, avg 168.057 ms, 5.950 ops/sec -RSA 2048 Pub OAEP 15 ops took 1.008 sec, avg 67.231 ms, 14.874 ops/sec -RSA 2048 Priv OAEP 7 ops took 1.126 sec, avg 160.789 ms, 6.219 ops/sec -ECC 256 key gen 4 ops took 1.244 sec, avg 311.031 ms, 3.215 ops/sec -ECDSA 256 sign 14 ops took 1.009 sec, avg 72.057 ms, 13.878 ops/sec -ECDSA 256 verify 18 ops took 1.043 sec, avg 57.921 ms, 17.265 ops/sec -ECDHE 256 agree 9 ops took 1.025 sec, avg 113.888 ms, 8.781 ops/sec -``` +* [Examples Overview](https://www.wolfssl.com/documentation/manuals/wolftpm/examples-overview.html), [Key Management](https://www.wolfssl.com/documentation/manuals/wolftpm/key-management.html), [Attestation](https://www.wolfssl.com/documentation/manuals/wolftpm/attestation.html), [Sealing and NVRAM](https://www.wolfssl.com/documentation/manuals/wolftpm/sealing-and-nvram.html), [TLS and Certificates](https://www.wolfssl.com/documentation/manuals/wolftpm/tls-and-certificates.html), [Firmware Update](https://www.wolfssl.com/documentation/manuals/wolftpm/firmware-update.html), [Management and GPIO](https://www.wolfssl.com/documentation/manuals/wolftpm/management-and-gpio.html) -Run on STMicro ST33KTPM2XSPI at 33MHz: +**Features** -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's - Use Parameter Encryption: NULL -Loading SRK: Storage 0x81000200 (282 bytes) -RNG 24 KB took 1.042 seconds, 23.028 KB/s -AES-128-CBC-enc 52 KB took 1.018 seconds, 51.077 KB/s -AES-128-CBC-dec 52 KB took 1.027 seconds, 50.644 KB/s -AES-256-CBC-enc 46 KB took 1.012 seconds, 45.446 KB/s -AES-256-CBC-dec 46 KB took 1.021 seconds, 45.072 KB/s -AES-128-CTR-enc 44 KB took 1.025 seconds, 42.927 KB/s -AES-128-CTR-dec 44 KB took 1.024 seconds, 42.955 KB/s -AES-256-CTR-enc 40 KB took 1.025 seconds, 39.016 KB/s -AES-256-CTR-dec 40 KB took 1.026 seconds, 38.992 KB/s -AES-128-CFB-enc 52 KB took 1.026 seconds, 50.674 KB/s -AES-128-CFB-dec 46 KB took 1.023 seconds, 44.986 KB/s -AES-256-CFB-enc 46 KB took 1.021 seconds, 45.047 KB/s -AES-256-CFB-dec 42 KB took 1.033 seconds, 40.665 KB/s -SHA1 138 KB took 1.009 seconds, 136.727 KB/s -SHA256 128 KB took 1.010 seconds, 126.723 KB/s -SHA384 116 KB took 1.001 seconds, 115.833 KB/s -RSA 2048 key gen 9 ops took 17.497 sec, avg 1944.057 ms, 0.514 ops/sec -RSA 2048 Public 155 ops took 1.003 sec, avg 6.468 ms, 154.601 ops/sec -RSA 2048 Private 12 ops took 1.090 sec, avg 90.806 ms, 11.013 ops/sec -RSA 2048 Pub OAEP 122 ops took 1.004 sec, avg 8.230 ms, 121.501 ops/sec -RSA 2048 Priv OAEP 11 ops took 1.023 sec, avg 92.964 ms, 10.757 ops/sec -ECC 256 key gen 12 ops took 1.070 sec, avg 89.172 ms, 11.214 ops/sec -ECDSA 256 sign 40 ops took 1.010 sec, avg 25.251 ms, 39.602 ops/sec -ECDSA 256 verify 28 ops took 1.023 sec, avg 36.543 ms, 27.365 ops/sec -ECDHE 256 agree 16 ops took 1.062 sec, avg 66.391 ms, 15.062 ops/sec -``` +* [Post-Quantum](https://www.wolfssl.com/documentation/manuals/wolftpm/post-quantum.html): ML-DSA, ML-KEM, PQC TLS 1.3, and the SealSQ QVault +* [SPDM](https://www.wolfssl.com/documentation/manuals/wolftpm/spdm.html): encrypted TPM sessions over the TCG SPDM binding +* [Firmware TPM](https://www.wolfssl.com/documentation/manuals/wolftpm/fwtpm/overview.html): the wolfCrypt firmware TPM (overview, building, usage, HAL and porting, post-quantum, and SPDM) -Run on STMicro ST33TPHF2XSPI at 33MHz: +**Wrappers and integrations** -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 14 KB took 1.017 seconds, 13.763 KB/s -AES-128-CBC-enc 40 KB took 1.008 seconds, 39.666 KB/s -AES-128-CBC-dec 42 KB took 1.032 seconds, 40.711 KB/s -AES-256-CBC-enc 40 KB took 1.013 seconds, 39.496 KB/s -AES-256-CBC-dec 40 KB took 1.011 seconds, 39.563 KB/s -AES-128-CTR-enc 26 KB took 1.055 seconds, 24.646 KB/s -AES-128-CTR-dec 26 KB took 1.035 seconds, 25.117 KB/s -AES-256-CTR-enc 26 KB took 1.028 seconds, 25.302 KB/s -AES-256-CTR-dec 26 KB took 1.030 seconds, 25.252 KB/s -AES-128-CFB-enc 42 KB took 1.045 seconds, 40.201 KB/s -AES-128-CFB-dec 40 KB took 1.008 seconds, 39.699 KB/s -AES-256-CFB-enc 40 KB took 1.022 seconds, 39.151 KB/s -AES-256-CFB-dec 42 KB took 1.041 seconds, 40.362 KB/s -SHA1 86 KB took 1.005 seconds, 85.559 KB/s -SHA256 84 KB took 1.019 seconds, 82.467 KB/s -RSA 2048 key gen 1 ops took 7.455 sec, avg 7455.036 ms, 0.134 ops/sec -RSA 2048 Public 110 ops took 1.003 sec, avg 9.122 ms, 109.624 ops/sec -RSA 2048 Private 5 ops took 1.239 sec, avg 247.752 ms, 4.036 ops/sec -RSA 2048 Pub OAEP 81 ops took 1.001 sec, avg 12.364 ms, 80.880 ops/sec -RSA 2048 Priv OAEP 4 ops took 1.007 sec, avg 251.780 ms, 3.972 ops/sec -ECC 256 key gen 5 ops took 1.099 sec, avg 219.770 ms, 4.550 ops/sec -ECDSA 256 sign 24 ops took 1.016 sec, avg 42.338 ms, 23.619 ops/sec -ECDSA 256 verify 14 ops took 1.036 sec, avg 74.026 ms, 13.509 ops/sec -ECDHE 256 agree 5 ops took 1.235 sec, avg 247.085 ms, 4.047 ops/sec +* [Rust Wrapper](https://www.wolfssl.com/documentation/manuals/wolftpm/rust-wrapper.html), [C# Wrapper](https://www.wolfssl.com/documentation/manuals/wolftpm/csharp-wrapper.html), [STM32Cube](https://www.wolfssl.com/documentation/manuals/wolftpm/stm32cube.html), [Embedded Integrations](https://www.wolfssl.com/documentation/manuals/wolftpm/embedded-integrations.html) -``` - -Run on Microchip ATTPM20 at 33MHz: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 2 KB took 1.867 seconds, 1.071 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -AES-128-CFB-enc 16 KB took 1.112 seconds, 14.383 KB/s -AES-128-CFB-dec 16 KB took 1.129 seconds, 14.166 KB/s -AES-256-CFB-enc 12 KB took 1.013 seconds, 11.845 KB/s -AES-256-CFB-dec 12 KB took 1.008 seconds, 11.909 KB/s -SHA1 22 KB took 1.009 seconds, 21.797 KB/s -SHA256 22 KB took 1.034 seconds, 21.270 KB/s -RSA 2048 key gen 3 ops took 15.828 sec, avg 5275.861 ms, 0.190 ops/sec -RSA 2048 Public 22 ops took 1.034 sec, avg 47.021 ms, 21.267 ops/sec -RSA 2048 Private 9 ops took 1.059 sec, avg 117.677 ms, 8.498 ops/sec -RSA 2048 Pub OAEP 21 ops took 1.007 sec, avg 47.959 ms, 20.851 ops/sec -RSA 2048 Priv OAEP 9 ops took 1.066 sec, avg 118.423 ms, 8.444 ops/sec -ECC 256 key gen 7 ops took 1.072 sec, avg 153.140 ms, 6.530 ops/sec -ECDSA 256 sign 18 ops took 1.056 sec, avg 58.674 ms, 17.043 ops/sec -ECDSA 256 verify 24 ops took 1.031 sec, avg 42.970 ms, 23.272 ops/sec -ECDHE 256 agree 16 ops took 1.023 sec, avg 63.934 ms, 15.641 ops/sec -``` - -Run on Nations Technologies Inc. Z32H330 TPM 2.0 module at 33MHz: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 12 KB took 1.065 seconds, 11.270 KB/s -AES-128-CBC-enc 48 KB took 1.026 seconds, 46.780 KB/s -AES-128-CBC-dec 48 KB took 1.039 seconds, 46.212 KB/s -AES-256-CBC-enc 48 KB took 1.035 seconds, 46.370 KB/s -AES-256-CBC-dec 48 KB took 1.025 seconds, 46.852 KB/s -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -AES-128-CFB-enc 50 KB took 1.029 seconds, 48.591 KB/s -AES-128-CFB-dec 50 KB took 1.035 seconds, 48.294 KB/s -AES-256-CFB-enc 48 KB took 1.000 seconds, 47.982 KB/s -AES-256-CFB-dec 48 KB took 1.003 seconds, 47.855 KB/s -SHA1 80 KB took 1.009 seconds, 79.248 KB/s -SHA256 80 KB took 1.004 seconds, 79.702 KB/s -SHA384 78 KB took 1.018 seconds, 76.639 KB/s -RSA 2048 key gen 8 ops took 17.471 sec, avg 2183.823 ms, 0.458 ops/sec -RSA 2048 Public 52 ops took 1.004 sec, avg 19.303 ms, 51.805 ops/sec -RSA 2048 Private 8 ops took 1.066 sec, avg 133.243 ms, 7.505 ops/sec -RSA 2048 Pub OAEP 51 ops took 1.001 sec, avg 19.621 ms, 50.966 ops/sec -RSA 2048 Priv OAEP 8 ops took 1.073 sec, avg 134.182 ms, 7.453 ops/sec -ECC 256 key gen 20 ops took 1.037 sec, avg 51.871 ms, 19.279 ops/sec -ECDSA 256 sign 43 ops took 1.006 sec, avg 23.399 ms, 42.736 ops/sec -ECDSA 256 verify 28 ops took 1.030 sec, avg 36.785 ms, 27.185 ops/sec -ECDHE 256 agree 26 ops took 1.010 sec, avg 38.847 ms, 25.742 ops/sec -``` - -Run on Nations Technologies Inc. NS350 TPM 2.0 module at 33MHz: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's - Use Parameter Encryption: NULL -RNG 6 KB took 1.052 seconds, 5.703 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-128-CTR-enc not supported! -Benchmark symmetric AES-128-CTR-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -Encrypt/Decrypt unavailable -AES-128-CFB-enc 0 bytes took 0.005 seconds, 0.000 bytes/s -Encrypt/Decrypt unavailable -AES-128-CFB-dec 0 bytes took 0.006 seconds, 0.000 bytes/s -Encrypt/Decrypt unavailable -AES-256-CFB-enc 0 bytes took 0.006 seconds, 0.000 bytes/s -Encrypt/Decrypt unavailable -AES-256-CFB-dec 0 bytes took 0.005 seconds, 0.000 bytes/s -SHA1 68 KB took 1.003 seconds, 67.772 KB/s -SHA256 68 KB took 1.002 seconds, 67.871 KB/s -SHA384 66 KB took 1.007 seconds, 65.548 KB/s -RSA 2048 key gen 7 ops took 16.652 sec, avg 2378.893 ms, 0.420 ops/sec -RSA 2048 Public 126 ops took 1.005 sec, avg 7.980 ms, 125.321 ops/sec -RSA 2048 Private 20 ops took 1.035 sec, avg 51.735 ms, 19.329 ops/sec -RSA 2048 Pub OAEP 81 ops took 1.008 sec, avg 12.443 ms, 80.366 ops/sec -RSA 2048 Priv OAEP 19 ops took 1.027 sec, avg 54.033 ms, 18.507 ops/sec -ECC 256 key gen 20 ops took 1.042 sec, avg 52.095 ms, 19.196 ops/sec -ECDSA 256 sign 60 ops took 1.009 sec, avg 16.816 ms, 59.466 ops/sec -ECDSA 256 verify 46 ops took 1.008 sec, avg 21.921 ms, 45.618 ops/sec -ECDHE 256 agree 38 ops took 1.008 sec, avg 26.532 ms, 37.691 ops/sec -``` - -Run on Nuvoton NPCT650: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's -RNG 8 KB took 1.291 seconds, 6.197 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -Benchmark symmetric AES-256-CTR-enc not supported! -Benchmark symmetric AES-256-CTR-dec not supported! -Benchmark symmetric AES-256-CFB-enc not supported! -Benchmark symmetric AES-256-CFB-dec not supported! -SHA1 90 KB took 1.005 seconds, 89.530 KB/s -SHA256 90 KB took 1.010 seconds, 89.139 KB/s -RSA 2048 key gen 8 ops took 35.833 sec, avg 4479.152 ms, 0.223 ops/sec -RSA 2048 Public 77 ops took 1.007 sec, avg 13.078 ms, 76.463 ops/sec -RSA 2048 Private 2 ops took 1.082 sec, avg 540.926 ms, 1.849 ops/sec -RSA 2048 Pub OAEP 53 ops took 1.005 sec, avg 18.961 ms, 52.739 ops/sec -RSA 2048 Priv OAEP 2 ops took 1.088 sec, avg 544.075 ms, 1.838 ops/sec -ECC 256 key gen 7 ops took 1.033 sec, avg 147.608 ms, 6.775 ops/sec -ECDSA 256 sign 6 ops took 1.141 sec, avg 190.149 ms, 5.259 ops/sec -ECDSA 256 verify 4 ops took 1.061 sec, avg 265.216 ms, 3.771 ops/sec -ECDHE 256 agree 6 ops took 1.055 sec, avg 175.915 ms, 5.685 ops/sec -``` +**Reference** -Run on Nuvoton NPCT750 at 43MHz: - -``` -RNG 16 KB took 1.114 seconds, 14.368 KB/s -Benchmark symmetric AES-128-CBC-enc not supported! -Benchmark symmetric AES-128-CBC-dec not supported! -Benchmark symmetric AES-256-CBC-enc not supported! -Benchmark symmetric AES-256-CBC-dec not supported! -SHA1 120 KB took 1.012 seconds, 118.618 KB/s -SHA256 122 KB took 1.012 seconds, 120.551 KB/s -SHA384 120 KB took 1.003 seconds, 119.608 KB/s -RSA 2048 key gen 5 ops took 17.043 sec, avg 3408.678 ms, 0.293 ops/sec -RSA 2048 Public 134 ops took 1.004 sec, avg 7.490 ms, 133.517 ops/sec -RSA 2048 Private 15 ops took 1.054 sec, avg 70.261 ms, 14.233 ops/sec -RSA 2048 Pub OAEP 116 ops took 1.002 sec, avg 8.636 ms, 115.797 ops/sec -RSA 2048 Priv OAEP 15 ops took 1.061 sec, avg 70.716 ms, 14.141 ops/sec -ECC 256 key gen 12 ops took 1.008 sec, avg 84.020 ms, 11.902 ops/sec -ECDSA 256 sign 18 ops took 1.015 sec, avg 56.399 ms, 17.731 ops/sec -ECDSA 256 verify 26 ops took 1.018 sec, avg 39.164 ms, 25.533 ops/sec -ECDHE 256 agree 35 ops took 1.029 sec, avg 29.402 ms, 34.011 ops/sec -``` - -Run on the NVIDIA Jetson Orin (Tegra234) OP-TEE firmware TPM, via `/dev/tpmrm0`. -Jetson Linux R36.4.4, kernel 5.15.148-tegra, `MAXN_SUPER` power mode with all six -Cortex-A78AE cores at 1728 MHz: - -``` -./examples/bench/bench -TPM2 Benchmark using Wrapper API's - Use Parameter Encryption: NULL -Loading SRK: Storage 0x81000200 (282 bytes) -RNG 563 KB took 1.001 seconds, 562.277 KB/s -AES-128-CBC-enc 3 MB took 1.000 seconds, 2.798 MB/s -AES-128-CBC-dec 3 MB took 1.000 seconds, 2.780 MB/s -AES-256-CBC-enc 3 MB took 1.000 seconds, 2.898 MB/s -AES-256-CBC-dec 3 MB took 1.000 seconds, 2.888 MB/s -AES-128-CTR-enc 3 MB took 1.000 seconds, 2.910 MB/s -AES-128-CTR-dec 3 MB took 1.000 seconds, 2.762 MB/s -AES-256-CTR-enc 3 MB took 1.000 seconds, 2.764 MB/s -AES-256-CTR-dec 3 MB took 1.000 seconds, 2.730 MB/s -AES-128-CFB-enc 3 MB took 1.000 seconds, 2.752 MB/s -AES-128-CFB-dec 3 MB took 1.000 seconds, 2.688 MB/s -AES-256-CFB-enc 3 MB took 1.000 seconds, 2.881 MB/s -AES-256-CFB-dec 3 MB took 1.000 seconds, 2.830 MB/s -SHA1 2 MB took 1.000 seconds, 1.521 MB/s -SHA256 2 MB took 1.000 seconds, 1.572 MB/s -SHA384 2 MB took 1.000 seconds, 1.554 MB/s -SHA512 2 MB took 1.000 seconds, 1.569 MB/s -RSA 2048 key gen 21 ops took 15.465 sec, avg 736.433 ms, 1.358 ops/sec -RSA 2048 Public 1145 ops took 1.001 sec, avg 0.874 ms, 1144.407 ops/sec -RSA 2048 Private 85 ops took 1.012 sec, avg 11.900 ms, 84.033 ops/sec -RSA 2048 Pub OAEP 1086 ops took 1.000 sec, avg 0.921 ms, 1085.719 ops/sec -RSA 2048 Priv OAEP 84 ops took 1.002 sec, avg 11.934 ms, 83.793 ops/sec -ECC 256 key gen 9 ops took 1.081 sec, avg 120.163 ms, 8.322 ops/sec -ECDSA 256 sign 23 ops took 1.038 sec, avg 45.139 ms, 22.154 ops/sec -ECDSA 256 verify 32 ops took 1.016 sec, avg 31.737 ms, 31.509 ops/sec -ECDHE 256 agree 12 ops took 1.076 sec, avg 89.632 ms, 11.157 ops/sec -``` - -Unlike the discrete parts above, every operation the benchmark exercises is -supported, and the throughput figures are one to two orders of magnitude higher. -That is a property of where the TPM runs rather than of the TPM itself: the -firmware TPM executes on an application core with no serial bus in the path, -whereas a discrete part is a small microcontroller reached over SPI or I2C. The -comparison is useful for capacity planning, not as a security ranking - the -discrete parts are separate silicon with their own tamper boundary, while the -firmware TPM shares the SoC with the software it attests. See -[docs/DEVTPM.md](docs/DEVTPM.md#nvidia-jetson-orin-tegra234-firmware-tpm). - -### TPM2 Native Tests - -``` -./examples/native/native_test -TPM2 Demo using Native API's -TPM2: Caps 0x30000495, Did 0x0000, Vid 0x104a, Rid 0x4e -TPM2_Startup pass -TPM2_SelfTest pass -TPM2_GetTestResult: Size 12, Rc 0x0 -TPM2_IncrementalSelfTest: Rc 0x0, Alg 0x1 (Todo 0) -TPM2_GetCapability: Property FamilyIndicator 0x322e3000 -TPM2_GetCapability: Property PCR Count 24 -TPM2_GetCapability: Property FIRMWARE_VERSION_1 0x004a0008 -TPM2_GetCapability: Property FIRMWARE_VERSION_2 0x44a01587 -TPM2_GetRandom: Got 32 bytes -TPM2_StirRandom: success -TPM2_PCR_Read: Index 0, Count 1 -TPM2_PCR_Read: Index 0, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 1, Count 1 -TPM2_PCR_Read: Index 1, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 2, Count 1 -TPM2_PCR_Read: Index 2, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 3, Count 1 -TPM2_PCR_Read: Index 3, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 4, Count 1 -TPM2_PCR_Read: Index 4, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 5, Count 1 -TPM2_PCR_Read: Index 5, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 6, Count 1 -TPM2_PCR_Read: Index 6, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 7, Count 1 -TPM2_PCR_Read: Index 7, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 8, Count 1 -TPM2_PCR_Read: Index 8, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 9, Count 1 -TPM2_PCR_Read: Index 9, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 10, Count 1 -TPM2_PCR_Read: Index 10, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 11, Count 1 -TPM2_PCR_Read: Index 11, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 12, Count 1 -TPM2_PCR_Read: Index 12, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 13, Count 1 -TPM2_PCR_Read: Index 13, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 14, Count 1 -TPM2_PCR_Read: Index 14, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 15, Count 1 -TPM2_PCR_Read: Index 15, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 16, Count 1 -TPM2_PCR_Read: Index 16, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 17, Count 1 -TPM2_PCR_Read: Index 17, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 18, Count 1 -TPM2_PCR_Read: Index 18, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 19, Count 1 -TPM2_PCR_Read: Index 19, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 20, Count 1 -TPM2_PCR_Read: Index 20, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 21, Count 1 -TPM2_PCR_Read: Index 21, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 22, Count 1 -TPM2_PCR_Read: Index 22, Digest Sz 32, Update Counter 20 -TPM2_PCR_Read: Index 23, Count 1 -TPM2_PCR_Read: Index 23, Digest Sz 32, Update Counter 20 -TPM2_PCR_Extend success -TPM2_PCR_Read: Index 0, Count 1 -TPM2_PCR_Read: Index 0, Digest Sz 32, Update Counter 21 -TPM2_StartAuthSession: sessionHandle 0x3000000 -TPM2_PolicyGetDigest: size 32 -TPM2_PCR_Read: Index 0, Digest Sz 20, Update Counter 21 -wc_Hash of PCR[0]: size 32 -TPM2_PolicyPCR failed 0x1c4: TPM_RC_AUTHSIZE -TPM2_PolicyRestart: Done -TPM2_HashSequenceStart: sequenceHandle 0x80000000 -Hash SHA256 test success -TPM2_CreatePrimary: Endorsement 0x80000000 (314 bytes) -TPM2_CreatePrimary: Storage 0x80000002 (282 bytes) -TPM2_LoadExternal: 0x80000004 -TPM2_MakeCredential: credentialBlob 68, secret 256 -TPM2_ReadPublic Handle 0x80000004: pub 314, name 34, qualifiedName 34 -Create HMAC-SHA256 Key success, public 48, Private 137 -TPM2_Load New HMAC Key Handle 0x80000004 -TPM2_PolicyCommandCode: success -TPM2_ObjectChangeAuth: private 137 -TPM2_ECC_Parameters: CurveID 3, sz 256, p 32, a 32, b 32, gX 32, gY 32, n 32, h 1 -TPM2_Create: New ECDSA Key: pub 88, priv 126 -TPM2_Load ECDSA Key Handle 0x80000004 -TPM2_Sign: ECC S 32, R 32 -TPM2_VerifySignature: Tag 32802 -TPM2_Create: New ECDH Key: pub 88, priv 126 -TPM2_Load ECDH Key Handle 0x80000004 -TPM2_ECDH_KeyGen: zPt 68, pubPt 68 -TPM2_ECDH_ZGen: zPt 68 -TPM2 ECC Shared Secret Pass -TPM2_Create: New RSA Key: pub 278, priv 222 -TPM2_Load RSA Key Handle 0x80000004 -TPM2_RSA_Encrypt: 256 -TPM2_RSA_Decrypt: 68 -RSA Encrypt/Decrypt test passed -TPM2_NV_DefineSpace: 0x1bfffff -TPM2_NV_ReadPublic: Sz 14, Idx 0x1bfffff, nameAlg 11, Attr 0x2020002, authPol 0, dataSz 32, name 34 -Create AES128 CFB Key success, public 50, Private 142 -TPM2_Load New AES Key Handle 0x80000004 -Encrypt/Decrypt test success -``` - -### TPM2 CSR Example - -``` -./examples/csr/csr -TPM2 CSR Example -Generated/Signed Cert (DER 860, PEM 1236) ------BEGIN CERTIFICATE REQUEST----- -MIIDWDCCAkACAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP -BgNVBAcMCFBvcnRsYW5kMQ0wCwYDVQQEDARUZXN0MRAwDgYDVQQKDAd3b2xmU1NM -MQwwCgYDVQQLDANSU0ExGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG -SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBANtFRTX9CIW489vdmfy0qoffKtXBIfEGo07XgbvHPqk/KLx9NpK4 -fDLRdh5Kh7mDIGQI0hKDQMQ4GRTzRlE+wXlTqGQaQohac1LRxe21RCCKn0ZXvbCJ -Wd1cIAGQyDyOb8WYCquQB79r2pIAKnVbedu+G1jx3tVrwB8ZCosKF86au7cEDxvD -sdmt2vcEIlMcgfWQNo8TkWEKW33qu/rOOfJAUkVOUKENvj8zz/Iw4pX9nImiclMC -/pMcgjpnFUlG5a0Jwg2PR7pXyRYUCciMq20UF5LDZG3NmFirVqigOmBIFsrpVCjt -wf/Ep6DxFgmy7KNJ/0kzQByySvjKrIOqynsCAwEAAaB3MHUGCSqGSIb3DQEJDjFo -MGYwHQYDVR0OBBYEFBHIhJ44Ide+SKGpL2neKuusXBZxMEUGA1UdJQQ+MDwGCCsG -AQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYI -KwYBBQUHAwkwDQYJKoZIhvcNAQELBQADggEBACGHTZE5BVonf9OM3bYZvl2SiKdj -fo+f8a5COgBgCiNK8DPXCr+RMfp7jy8+3NP0bUPppi46F6Eq80YIZuQJgoyd0l8l -F+0KXq/FuoHtTLH7joHCKcYta1yPpnvKAG9195aIruAHesXwDxklqTvlVx3/e9No -YtmWUMdrLvTZrI1L1/0OuHbPgCGmdyHOXEh0xY0VTE1I0ff0b8UC3dQCsf8uROhO -fXXYwZz9LLSdO/QuDSxXThEe4m1/AUJkiaQ/T2zNEiR5Imk+jluXLz8bVM7w+HMt -l/076ekjTI+7PwzBZIG2F3nOIDUmHwe0lAWdU8h9IoAlM6kS22fh6gZZqQg= ------END CERTIFICATE REQUEST----- - -Generated/Signed Cert (DER 467, PEM 704) ------BEGIN CERTIFICATE REQUEST----- -MIIBzzCCAXUCAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP -BgNVBAcMCFBvcnRsYW5kMQ0wCwYDVQQEDARUZXN0MRAwDgYDVQQKDAd3b2xmU1NM -MQwwCgYDVQQLDANFQ0MxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG -SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH -A0IABIokJgsrMSW8f6si4S1saUXABXbqWKWVQn+D6z9LQe/wkPqozP/hV/3qTtpE -I/E3HjcHqRY+nsosjlEz36mzrRagdzB1BgkqhkiG9w0BCQ4xaDBmMB0GA1UdDgQW -BBRyZJhX+sHZEE117OKL0/CPVGbAKzBFBgNVHSUEPjA8BggrBgEFBQcDAQYIKwYB -BQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJMAoG -CCqGSM49BAMCA0gAMEUCIQCR9cbyRt3cbEZUIOBa4GNSRTlgFdB3X1EOwm+cA5/k -6AIgBm+EU6m5SDsk7BYmxTQAhgJFrelwymOa7m16kAXnFuU= ------END CERTIFICATE REQUEST----- -``` - -### TPM2 PKCS 7 Example - -``` -./examples/pkcs7/pkcs7 -TPM2 PKCS7 Example -PKCS7 Signed Container 1625 -PKCS7 Container Verified (using TPM) -PKCS7 Container Verified (using software) -``` - -### TPM TLS Client Example - -The wolfSSL TLS client requires loading a public key to indicate mutual authentication is used. The crypto callback uses the TPM for the private key signing. - -``` -./examples/tls/tls_client -TPM2 TLS Client Example -Write (29): GET /index.html HTTP/1.0 - - -Read (193): HTTP/1.1 200 OK -Content-Type: text/html -Connection: close - - - -Welcome to wolfSSL! - - -

wolfSSL has successfully performed handshake!

- - -``` - -### TPM TLS Server Example - -The wolfSSL TLS server loads the TPM public key and the crypto callback uses the TPM for the private key signing. - -``` -./examples/tls/tls_server -TPM2 TLS Server Example -Loading RSA certificate and public key -Read (29): GET /index.html HTTP/1.0 - - -Write (193): HTTP/1.1 200 OK -Content-Type: text/html -Connection: close - - - -Welcome to wolfSSL! - - -

wolfSSL has successfully performed handshake!

- - -``` - -### ST33 Firmware Update Example - -The firmware update example allows updating firmware on STMicro ST33 TPMs. Build with `--enable-st33 --enable-firmware` to enable this example. - -LMS (Leighton-Micali Signature) support is based on firmware version: -- **Firmware < 512**: Legacy firmware - Non-LMS format required -- **Firmware >= 512**: Modern firmware - LMS format required - -```bash -# Display firmware information -./examples/firmware/st33_fw_update - -# Cancel any in-progress firmware update -./examples/firmware/st33_fw_update --abandon - -# Perform firmware update (format auto-detected from TPM firmware version) -./examples/firmware/st33_fw_update -``` - -Example output: -``` -ST33 Firmware Update Tool -Mfg STM (2), Vendor ST33KTPM2X, Fw 9.512 (0x0) -Firmware version details: Major=9, Minor=512, Vendor=0x0 -Hardware: ST33K (modern firmware, Generation 2) -Firmware update: LMS format required -``` - -## Device Identity and Attestation Keys - -The TCG published a specification for TPM manufacture guidance on setting up keys that can be used for device identity and attestation. - -This feature has been tested with the ST33KTPM and is enabled with `WOLFTPM_MFG_IDENTITY`. The ST33KTPM samples are provisioned with a default master password enabled with `TEST_SAMPLE`. To define your own master password use `TPM2_IAK_SAMPLE_MASTER_PASSWORD`. The master password is hashed along with the device serial number to produce authentication for accessing these keys. - -The default keys are ECDSA SECP384R1 with SHA2-384 and stored in NV Index defined by `TPM2_IAK_KEY_HANDLE`, `TPM2_IAK_CERT_HANDLE`, `TPM2_IDEVID_KEY_HANDLE` and `TPM2_IDEVID_CERT_HANDLE`. - - -### TPM Endorsement Key Certificates - -The TCG EK Credential Profile defines how manufacturers provision endorsement certificates in the TCG NV index range (see TPM_20_TCG_NV_SPACE). -The `get_ek_certs` example shows how to retrieve those EK certificates, validate them and create a primary EK handle for signing. -See `./examples/endorsement/get_ek_certs`. - - -## Todo - -* Update to v1.59 of specification (adding CertifyX509). -* Inner wrap support for SensitiveToPrivate. -* Add support for IRQ (interrupt line) +* [API Reference](https://www.wolfssl.com/documentation/manuals/wolftpm/api-reference.html), [Testing](https://www.wolfssl.com/documentation/manuals/wolftpm/testing.html), [Benchmarks](https://www.wolfssl.com/documentation/manuals/wolftpm/benchmarks.html), [SBOM and Compliance](https://www.wolfssl.com/documentation/manuals/wolftpm/sbom-and-compliance.html), [Release Notes](https://www.wolfssl.com/documentation/manuals/wolftpm/release-notes.html) ## SBOM / EU CRA Compliance -wolfTPM generates a Software Bill of Materials (SBOM) in CycloneDX 1.6 and -SPDX 2.3 formats to support compliance with the EU Cyber Resilience Act (CRA). -The generator is the wolfGlass snapshot vendored in `tools/sbom/` and pinned by -`tools/sbom/.wolfglass-rev`. The SBOM records the configured build options -(from `wolftpm/options.h`), hashes the built `libwolftpm` library artifact -(shared or static; ELF, Mach-O, or PE), and lists wolfSSL as a dependency so -vulnerability scanners can associate wolfSSL advisories with a wolfTPM -deployment. Output is reproducible: set `SOURCE_DATE_EPOCH` (or build from a git -checkout, which uses the last commit time) and repeated runs are byte-identical. - -```sh -make sbom -``` - -Requires `python3` and `pyspdxtools` (`pip install spdx-tools`). The generator -ships in the tree, so `make sbom` does not need a separate wolfSSL checkout. -Pass `WOLFSSL_DIR=/path/to/wolfssl` when pkg-config cannot see the wolfSSL that -this build linked, so the dependency version is read from `wolfssl/version.h`. -`SBOM_WOLFSSL_VERSION` overrides that detection. - -The CMake build exposes the same target. `WOLFSSL_DIR` is optional and has the -same meaning: - -```sh -cmake -B build . -cmake --build build --target sbom -``` - -Output: `wolftpm-.cdx.json`, `wolftpm-.spdx.json`, `wolftpm-.spdx` - -Optional overrides: - -- `SBOM_LICENSE_OVERRIDE` - SPDX expression to use instead of the licence - parsed from `COPYING` (e.g. `LicenseRef-wolfSSL-Commercial` for commercial - licensees). Defaults to `GPL-3.0-or-later` (the per-file header licence). -- `SBOM_LICENSE_TEXT` - path to the licence text for any `LicenseRef-*` used in - `SBOM_LICENSE_OVERRIDE` (required by SPDX 2.3). -- `SBOM_WOLFSSL_VERSION` - version recorded for the wolfSSL dependency; - auto-detected from `WOLFSSL_DIR/wolfssl/version.h` (or wolfSSL's `pkg-config` - entry) when unset. - -```sh -make install-sbom # installs to $(datadir)/doc/wolftpm/ -make uninstall-sbom -``` - -For further CRA guidance see [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md). +wolfTPM generates a Software Bill of Materials (CycloneDX 1.6 and SPDX 2.3) for EU +Cyber Resilience Act (CRA) compliance, with `make sbom` or the CMake `sbom` target. +See the [SBOM and Compliance manual](https://www.wolfssl.com/documentation/manuals/wolftpm/sbom-and-compliance.html) +and [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md). ## Support diff --git a/docker/docs/Dockerfile b/docker/docs/Dockerfile new file mode 100644 index 00000000..aaed3fa5 --- /dev/null +++ b/docker/docs/Dockerfile @@ -0,0 +1,29 @@ +FROM python:3.12-slim-bookworm + +LABEL org.opencontainers.image.source="https://github.com/wolfSSL/wolfTPM" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + bash git make patch perl librsvg2-bin \ + doxygen build-essential cmake \ + libfmt-dev nlohmann-json3-dev libspdlog-dev libcxxopts-dev \ + pandoc texlive-xetex texlive-latex-extra texlive-fonts-recommended \ + texlive-lang-chinese texlive-lang-japanese \ + fonts-noto-core fonts-noto-mono fonts-noto-cjk lmodern \ + && rm -rf /var/lib/apt/lists/* + +# doxybook2 (wolfSSL fork) turns the Doxygen XML into the API-reference markdown. +# Both sources are pinned so this content-addressed image rebuilds identically. +RUN git clone --depth 1 --branch v3.5.0 https://github.com/pantor/inja /tmp/inja \ + && cmake -S /tmp/inja -B /tmp/inja/build -DBUILD_TESTING=OFF -DINJA_BUILD_TESTS=OFF \ + && cmake --install /tmp/inja/build \ + && git clone https://github.com/dgarske/doxybook2 /tmp/doxybook2 \ + && git -C /tmp/doxybook2 checkout d2edb6eda200f8e62d5f46553e5da1161a4f19b3 \ + && cmake -S /tmp/doxybook2 -B /tmp/doxybook2/build \ + && cmake --build /tmp/doxybook2/build --target install \ + && rm -rf /tmp/inja /tmp/doxybook2 + +COPY requirements.txt /tmp/requirements-docs.txt +RUN python -m pip install --no-cache-dir -r /tmp/requirements-docs.txt + +WORKDIR /work diff --git a/docker/docs/requirements.txt b/docker/docs/requirements.txt new file mode 100644 index 00000000..f2caded5 --- /dev/null +++ b/docker/docs/requirements.txt @@ -0,0 +1 @@ +mkdocs==1.6.1 diff --git a/docs/DEVTPM.md b/docs/DEVTPM.md index a9d7520d..e6691afe 100644 --- a/docs/DEVTPM.md +++ b/docs/DEVTPM.md @@ -1,173 +1,8 @@ # wolfTPM with the Linux Kernel TPM Device (/dev/tpmX) -On Linux the kernel's TPM driver stack exposes a TPM through a character device, and wolfTPM can use it directly instead of driving SPI or I2C itself. This is the right transport whenever the kernel already owns the TPM: a discrete chip bound to a kernel driver, a Windows-style firmware TPM, or a TEE-resident firmware TPM such as the one on NVIDIA Jetson platforms. +This page has moved into the wolfTPM manual. -With `--enable-devtpm` there is **no TIS layer and no HAL IO callback**: `hal/tpm_io.c` is compiled out entirely and `TPM2_IoCb` is `NULL` (see `hal/tpm_io.h`), so pass `NULL` for the callback argument of `TPM2_Init` / `wolfTPM2_Init`. +Read it here: -With `--enable-autodetect` this is **not** the case. The TIS/SPI HAL stays compiled in on purpose - it is the fallback - and `TPM2_IoCb` is a real function. Keep passing it, or the SPI fallback that build exists to provide is unreachable. - -## Two device nodes - -The kernel presents up to two nodes per TPM: - -* `/dev/tpm0` - the raw device. One user at a time, no resource management. Whatever you send reaches the TPM. -* `/dev/tpmrm0` - the in-kernel resource manager (kernel 4.12+, practical from 5.12+). It virtualizes handles, swaps transient objects and sessions in and out as needed, and flushes everything belonging to a connection when that connection closes. - -wolfTPM prefers `/dev/tpmrm0` and falls back to `/dev/tpm0`. The resource manager is the better default: a TPM has very few transient object slots, and without it a program that leaks a handle wedges the TPM for everything else on the system. - -Build-time overrides, honored by both `--enable-devtpm` and `--enable-autodetect`: - -* `-DWOLFTPM_USE_TPMRM` - use `/dev/tpmrm0` only, with no fallback to the raw device. -* `CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm1"'` - use a specific node. The inner quotes are required: the macro is used directly as a C string literal, so an unquoted value does not compile. - -## Startup, shutdown, and shared state - -The TPM is started by firmware long before Linux runs, and on the resource manager it is shared with every other process on the system. Restarting or shutting it down is therefore not an individual caller's decision, so wolfTPM stays out of the way on this transport: - -* `wolfTPM2_Init` skips the startup and self-test sequence. -* `wolfTPM2_Reset` and `wolfTPM2_Shutdown` send no TPM command and return `NOT_COMPILED_IN` (-174), the same way `wolfTPM2_SetLocality` does on this transport. A `wolfTPM2_Reset(dev, 0, 0)` that asked for neither a shutdown nor a startup still returns `TPM_RC_SUCCESS`, since nothing was declined. Treat `NOT_COMPILED_IN` here as "the OS owns this", not as a failure. -* `wolfTPM2_SetLocality` returns `NOT_COMPILED_IN` - the kernel owns the locality. - -Be aware that the kernel does **not** reliably stop you here. Command filtering on `/dev/tpmrm0` is primarily about handle isolation, not about blocking global state changes, and behavior varies by kernel version and TPM implementation. On Linux 5.15 with the Jetson OP-TEE fTPM, a `TPM2_Shutdown(TPM_SU_CLEAR)` sent through the resource manager is passed straight through and returns success - both from wolfTPM and from `tpm2_shutdown`. So this is a case where the library declining to send the command is what protects other users of the TPM, rather than the kernel doing it for you. - -If you genuinely need to control TPM startup state, you need `/dev/tpm0` and exclusive use of the TPM, or direct SPI access with wolfTPM's own TIS driver. - -## What the native API does on autodetect builds - -Two behaviors worth knowing if you use `TPM2_Init` / `TPM2_Init_ex` directly rather than the `wolfTPM2_*` wrapper. - -**The kernel device wins over your callback.** If `/dev/tpmrm0` or `/dev/tpm0` opens, every command is routed there and the HAL IO callback you passed is never invoked. On a host that has both a kernel-bound TPM and a discrete SPI part, that means you now talk to a different TPM than a pre-autodetect build did. Pin the part you want with `--enable-devtpm`, `--enable-spi` / `--enable-`, or `-DTPM2_LINUX_DEV`. - -**Init now acquires a descriptor.** `TPM2_Init*` opens the device on autodetect builds, and `TPM2_Cleanup()` is what closes it. Native callers that skipped cleanup previously leaked nothing; now they leak a descriptor per context. This matters most on hosts exposing only the raw `/dev/tpm0`, which permits a single open - a context that merely initialized holds the TPM exclusively for its lifetime, and a second context in the same process falls through to a different transport. - -`TPM2_Init_minimal()` is unaffected: it performs no IO and still succeeds with no device present. - -## Transient handles do not outlive a process - -This is the difference most likely to break an existing application. - -On `/dev/tpmrm0` the kernel gives each open file description its own handle space. Transient object handles are **virtualized** - the value the TPM assigned is not the value you get back - and everything in that space is **flushed when the file descriptor closes**. So a transient key created by one process is gone by the time a second process runs, and the handle number it printed is meaningless to anyone else. - -Creating a primary key on the Jetson fTPM through the resource manager returns: - -``` -Create Primary Handle: 0x80ffffff -``` - -not the `0x80000000` a raw device would report. Query the transient handles from a separate process afterwards and the list is empty: - -```bash -tpm2_getcap handles-transient # no output - the space was torn down -``` - -Two practical consequences: - -* A "create a key, keep it, use it from the next command" workflow does not work across processes. Do the whole sequence in one process, or make the object persistent with `TPM2_EvictControl` so it gets a stable `0x81xxxxxx` handle that does survive. -* Passing a hard-coded transient handle such as `0x80000000` on a command line will fail. The kernel rejects the reference before it reaches the TPM, and because that happens at the file-descriptor layer the error surfaces as an `errno 22 = Invalid argument` on `read()`, which wolfTPM reports as `TPM_RC_FAILURE` rather than as a handle error. If you see `TPM_RC_FAILURE` alongside `Failed to read from /dev/tpmrm0 ... errno 22`, suspect a stale or cross-process transient handle before suspecting the TPM. - -wolfTPM's own `examples/run_examples.sh` hits exactly this: its provisioning section creates IAK and IDevID primaries with `-keep` in one process and then references `0x80000000` / `0x80000001` from another. That block cannot pass on the resource manager by construction. Everything either side of it is unaffected. Use `/dev/tpm0` with exclusive access if you need to run it as written. - -## Building - -```bash -./autogen.sh -./configure --enable-devtpm -make -``` - -`--enable-devtpm` uses the kernel node only. Use `--enable-autodetect` instead if you want wolfTPM to try `/dev/tpmrm0`, then `/dev/tpm0`, and finally fall back to probing SPI - useful for one binary that has to run on several boards. - -Only one transport can be enabled at a time. `--enable-devtpm` conflicts with `--enable-swtpm` and `--enable-winapi`, and configure will stop if you ask for more than one. - -### The x86_64 / aarch64 default - -A bare `./configure` on Linux `x86_64` or `aarch64` does **not** produce a build that talks to `/dev/tpmX`. On those hosts wolfTPM auto-enables the software TPMs (swTPM and fwTPM) so that `make check` passes with no hardware attached, and defining `WOLFTPM_SWTPM` suppresses the kernel-device autodetect path. The result talks to a simulator on TCP port 2321. - -Selecting any hardware path explicitly turns that default back off - `--enable-autodetect`, `--enable-devtpm`, or any `--enable-`. Configure prints a notice when the software default is taken, so check the tail of its output if a build unexpectedly fails to find your TPM. - -This bites hardest on single-board `aarch64` machines with a firmware TPM, where the kernel device is the only transport there is. - -## Permissions - -The TPM character devices are not world-accessible. On a typical system they are mode `0660` owned by group `tss`: - -``` -crw-rw---- 1 tss root 10, 224 /dev/tpm0 -crw-rw---- 1 tss tss 252, 65536 /dev/tpmrm0 -``` - -wolfTPM detects `EACCES` and reports it plainly: - -``` -Permission denied on /dev/tpm0 -Use sudo or add tss group to user. -``` - -The fix is to put your user in the owning group and start a new login session: - -```bash -sudo usermod -aG tss $USER -``` - -Note that the `tss` group is created by tpm2-tss, and on distributions that ship it the group frequently exists with no members - so this step is required even though the group looks correctly set up. - -To use a group of your own instead, add a udev rule: - -1) Create the group and add your user: - -```bash -sudo addgroup wolftpm -sudo adduser [username] wolftpm -``` - -2) Create `/etc/udev/rules.d/wolftpm-udev.rules` containing: - -``` -KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", GROUP="wolftpm" -``` - -3) Reload the rules: `sudo udevadm control -R`, then re-plug or reboot. - -## NVIDIA Jetson Orin (Tegra234) firmware TPM - -Jetson Orin platforms carry a TPM 2.0 implemented in firmware, running as a trusted application inside OP-TEE rather than as a discrete package on a bus. Linux reaches it through the `tpm_ftpm_tee` driver, which speaks to the TA over the TEE interface and registers an ordinary TPM chip - so from wolfTPM's point of view it is just another `/dev/tpmrm0`. - -Confirm the device is present before building: - -```bash -lsmod | grep tpm_ftpm_tee -ls -l /dev/tpm* -cat /sys/class/tpm/tpm0/tpm_version_major # expect 2 -``` - -If the module is missing, try `sudo modprobe tpm_ftpm_tee` and check that the kernel was configured with `CONFIG_TCG_FTPM_TEE`. On NVIDIA's Jetson Linux (L4T) images the driver is present and an `fTPM Device Provisioning Service` systemd unit runs at boot; you can see it complete in the boot log. - -Note that an OP-TEE boot message about silicon-identity fTPM provisioning not being enabled refers to a separate NVIDIA feature and does **not** mean the TPM 2.0 device is unavailable. - -Build as above with `--enable-devtpm` or `--enable-autodetect`, then confirm with: - -```bash -./examples/wrap/caps -``` - -Because this is a firmware TPM, expect two differences from a discrete part. There is no TIS bus, so the `TPM2: Caps/Did/Vid/Rid` values do not exist and the device is identified purely from `TPM2_GetCapability` properties. Under `--enable-devtpm` the `DEBUG_WOLFTPM` line is still printed but reads all zeros; under `--enable-autodetect` `wolfTPM2_Init_ex` returns as soon as the kernel device opens, before that printf, so the line is absent entirely. And a firmware TPM's algorithm coverage is set by its firmware build rather than by a datasheet, so it is worth checking rather than assuming; where an operation is absent the benchmark reports it as unsupported rather than failing. The Jetson Orin fTPM supports every operation the benchmark exercises - see the README results. - -See the main [README.md](../README.md#device-identification) for this platform's identification values and benchmark results. - -## Testing - -The examples run unchanged on this transport: - -```bash -./examples/wrap/caps -./examples/native/native_test -./examples/wrap/wrap_test -./examples/bench/bench -./examples/run_examples.sh -``` - -`run_examples.sh` already skips the locality test on backends that do not support it. - -## CI coverage - -Both `--enable-devtpm` and `--enable-autodetect` are build-tested in CI, but not run - GitHub-hosted runners have no `/dev/tpm*` node. Runtime coverage of this transport requires a self-hosted runner with a real TPM bound to the kernel driver. +The Linux kernel device material is kept in the System Interfaces page, +[`docs/system-interfaces.md`](system-interfaces.md). diff --git a/docs/FWTPM.md b/docs/FWTPM.md index a88c3fce..275832a2 100644 --- a/docs/FWTPM.md +++ b/docs/FWTPM.md @@ -1,998 +1,8 @@ -# wolfTPM fwTPM (fTPM / swtpm) -- Firmware TPM 2.0 +# wolfTPM Firmware TPM (fwTPM) -## Overview +This page has moved into the wolfTPM manual. -The wolfTPM fwTPM (industry terms: fTPM, swtpm-compatible) is a portable firmware TPM 2.0 implementation built entirely -on wolfCrypt cryptographic primitives. It provides a standards-compliant TPM 2.0 -command processor as a standalone server process (`fwtpm_server`) implementing -105 of 113 commands from the TPM 2.0 v1.38 specification (93% coverage). The -fwTPM can replace a hardware TPM for: +Read it here: -- **Embedded/IoT platforms** without a discrete TPM chip (bare-metal via SPI/I2C TIS HAL) -- **Development and testing** of TPM-dependent applications (drop-in for swtpm or MS TPM simulator) -- **CI/CD pipelines** requiring TPM functionality (socket transport compatible with tpm2-tools) -- **Prototyping** TPM workflows before hardware is available - -### Architecture - -``` -+---------------------+ +---------------------------+ -| wolfTPM Client App | | fwtpm_server | -| (examples, tests) | | | -+----------+----------+ | +---------------------+ | - | | | fwtpm_command.c | | - TCP (SWTPM protocol) | | (command processor) | | - or TIS shared memory | +----------+----------+ | - | | | | -+----------v----------+ | +----------v----------+ | -| Transport Layer +--------->+ | wolfCrypt | | -| (socket or TIS HAL) | | | (RSA, ECC, SHA, | | -+---------------------+ | | HMAC, RNG, AES) | | - | +---------------------+ | - | | | - | +----------v----------+ | - | | fwtpm_nv.c | | - | | (persistent storage) | | - | +---------------------+ | - +---------------------------+ -``` - -**Components:** - -| File | Role | -|------|------| -| `fwtpm_command.c` | TPM 2.0 command processor and dispatch table (~9500 lines) | -| `fwtpm_io.c` | Transport layer -- SWTPM TCP socket protocol (default) | -| `fwtpm_nv.c` | NV storage -- file-based (default); HAL-abstracted, with a built-in append-only mode for write-once flash | -| `fwtpm_tis.c` | TIS register state machine (transport-agnostic) | -| `fwtpm_tis_shm.c` | POSIX shared memory + semaphore TIS transport | -| `fwtpm_main.c` | Server entry point, CLI argument parsing | -| `tpm2_util.c` | Shared utilities (hash helpers, ForceZero, PrintBin) | -| `tpm2_packet.c` | TPM packet marshaling/unmarshaling | -| `tpm2_param_enc.c` | Parameter encryption (XOR and AES session encryption) | - - -## Building - -### Prerequisites - -wolfSSL must be built with TPM support: - -```sh -cd wolfssl -./configure --enable-wolftpm --enable-pkcallbacks -make -sudo make install -``` - -### Build fwTPM Server - -**Socket transport (SWTPM protocol, default for development):** - -```sh -cd wolftpm -./configure --enable-fwtpm --enable-swtpm -make -``` - -This produces `src/fwtpm/fwtpm_server` and builds the wolfTPM client library -with `WOLFTPM_SWTPM` for socket-based communication. - -**TIS/shared-memory transport (for fwTPM HAL integration):** - -```sh -./configure --enable-fwtpm -make -``` - -When `--enable-swtpm` is omitted, the build uses TIS shared-memory transport -(`WOLFTPM_FWTPM_HAL`, `WOLFTPM_ADV_IO`) and compiles `fwtpm_tis.c` into the -server. - -**fwTPM server only (no client library or examples):** - -```sh -./configure --enable-fwtpm-only --enable-swtpm -make -``` - -This builds only the `fwtpm_server` binary, skipping `libwolftpm`, examples, -and tests. Useful for embedded targets that only need the TPM server. - -**Debug build:** - -```sh -./configure --enable-fwtpm --enable-swtpm --enable-debug -make -``` - -### Build Output - -| Artifact | Description | -|----------|-------------| -| `src/fwtpm/fwtpm_server` | Standalone fwTPM server binary | -| `src/.libs/libwolftpm.*` | wolfTPM client library | - -### Key Build Flags - -| Configure Option | Effect | -|-----------------|--------| -| `--enable-fwtpm` | Build `fwtpm_server` binary (alongside client library) | -| `--enable-fwtpm-only` | Build only `fwtpm_server` (no client library, examples, or tests) | -| `--enable-swtpm` | Use SWTPM TCP socket transport (ports 2321/2322) | -| `--enable-fwtpm-nv-appendonly` | Append-only NV journal for write-once flash ports (off by default) | -| `--enable-debug` | Enable debug logging | - -| Compile Define | Set By | -|---------------|--------| -| `WOLFTPM_FWTPM` | Automatically set for `fwtpm_server` target only | -| `WOLFTPM_SWTPM` | `--enable-swtpm` | -| `WOLFTPM_FWTPM_HAL` | `--enable-fwtpm` without `--enable-swtpm` | -| `WOLFTPM_FWTPM_TIS` | `--enable-fwtpm` without `--enable-swtpm` | -| `WOLFTPM_ADV_IO` | Set with `WOLFTPM_FWTPM_HAL` | -| `WOLFTPM_FWTPM_NV_APPEND_ONLY` | `--enable-fwtpm-nv-appendonly` (CMake `WOLFTPM_FWTPM_NV_APPEND_ONLY=yes`) | -| `WOLFTPM_FWTPM_TCG_TEST` | Manually (`CFLAGS=-DWOLFTPM_FWTPM_TCG_TEST`); off by default | - -No vendor commands are registered by default. Define `WOLFTPM_FWTPM_TCG_TEST` to compile in the optional `TPM2_Vendor_TCG_Test` (`0x20000000`) echo command. - -### Command-Code Enforcement - -A valid command code carries only the 16-bit index plus, for vendor commands, the V bit (`CC_VEND`, bit 29); codes with any other reserved bit set, or codes not in the dispatch table, are rejected with `TPM_RC_COMMAND_CODE`. `TPM2_GetCapability(TPM_CAP_COMMANDS)` returns proper `TPMA_CC` values (index + handle attributes + V bit, ordered by command code). - - -## Usage - -### Starting the Server - -```sh -./src/fwtpm/fwtpm_server [options] -``` - -**Options:** - -| Option | Description | -|--------|-------------| -| `--help`, `-h` | Show usage information | -| `--version`, `-v` | Print version string | -| `--port ` | Command port (default: 2321) | -| `--platform-port ` | Platform port (default: 2322) | - -**Example:** - -```sh -# Start with default ports -./src/fwtpm/fwtpm_server - -# Start on custom ports -./src/fwtpm/fwtpm_server --port 2331 --platform-port 2332 -``` - -The server prints its configuration on startup: - -``` -wolfTPM fwTPM Server v0.1.0 - Command port: 2321 - Platform port: 2322 - Manufacturer: WOLF - Model: fwTPM -``` - -In `--spdm-tcg` test mode the server also prints its generated responder -public key. This is a local test-harness convenience, not a provisioning or -trust-anchor channel for hardware responders. - -### Connecting wolfTPM Clients - -Any wolfTPM application built with `--enable-swtpm` connects to the fwTPM -server automatically via TCP: - -```sh -# In one terminal: start the server -./src/fwtpm/fwtpm_server - -# In another terminal: run wolfTPM examples -./examples/wrap/wrap_test -./examples/keygen/keygen keyblob.bin -rsa -t -./examples/attestation/make_credential -``` - -### NV Persistence - -The server stores persistent state (hierarchy seeds, auth values, PCR state, -NV indices) in `fwtpm_nv.bin` (configurable via `FWTPM_NV_FILE`). On first -start, seeds are randomly generated and saved. Subsequent starts reload -existing state. - -#### NV Storage HAL (embedded ports) - -NV access is abstracted behind `FWTPM_NV_HAL` (`read`/`write`/`erase`/`ctx`/ -`maxSize`/`get_integrity_key`). The default backend is the file above; an -embedded port supplies its own HAL and registers it before `FWTPM_Init()`. - -The journal is log-structured. On a byte-addressable backend (the file -default) it writes TLV entries at byte-granular offsets, rewrites the header in -place, and rewrites a trailing integrity MAC after every append. Internal flash -and NOR are write-once and program-granularity aligned, so they cannot service -in-place rewrites. Build with `--enable-fwtpm-nv-appendonly` -(`-DWOLFTPM_FWTPM_NV_APPEND_ONLY`) and set `appendOnly` and `writeAlign` on the -HAL; the journal then runs in append-only mode: the header is written only at -compaction, `writePos` is derived by scanning on load, and each commit is -sealed with an appended MAC-checkpoint entry padded up to `writeAlign`. The -existing `read`/`write`/`erase` HAL is the integration point - no separate -adapter. - -```c -/* Native flash HAL. In append-only mode the journal only ever calls write() - * with writeAlign-aligned, forward, into-erased bytes, so write() is a simple - * flash program; erase() erases the region (sector loop); read() reads raw. */ -FWTPM_NV_HAL hal; -XMEMSET(&hal, 0, sizeof(hal)); -hal.read = myRead; hal.write = myProgram; hal.erase = myErase; -hal.ctx = myCtx; hal.maxSize = NV_SIZE; -hal.appendOnly = 1; -hal.writeAlign = PROG_SIZE; /* flash word size, e.g. 16 (STM32H5) */ -hal.get_integrity_key = myDeviceSecret;/* recommended on flash */ -FWTPM_NV_SetHAL(&ctx, &hal); /* before FWTPM_Init() */ -``` - -In append-only mode the journal buffers a pending program granule internally and -flushes full, aligned granules through `write()`, so a programmed cell is never -rewritten and a whole sector is erased only on compaction. The header sector is -therefore not erased on every append, and a torn final commit (e.g. on power -loss) is ignored on the next load while all previously committed state survives. -A `get_integrity_key` callback is strongly recommended on flash so the MAC -checkpoints authenticate the journal and reject a torn or tampered tail. -`writeAlign <= 1` selects no buffering, so byte-writable NV (EEPROM/FRAM) works -with a plain `write()`. Compaction still erases the whole region before -rewriting, so a power loss during compaction itself remains a vulnerable window -(a future two-region ping-pong layout would close it). See -`src/fwtpm/ports/README.md` for the full porting guide. - - -## Supported TPM 2.0 Commands - -### Startup / Self-Test - -| Command | Description | -|---------|-------------| -| `TPM2_Startup` | Initialize TPM (SU_CLEAR or SU_STATE) | -| `TPM2_Shutdown` | Save state and prepare for power-off | -| `TPM2_SelfTest` | Execute full self-test | -| `TPM2_IncrementalSelfTest` | Incremental algorithm self-test | -| `TPM2_GetTestResult` | Return self-test result | - -### Random Number Generation - -| Command | Description | -|---------|-------------| -| `TPM2_GetRandom` | Generate random bytes (max 48 per call) | -| `TPM2_StirRandom` | Add entropy to RNG state | - -### Capability - -| Command | Description | -|---------|-------------| -| `TPM2_GetCapability` | Query TPM properties, algorithms, handles | - -### Key Management - -| Command | Description | -|---------|-------------| -| `TPM2_CreatePrimary` | Create primary key under a hierarchy | -| `TPM2_Create` | Create child key under a parent | -| `TPM2_CreateLoaded` | Create and load key in one command | -| `TPM2_Load` | Load key from private/public parts | -| `TPM2_LoadExternal` | Load external (software) key | -| `TPM2_Import` | Import externally wrapped key | -| `TPM2_Duplicate` | Export key for transfer (inner/outer wrapping) | -| `TPM2_Rewrap` | Re-wrap key under new parent (placeholder) | -| `TPM2_FlushContext` | Unload a transient object or session | -| `TPM2_ContextSave` | Save object/session context | -| `TPM2_ContextLoad` | Restore saved context | -| `TPM2_ReadPublic` | Read public area of a loaded key | -| `TPM2_ObjectChangeAuth` | Change authorization of a key | -| `TPM2_EvictControl` | Make transient key persistent (or remove) | -| `TPM2_HierarchyControl` | Enable or disable a hierarchy | -| `TPM2_HierarchyChangeAuth` | Change hierarchy authorization value | -| `TPM2_Clear` | Clear hierarchy (Owner or Platform) | -| `TPM2_ChangePPS` | Replace platform primary seed | -| `TPM2_ChangeEPS` | Replace endorsement primary seed | - -### Cryptographic Operations - -| Command | Description | -|---------|-------------| -| `TPM2_Sign` | Sign digest with loaded key | -| `TPM2_VerifySignature` | Verify signature against loaded key | -| `TPM2_RSA_Encrypt` | RSA encryption (OAEP, PKCS1) | -| `TPM2_RSA_Decrypt` | RSA decryption | -| `TPM2_EncryptDecrypt` | Symmetric encrypt/decrypt | -| `TPM2_EncryptDecrypt2` | Symmetric encrypt/decrypt (alternate) | -| `TPM2_Hash` | Single-shot hash computation | -| `TPM2_HMAC` | Single-shot HMAC computation | -| `TPM2_ECDH_KeyGen` | Generate ephemeral ECC key pair | -| `TPM2_ECDH_ZGen` | Compute ECDH shared secret | -| `TPM2_ECC_Parameters` | Get ECC curve parameters | -| `TPM2_TestParms` | Validate algorithm parameter support | - -### Hash Sequences - -| Command | Description | -|---------|-------------| -| `TPM2_HashSequenceStart` | Start a hash sequence | -| `TPM2_HMAC_Start` | Start an HMAC sequence | -| `TPM2_SequenceUpdate` | Add data to a hash/HMAC sequence | -| `TPM2_SequenceComplete` | Finalize hash/HMAC sequence and get result | -| `TPM2_EventSequenceComplete` | Finalize hash sequence and extend PCR | - -### Sealing - -| Command | Description | -|---------|-------------| -| `TPM2_Unseal` | Unseal data from a sealed object | - -### PCR (Platform Configuration Registers) - -| Command | Description | -|---------|-------------| -| `TPM2_PCR_Read` | Read PCR values | -| `TPM2_PCR_Extend` | Extend a PCR with a digest | -| `TPM2_PCR_Reset` | Reset a resettable PCR | - -### Clock - -| Command | Description | -|---------|-------------| -| `TPM2_ReadClock` | Read TPM clock values | -| `TPM2_ClockSet` | Set TPM clock | - -### Sessions and Authorization - -| Command | Description | -|---------|-------------| -| `TPM2_StartAuthSession` | Create HMAC, policy, or trial session | - -### Policy - -| Command | Description | -|---------|-------------| -| `TPM2_PolicyGetDigest` | Get current policy session digest | -| `TPM2_PolicyRestart` | Reset policy session digest | -| `TPM2_PolicyPCR` | Bind policy to PCR values | -| `TPM2_PolicyPassword` | Include password in policy | -| `TPM2_PolicyAuthValue` | Include auth value in policy | -| `TPM2_PolicyCommandCode` | Restrict policy to specific command | -| `TPM2_PolicyOR` | Logical OR of policy branches | -| `TPM2_PolicySecret` | Authorization with secret | -| `TPM2_PolicyAuthorize` | Approve policy with signing key | -| `TPM2_PolicyNV` | Policy based on NV index comparison | -| `TPM2_PolicyLocality` | Restrict policy to specific locality | -| `TPM2_PolicySigned` | Authorize policy with external signing key | - -### Dictionary Attack (DA) Protection - -| Command | Description | -|---------|-------------| -| `TPM2_DictionaryAttackParameters` | Set `maxTries`, `recoveryTime`, `lockoutRecovery` | -| `TPM2_DictionaryAttackLockReset` | Reset the failed-tries counter (lockoutAuth) | - -fwTPM follows the TPM 2.0 spec (Part 1 Sec.19.8). A failed authorization of a -DA-protected entity increments `failedTries`; once it reaches `maxTries` the TPM -returns `TPM_RC_LOCKOUT`. `failedTries` is persisted in NV on every failure, so -a power cycle cannot reset it. When a clock HAL is registered -(`FWTPM_Clock_SetHAL`) it self-heals one try per `recoveryTime` seconds, and a -non-orderly shutdown adds a one-try penalty; on clockless builds neither applies -(recovery is via `DictionaryAttackLockReset`/`Clear` only) so routine unclean -power-off cannot accumulate into lockout. A failed `lockoutAuth` locks the -lockout hierarchy: that lock persists across reboot and clears after -`lockoutRecovery` seconds, except when `lockoutRecovery` is 0 (reboot-only -recovery). Because the clock HAL reports milliseconds *since boot*, this timer -measures continuous post-boot uptime, not wall-clock time across reboots — a -device that reboots more often than `lockoutRecovery` extends its effective -recovery window. The lock only blocks commands authorized via `lockoutAuth` -(`DictionaryAttackLockReset`, `DictionaryAttackParameters`, lockout-authorized -`Clear`); the platform hierarchy is always an escape hatch — -`TPM2_ClearControl(platformAuth, clearDisable=NO)` then `TPM2_Clear(platformAuth)` -recovers even when `disableClear` was set. `Startup`/`Shutdown` are never -DA-gated, so a reboot in lockout can always recover. Entities marked `noDA` -(`TPMA_OBJECT_noDA` on objects, -`TPMA_NV_NO_DA` on NV indices) never feed the counter and stay usable during -lockout. `TPM2_GetCapability(TPM_CAP_TPM_PROPERTIES)` reports -`TPM_PT_MAX_AUTH_FAIL`, `TPM_PT_LOCKOUT_INTERVAL`, `TPM_PT_LOCKOUT_RECOVERY`, -`TPM_PT_LOCKOUT_COUNTER`, and the `inLockout` bit of `TPM_PT_PERMANENT`. - -Durable accounting writes the NV FLAGS entry on each DA-protected failure (and -on the first DA-protected auth use per boot). This is bounded per boot — the -lockout gate stops counting once locked — but on flash-backed targets it adds -wear and makes failed-auth latency NV-bound; size the NV backend accordingly. - -The first use of a DA-protected (non-`noDA`) authorization after startup makes a -real TPM persist a `daUsed` flag to NV and return `TPM_RC_RETRY` ("resubmit the -identical command") while it writes. Build with `FWTPM_DA_USED_RETRY` to emulate -this so clients exercise their resubmit/retry handling. It is off by default; -DA accounting and persistence are active regardless. Compile out all DA logic -with `FWTPM_NO_DA`. - -Coverage: DA/noDA/lockout/self-heal/persistence unit tests in -`tests/fwtpm_unit_tests.c`, the `examples/management/da_check` end-to-end example -(add `-lockout` for the destructive lockout/recovery path), and the -`tests/fwtpm_da_retry.sh` harness that exercises the `TPM_RC_RETRY` path against -a `FWTPM_DA_USED_RETRY` build. - -### NV RAM - -| Command | Description | -|---------|-------------| -| `TPM2_NV_DefineSpace` | Create an NV index | -| `TPM2_NV_UndefineSpace` | Delete an NV index | -| `TPM2_NV_ReadPublic` | Read NV index public metadata | -| `TPM2_NV_Write` | Write data to NV index | -| `TPM2_NV_Read` | Read data from NV index | -| `TPM2_NV_Extend` | Extend NV index (hash-extend) | -| `TPM2_NV_Increment` | Increment NV counter | -| `TPM2_NV_WriteLock` | Lock NV index for writes | -| `TPM2_NV_ReadLock` | Lock NV index for reads | -| `TPM2_NV_SetBits` | OR bits into NV bit field index | -| `TPM2_NV_ChangeAuth` | Change NV index authorization value | -| `TPM2_NV_Certify` | Certify NV index contents | - -### Attestation and Credentials - -| Command | Description | -|---------|-------------| -| `TPM2_Quote` | Generate signed PCR quote | -| `TPM2_Certify` | Certify a loaded key | -| `TPM2_CertifyCreation` | Prove key was created by this TPM | -| `TPM2_GetTime` | Signed attestation of TPM clock | -| `TPM2_MakeCredential` | Create credential blob for a key | -| `TPM2_ActivateCredential` | Unwrap credential blob | - - -## HAL Abstraction - -The fwTPM provides two hardware abstraction layers (HALs) for porting to -embedded targets without modifying core logic. - -### IO HAL (Transport) - -The IO HAL abstracts the transport between the fwTPM server and its clients. -The default implementation uses TCP sockets (SWTPM protocol). For embedded -targets, replace with SPI, I2C, UART, or shared memory callbacks. - -**Callback structure** (defined in `FWTPM_IO_HAL` in `fwtpm.h`): - -| Callback | Signature | Description | -|----------|-----------|-------------| -| `send` | `int (*)(void* ctx, const void* buf, int sz)` | Send data to client | -| `recv` | `int (*)(void* ctx, void* buf, int sz)` | Receive data from client | -| `wait` | `int (*)(void* ctx)` | Wait for data/connections. Returns bitmask: `0x01`=command data, `0x02`=platform data, `0x04`=new command connection, `0x08`=new platform connection | -| `accept` | `int (*)(void* ctx, int type)` | Accept new connection (type: 0=command, 1=platform) | -| `close_conn` | `void (*)(void* ctx, int type)` | Close connection (type: 0=command, 1=platform) | -| `ctx` | `void*` | User context pointer | - -**Registration:** - -```c -FWTPM_IO_HAL myHal; -myHal.send = my_send; -myHal.recv = my_recv; -myHal.wait = my_wait; -myHal.accept = my_accept; -myHal.close_conn = my_close; -myHal.ctx = &myTransportCtx; - -FWTPM_IO_SetHAL(&ctx, &myHal); -``` - -### NV HAL (Persistent Storage) - -The NV HAL abstracts persistent storage. The default implementation uses a -local file (`fwtpm_nv.bin`). For embedded targets, replace with flash, EEPROM, -or other non-volatile storage callbacks. - -**Callback structure** (defined in `FWTPM_NV_HAL` in `fwtpm.h`): - -| Callback | Signature | Description | -|----------|-----------|-------------| -| `read` | `int (*)(void* ctx, word32 offset, byte* buf, word32 size)` | Read from NV at offset | -| `write` | `int (*)(void* ctx, word32 offset, const byte* buf, word32 size)` | Write to NV at offset | -| `ctx` | `void*` | User context pointer | - -**Registration:** - -```c -FWTPM_NV_HAL myNvHal; -myNvHal.read = my_flash_read; -myNvHal.write = my_flash_write; -myNvHal.ctx = &myFlashCtx; - -FWTPM_NV_SetHAL(&ctx, &myNvHal); -``` - -### Porting Example - -For a bare-metal embedded target with SPI transport and SPI flash NV: - -```c -FWTPM_CTX ctx; -FWTPM_Init(&ctx); - -/* Set custom IO transport */ -FWTPM_IO_HAL ioHal = { - .send = spi_slave_send, - .recv = spi_slave_recv, - .wait = spi_slave_poll, - .accept = NULL, /* not connection-oriented */ - .close_conn = NULL, - .ctx = &spiHandle -}; -FWTPM_IO_SetHAL(&ctx, &ioHal); - -/* Set custom NV storage */ -FWTPM_NV_HAL nvHal = { - .read = spi_flash_read, - .write = spi_flash_write, - .ctx = &flashHandle -}; -FWTPM_NV_SetHAL(&ctx, &nvHal); - -/* Initialize IO and run */ -FWTPM_IO_Init(&ctx); -FWTPM_IO_ServerLoop(&ctx); /* blocks */ - -FWTPM_IO_Cleanup(&ctx); -FWTPM_Cleanup(&ctx); -``` - - -## Configuration Macros - -All macros are compile-time overridable (e.g., `-DFWTPM_MAX_OBJECTS=8`). - -| Macro | Default | Description | -|-------|---------|-------------| -| `FWTPM_MAX_COMMAND_SIZE` | 4096 | Maximum command/response buffer size (bytes) | -| `FWTPM_MAX_RANDOM_BYTES` | 48 | Maximum bytes per `GetRandom` call | -| `FWTPM_MAX_OBJECTS` | 16 | Maximum concurrently loaded transient objects | -| `FWTPM_MAX_PERSISTENT` | 8 | Maximum persistent objects (via `EvictControl`) | -| `FWTPM_MAX_PRIVKEY_DER` | 2048 | Maximum DER-encoded private key size (bytes) | -| `FWTPM_MAX_HASH_SEQ` | 4 | Maximum concurrent hash/HMAC sequences | -| `FWTPM_MAX_PRIMARY_CACHE` | 16 | Cached primary keys per hierarchy+template | -| `FWTPM_MAX_SESSIONS` | 8 | Maximum concurrent auth sessions | -| `FWTPM_MAX_NV_INDICES` | 16 | Maximum NV RAM index slots; omitted from `FWTPM_CTX` with `FWTPM_NO_NV` | -| `FWTPM_MAX_NV_DATA` | 2048 | Maximum data per NV index (bytes) | -| `FWTPM_DA_DEFAULT_MAX_TRIES` | 32 | DA failed-auth count before lockout | -| `FWTPM_DA_DEFAULT_RECOVERY` | 600 | DA self-heal interval (seconds per try) | -| `FWTPM_DA_DEFAULT_LOCKOUT_RECOVERY` | 86400 | lockoutAuth recovery time (seconds) | -| `FWTPM_DA_MAX_TRIES_LIMIT` | 0xFFFF | Upper clamp for a replayed `maxTries`/`failedTries` | -| `FWTPM_MAX_DATA_BUF` | 1024 | Internal buffer for HMAC, hash, general data | -| `FWTPM_MAX_PUB_BUF` | 512 | Internal buffer for public area, signatures | -| `FWTPM_MAX_DER_SIG_BUF` | 256 | Internal buffer for DER signatures, ECC points | -| `FWTPM_MAX_ATTEST_BUF` | 1024 | Internal buffer for attestation marshaling | -| `FWTPM_MAX_CMD_AUTHS` | 3 | Maximum authorization sessions per command (TPM-spec hard cap) | -| `FWTPM_MAX_SENSITIVE_SIZE` | `FWTPM_MAX_PRIVKEY_DER + 128` | Maximum marshaled sensitive area (private key + auth + nonce headroom) | -| `FWTPM_MAX_SIGN_SEQ` | 4 | Maximum concurrent v1.85 PQC sign/verify sequences | -| `FWTPM_MAX_SYM_KEY_SIZE` | 32 | Symmetric key buffer (sized for AES-256) | -| `FWTPM_MAX_HMAC_KEY_SIZE` | 64 | HMAC key buffer (sized for SHA-512 block) | -| `FWTPM_MAX_HMAC_DIGEST_SIZE` | 64 | HMAC output buffer (sized for SHA-512) | -| `FWTPM_CMD_PORT` | 2321 | Default TCP command port | -| `FWTPM_PLAT_PORT` | 2322 | Default TCP platform port | -| `FWTPM_NV_FILE` | `"fwtpm_nv.bin"` | Default NV storage file path | -| `FWTPM_NV_MAX_WRITE_ALIGN` | 64 | Max append-only program granule in bytes (upper bound on a HAL's `writeAlign`); sizes the pending-granule buffer when `WOLFTPM_FWTPM_NV_APPEND_ONLY` is set | -| `FWTPM_PCR_BANKS` | 2 | Number of PCR banks (SHA-256 + SHA-384) | -| `FWTPM_TIS_BURST_COUNT` | 64 | TIS FIFO burst count (bytes per transfer) | -| `FWTPM_TIS_FIFO_SIZE` | 4096 | TIS command/response FIFO size | - -### Stack/Heap Control - -| Macro | Effect | -|-------|--------| -| `WOLFTPM_SMALL_STACK` | Use heap allocation for large stack objects | -| `WOLFTPM2_NO_HEAP` | Forbid heap allocation (all stack) | - -Note: `WOLFTPM_SMALL_STACK` and `WOLFTPM2_NO_HEAP` are mutually exclusive and -will produce a compile error if both are defined. - -### v1.85 Embedded RAM Impact - -Enabling `--enable-pqc` (or `--enable-v185`) lifts several internal buffers -to accommodate PQC key/signature sizes. The defaults **auto-shrink at compile -time** based on -which ML-DSA / ML-KEM parameter sets wolfCrypt was actually built with -(`WOLFSSL_NO_ML_DSA_44/65/87`, `WOLFSSL_NO_KYBER512/768/1024`) — boards -that only enable the smaller params get smaller buffers automatically, no -per-board override required. - -**Buffer sizes by enabled parameter set:** - -| Macro | Classical | MLDSA-44 + MLKEM-512 | MLDSA-65 + MLKEM-768 | MLDSA-87 + MLKEM-1024 | -|-------|-----------|----------------------|----------------------|------------------------| -| `FWTPM_TIS_FIFO_SIZE` | 4096 | 4096 | 8192 | 8192 | -| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 4096 | 8192 | 8192 | -| `FWTPM_MAX_PUB_BUF` | 512 | 1440 | 2080 | 2720 | -| `FWTPM_MAX_DER_SIG_BUF` | 256 | 2548 | 3437 | 4755 | -| `FWTPM_MAX_KEM_CT_BUF` | n/a | 832 | 1152 | 1632 | - -Sizing logic lives in `wolftpm/fwtpm/fwtpm.h` (constants -`FWTPM_MAX_MLDSA_SIG_SIZE`, `FWTPM_MAX_MLDSA_PUB_SIZE`, -`FWTPM_MAX_MLKEM_CT_SIZE`, `FWTPM_MAX_MLKEM_PUB_SIZE`) and -`wolftpm/fwtpm/fwtpm_tis.h` (FIFO size). The MLDSA constants come from -wolfCrypt's `WC_MLDSA_{44,65,87}_*_SIZE` macros; the MLKEM constants -are FIPS 203 spec values (wolfCrypt's `WC_ML_KEM_*_SIZE` macros aren't -preprocessor-evaluable). - -The 8192 lifts on FIFO/command buffers only kick in when MLDSA-65 or -MLDSA-87 is enabled (their signatures don't fit a 4096 response with -TPM headers). MLDSA-44-only and MLKEM-only v1.85 builds stay at 4096. - -**Per-deployment override:** every macro above is still `#ifndef`-guarded, -so a board can override individually on the compile line if the auto -default is wrong for its workload (e.g. `-DFWTPM_TIS_FIFO_SIZE=2048`). - -**Heap-vs-stack:** building with `WOLFTPM_SMALL_STACK` moves the large -per-call buffers off the stack into `XMALLOC`/`XFREE` regions. The PQC -paths already use `FWTPM_DECLARE_BUF` / `FWTPM_ALLOC_BUF` which respect -this flag, so no source changes are required. `WOLFTPM2_NO_HEAP` is -supported but pays full stack cost — pair it with the smallest PQC -parameter set you can. - -### Algorithm Feature Macros - -These macros use wolfCrypt's existing compile-time options to control which -cryptographic algorithms are available in fwtpm_server. If an algorithm is -disabled, the corresponding TPM commands are excluded from the build. - -| Macro | Default | Effect | -|-------|---------|--------| -| `NO_RSA` | not defined | Excludes RSA keygen, sign, verify, `RSA_Encrypt`, `RSA_Decrypt` | -| `HAVE_ECC` | defined | Enables ECC keygen, sign, verify, `ECDH_KeyGen`, `ECDH_ZGen`, `ECC_Parameters` | -| `HAVE_ECC384` | defined | Enables P-384 curve support | -| `HAVE_ECC521` or `HAVE_ALL_CURVES` | build-dependent | Enables P-521 when `MAX_ECC_KEY_BITS >= 521` provides 66-byte TPM ECC fields | -| `ECC_MIN_KEY_SZ` | wolfCrypt-defined | Excludes smaller curves from `ECC_Parameters` and `TPM_CAP_ECC_CURVES` | -| `NO_AES` | not defined | Excludes `EncryptDecrypt`, `EncryptDecrypt2`, AES parameter encryption | -| `WOLFSSL_SHA384` | defined | Enables SHA-384 PCR bank | - -When an algorithm is disabled, commands that exclusively use that algorithm -are removed from the dispatch table at compile time. Commands that support -multiple algorithms (e.g., `CreatePrimary`, `Sign`) remain available but -return `TPM_RC_ASYMMETRIC` for the disabled algorithm type. - -### TPM Feature Group Macros - -These fwTPM-specific macros disable entire groups of TPM 2.0 functionality -to reduce code size on constrained targets. - -| Macro | Default | Commands Excluded | -|-------|---------|-------------------| -| `FWTPM_NO_ATTESTATION` | not defined | `Quote`, `Certify`, `CertifyCreation`, `GetTime`, `NV_Certify` | -| `FWTPM_NO_NV` | not defined | `NV_DefineSpace`, `NV_UndefineSpace`, `NV_ReadPublic`, `NV_Write`, `NV_Read`, `NV_Extend`, `NV_Increment`, `NV_WriteLock`, `NV_ReadLock`, `NV_Certify`; also removes the in-memory NV index slots from `FWTPM_CTX` | -| `FWTPM_NO_POLICY` | not defined | `PolicyGetDigest`, `PolicyRestart`, `PolicyPCR`, `PolicyPassword`, `PolicyAuthValue`, `PolicyCommandCode`, `PolicyOR`, `PolicySecret`, `PolicyAuthorize`, `PolicyNV` | -| `FWTPM_NO_CREDENTIAL` | not defined | `MakeCredential`, `ActivateCredential` | -| `FWTPM_NO_DA` | not defined | `DictionaryAttackParameters`, `DictionaryAttackLockReset`, and all lockout accounting | -| `FWTPM_NO_PARAM_ENC` | not defined | command/response parameter (XOR/AES-CFB) encryption support in sessions | -| `FWTPM_NO_KEY_MIGRATION` | not defined | `Import`, `Duplicate`, `Rewrap` | -| `FWTPM_NO_ECDH` | not defined | `ECDH_KeyGen`, `ECDH_ZGen`, `EC_Ephemeral`, `ZGen_2Phase`, `ECC_Parameters` (ECDSA sign/verify retained), plus the `ecEphemeral*` commit state in `FWTPM_CTX` | -| `FWTPM_NO_HASH_CMDS` | not defined | `Hash`, `HMAC`, `HMAC_Start`, `HashSequenceStart`, `SequenceUpdate`, `SequenceComplete`, `EventSequenceComplete`, and the `FWTPM_CTX` hash-sequence slots | -| `FWTPM_NO_CONTEXT` | not defined | `ContextSave`, `ContextLoad` (`FlushContext` retained), plus the per-boot context protection key and saved-context replay list in `FWTPM_CTX` | -| `FWTPM_NO_SYM_ENCRYPT` | not defined | `EncryptDecrypt`, `EncryptDecrypt2` | -| `FWTPM_NO_CLOCK` | not defined | `ReadClock`, `ClockSet`, `ClockRateAdjust` | - -Removing a command group also removes it from the `TPM2_GetCapability(TPM_CAP_COMMANDS)` advertisement and the `TPM_PT_TOTAL_COMMANDS` count, since both are derived from the dispatch table. Note: when `WOLFTPM_MLDSA` is built, `SequenceUpdate` alone is retained under `FWTPM_NO_HASH_CMDS`, because ML-DSA verify sequences stream their message through it. `SequenceComplete` is not shared -- ML-DSA sequences finalize through `TPM2_SignSequenceComplete` / `TPM2_VerifySequenceComplete` -- so it is gated out with the rest of the hash commands rather than advertised as a command that can never succeed. - -The `FWTPM_DA_USED_RETRY` macro (off by default) does not remove commands; it -makes the server return `TPM_RC_RETRY` on the first DA-protected auth use after -startup, emulating a real TPM persisting `daUsed`. See -[Dictionary Attack (DA) Protection](#dictionary-attack-da-protection). - -**Minimal build example.** There is no umbrella macro - select the command -groups to drop explicitly, so each is a deliberate choice. For example, to build -a small ECC-only signing + NV fTPM (this set drops attestation; keep -`Sign`/`VerifySignature`, PCR, and NV): - -```sh -./configure --enable-fwtpm --enable-swtpm \ - CFLAGS="-DNO_RSA \ - -DFWTPM_NO_POLICY -DFWTPM_NO_ATTESTATION -DFWTPM_NO_CREDENTIAL \ - -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC -DFWTPM_NO_KEY_MIGRATION \ - -DFWTPM_NO_ECDH -DFWTPM_NO_HASH_CMDS -DFWTPM_NO_CONTEXT \ - -DFWTPM_NO_SYM_ENCRYPT -DFWTPM_NO_CLOCK" -``` - -That set retains a core fTPM: `Startup`, `Shutdown`, `SelfTest`, `GetRandom`, -`GetCapability`, the `PCR_*` commands, `Create`/`CreatePrimary`/`Load`/ -`ReadPublic`/`FlushContext`, `Sign`/`VerifySignature`, the `NV_*` commands, and -session support (`StartAuthSession`/`Unseal`). Add `-DFWTPM_NO_NV` to also drop -NV, or drop any `-DFWTPM_NO_*` above to keep that group. This ECC-only build is -small enough to run as a soft-core fTPM on a constrained FPGA (see the MicroBlaze -V example in the `wolftpm-examples` repo, which fits an ECC-only fTPM into -~192 KB of on-chip memory). - -**Dependencies:** -- `FWTPM_NO_NV` also removes `NV_Certify` (even if `FWTPM_NO_ATTESTATION` is not set) -- `NO_RSA` implies no RSA attestation signatures (ECC-only attestation still works with `HAVE_ECC`) - - -## Transport Modes - -### Socket / SWTPM (Default) - -Built with `--enable-fwtpm --enable-swtpm`. The server listens on two TCP -ports using the SWTPM wire protocol: - -- **Command port** (default 2321): TPM command/response traffic -- **Platform port** (default 2322): Platform signals (power on/off, NV on, cancel, reset, session end, stop) - -**SWTPM TCP protocol commands** (platform port): - -| Signal | Value | Description | -|--------|-------|-------------| -| `SIGNAL_POWER_ON` | 1 | Power on the TPM | -| `SIGNAL_POWER_OFF` | 2 | Power off the TPM | -| `SIGNAL_PHYS_PRES_ON` | 3 | Assert physical presence | -| `SIGNAL_PHYS_PRES_OFF` | 4 | Deassert physical presence | -| `SIGNAL_HASH_START` | 5 | Start measured boot hash | -| `SIGNAL_HASH_DATA` | 6 | Provide measured boot data | -| `SIGNAL_HASH_END` | 9 | End measured boot hash | -| `SEND_COMMAND` | 8 | Send TPM command (command port) | -| `SIGNAL_NV_ON` | 11 | NV storage available | -| `SIGNAL_CANCEL_ON` | 13 | Cancel current command | -| `SIGNAL_CANCEL_OFF` | 14 | Clear cancel | -| `SIGNAL_RESET` | 17 | Reset TPM | -| `SESSION_END` | 20 | End TCP session | -| `STOP` | 21 | Stop server | - -wolfTPM clients connect using the standard SWTPM interface, compatible with -`tpm2-tools` and other SWTPM-aware software. - -### TIS / Shared Memory - -Built with `--enable-fwtpm` (without `--enable-swtpm`). Uses POSIX shared -memory and named semaphores to emulate TIS (TPM Interface Specification) -register-level access. This mode simulates an SPI-attached TPM. - -**Shared memory layout** (`FWTPM_TIS_SHM`): - -| Field | Description | -|-------|-------------| -| `magic` / `version` | Validation header (`0x57544953` / `"WTIS"`, protocol version 2) | -| `reg_addr`, `reg_len`, `reg_is_write`, `reg_data` | Register access request | -| TIS register shadow: `access`, `sts`, `int_enable`, `int_status`, `intf_caps`, `did_vid`, `rid` | Emulated TIS registers | -| `cmd_buf[4096]`, `cmd_len`, `fifo_write_pos` | Command FIFO | -| `rsp_buf[4096]`, `rsp_len`, `fifo_read_pos` | Response FIFO | - -**Paths** (compile-time configurable): - -| Define | Default | Description | -|--------|---------|-------------| -| `FWTPM_TIS_SHM_PATH` | `/tmp/fwtpm.shm` | Shared memory file; clients require a regular, single-link, same-UID, exact-size `0600` endpoint | -| `FWTPM_TIS_SEM_CMD` | `/fwtpm_cmd` | Command semaphore name | -| `FWTPM_TIS_SEM_RSP` | `/fwtpm_rsp` | Response semaphore name | - -Clients require an exact protocol version and shared-region-size match, so -rebuild the client library and `fwtpm_server` together when changing options -that affect `FWTPM_TIS_FIFO_SIZE`. The default paths are global, so one server -per host. - -**Server-side API:** - -- `FWTPM_TIS_Init()` -- Create shared memory and semaphores -- `FWTPM_TIS_Cleanup()` -- Remove shared memory and semaphores -- `FWTPM_TIS_ServerLoop()` -- Process TIS register accesses, dispatch commands - -**Client-side API** (enabled by `WOLFTPM_FWTPM_HAL`): - -- `FWTPM_TIS_ClientConnect()` -- Attach to existing shared memory -- `FWTPM_TIS_ClientDisconnect()` -- Detach from shared memory - - -## Testing - -See [src/fwtpm/README.md](../src/fwtpm/README.md) for the full CI test matrix -and test script usage. Quick reference: - -```sh -make check # Build + unit.test + run_examples.sh + tpm2-tools -scripts/tpm2_tools_test.sh # tpm2-tools only (311 tests) -``` - -`make check` runs `tests/fwtpm_check.sh`, which starts and stops -`fwtpm_server` automatically -- do not start it manually. - - -## API Reference - -### Core (`fwtpm.h`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_Init(FWTPM_CTX* ctx)` | Initialize fwTPM context, RNG, load NV state | -| `int FWTPM_Cleanup(FWTPM_CTX* ctx)` | Save NV, free resources, zero sensitive data | -| `const char* FWTPM_GetVersionString(void)` | Return version string (e.g., `"0.1.0"`) | - -### Command Processor (`fwtpm_command.h`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_ProcessCommand(FWTPM_CTX* ctx, const byte* cmdBuf, int cmdSize, byte* rspBuf, int* rspSize, int locality)` | Process a raw TPM command packet and produce a response. Returns `TPM_RC_SUCCESS` on successful processing; the response buffer may contain a TPM error RC. | - -### IO Transport (`fwtpm_io.h`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_IO_SetHAL(FWTPM_CTX* ctx, FWTPM_IO_HAL* hal)` | Register custom IO transport callbacks | -| `int FWTPM_IO_Init(FWTPM_CTX* ctx)` | Initialize transport (sockets or custom HAL) | -| `void FWTPM_IO_Cleanup(FWTPM_CTX* ctx)` | Close transport and release resources | -| `int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)` | Main server loop -- blocks until `ctx->running` is cleared | - -### NV Storage (`fwtpm_nv.h`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_NV_Init(FWTPM_CTX* ctx)` | Load NV state from storage or create new (generates seeds) | -| `int FWTPM_NV_Save(FWTPM_CTX* ctx)` | Save current TPM state to NV storage | -| `int FWTPM_NV_SetHAL(FWTPM_CTX* ctx, FWTPM_NV_HAL* hal)` | Register custom NV storage callbacks | - -### TIS Server (`fwtpm_tis.h`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_TIS_Init(FWTPM_CTX* ctx)` | Create shared memory region and semaphores | -| `void FWTPM_TIS_Cleanup(FWTPM_CTX* ctx)` | Unlink shared memory and semaphores | -| `int FWTPM_TIS_ServerLoop(FWTPM_CTX* ctx)` | Process TIS register accesses (blocks) | - -### TIS Client (`fwtpm_tis.h`, requires `WOLFTPM_FWTPM_HAL`) - -| Function | Description | -|----------|-------------| -| `int FWTPM_TIS_ClientConnect(FWTPM_TIS_CLIENT_CTX* client)` | Attach to fwTPM shared memory | -| `void FWTPM_TIS_ClientDisconnect(FWTPM_TIS_CLIENT_CTX* client)` | Detach from shared memory | - - -## Startup / Shutdown Lifecycle - -1. **First boot:** `FWTPM_NV_Init` finds no NV file, generates random hierarchy - seeds, saves initial state. -2. **`TPM2_Startup(SU_CLEAR)`:** Flushes transient objects and sessions, resets - PCRs. Required before any other TPM command. -3. **Normal operation:** Commands are processed via `FWTPM_ProcessCommand`. -4. **`TPM2_Shutdown`:** Saves NV state but does NOT clear the "started" flag. - The TPM remains logically powered on. -5. **Server restart** (process exit and relaunch) constitutes a power cycle. - Only after a power cycle can `TPM2_Startup` be called again. - -Calling `TPM2_Startup` on an already-started TPM returns `TPM_RC_INITIALIZE`. - - -## Primary Key Derivation - -Primary keys are deterministically derived from the hierarchy seed per TPM 2.0 -Part 1 Section 26. The same seed + same template always produces the same key: - -- **RSA**: Primes p, q derived via iterative KDFa with labels `"RSA p"` / `"RSA q"`, - primality testing, then CRT computation -- **ECC**: Private scalar d derived via `KDFa(nameAlg, seed, "ECC", hashUnique, counter)`, - public point Q = d*G -- **KEYEDHASH/SYMCIPHER**: Key bytes derived via `KDFa(nameAlg, seed, label, hashUnique)` -- **hashUnique**: `H(sensitiveCreate.data || inPublic.unique)` per Section 26.1 - -A primary key cache (SHA-256 of template, `FWTPM_MAX_PRIMARY_CACHE` slots) avoids -re-deriving expensive RSA keys on repeated `CreatePrimary` calls. - -Hierarchy seeds are managed by `ChangePPS` (platform) and `ChangeEPS` (endorsement). -`Clear` regenerates owner and endorsement seeds. The null seed is re-randomized on -every `Startup(CLEAR)`. - - -## TPM 2.0 v1.85 Post-Quantum Support - -Enabled with `--enable-pqc` (alias `--enable-v185`) at configure time, or -auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has -both ML-DSA and ML-KEM available. Both flags set the internal -`WOLFTPM_V185` macro that gates the implementation. Pass `--disable-pqc` -to opt out when auto-detect would otherwise enable it. Implements the -post-quantum additions from TCG TPM 2.0 Library Specification v1.85 using -wolfCrypt's FIPS 203 / FIPS 204 modules. - -### Algorithms - -| Alg | Parameter Sets | Use | -|---|---|---| -| `TPM_ALG_MLKEM` (0x00A0) | MLKEM-512 / 768 / 1024 | Key encapsulation (decrypt-only keys) | -| `TPM_ALG_MLDSA` (0x00A1) | MLDSA-44 / 65 / 87 | Pure ML-DSA message signing | -| `TPM_ALG_HASH_MLDSA` (0x00A2) | MLDSA-44 / 65 / 87 | Pre-hashed ML-DSA signing | - -### Commands - -The eight v1.85 PQC commands in `src/fwtpm/fwtpm_command.c`: - -| Command | CC | Purpose | -|---|---|---| -| `TPM2_Encapsulate` | `0x000001A7` | ML-KEM encapsulation, returns sharedSecret + ciphertext | -| `TPM2_Decapsulate` | `0x000001A8` | ML-KEM decapsulation from ciphertext (requires USER auth) | -| `TPM2_SignSequenceStart` | `0x000001AA` | Begin ML-DSA sign sequence | -| `TPM2_SignSequenceComplete` | `0x000001A4` | Finalize sign sequence with message buffer | -| `TPM2_VerifySequenceStart` | `0x000001A9` | Begin ML-DSA verify sequence | -| `TPM2_VerifySequenceComplete` | `0x000001A3` | Finalize verify sequence, returns TPMT_TK_VERIFIED | -| `TPM2_SignDigest` | `0x000001A6` | One-shot digest sign (Hash-ML-DSA or ext-μ ML-DSA) | -| `TPM2_VerifyDigestSignature` | `0x000001A5` | Verify digest signature | - -### Primary Key Derivation - -PQC primary keys follow the same deterministic derivation model as RSA/ECC: -hierarchy seed + template → KDFa-derived seed → FIPS 203/204 key expansion. - -- **ML-DSA**: `KDFa(nameAlg, seed, "MLDSA", hashUnique) → 32-byte Xi` → - `wc_MlDsaKey_MakeKeyFromSeed` → (pub, expanded-priv). The wire format stores - only the 32-byte Xi per TCG Part 2 Table 210. -- **Hash-ML-DSA**: label is `"HASH_MLDSA"`; same seed size and expansion. -- **ML-KEM**: `KDFa(nameAlg, seed, "MLKEM", hashUnique) → 64-byte (d‖z)` → - `wc_MlKemKey_MakeKeyWithRandom` → (ek, dk). Wire format stores only 64-byte - seed per TCG Part 2 Table 206. - -These label strings are an interpretation — TCG Part 4 v185 (which would -normatively specify them) is unpublished, so they are subject to change -if rc5 / Part 4 v185 prescribe different labels. - -### Sign / Verify Sequences - -Pure ML-DSA is **one-shot** — `TPM2_SequenceUpdate` on a Pure ML-DSA sign -sequence returns `TPM_RC_ONE_SHOT_SIGNATURE`; the message must arrive via the -`buffer` parameter of `TPM2_SignSequenceComplete`. Verify sequences accumulate -the message via `TPM2_SequenceUpdate` since `TPM2_VerifySequenceComplete` has no -buffer parameter. - -Hash-ML-DSA sequences (both sign and verify) use wolfCrypt's `wc_HashAlg` context -to stream the message into the key's hash algorithm; `TPM2_SignSequenceComplete` -finalizes the hash and calls `wc_MlDsaKey_SignCtxHash`. - -Signature wire formats differ per spec Part 2 Table 217: - -- **Pure ML-DSA** → `TPM2B_SIGNATURE_MLDSA`: `sigAlg + size + bytes` -- **Hash-ML-DSA** → `TPMS_SIGNATURE_HASH_MLDSA`: `sigAlg + hashAlg + size + bytes` - -### Buffer Constants - -Under `WOLFTPM_V185`, buffers are lifted to accommodate ML-DSA-87 signatures -(4627 bytes) and public keys (2592 bytes): - -| Symbol | v1.38 | v1.85 | -|---|---|---| -| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 8192 | -| `FWTPM_MAX_PUB_BUF` | 512 | 2720 | -| `FWTPM_MAX_DER_SIG_BUF` | 256 | 4736 | -| `FWTPM_MAX_KEM_CT_BUF` | — | 1600 | -| `FWTPM_TIS_FIFO_SIZE` | 4096 | 8192 | -| `FWTPM_NV_PUBAREA_EST` | 600 | 2720 | - -### Deferred / Out of Scope - -Three v1.85 features are deferred with documented reasons: - -1. **ML-KEM-salted sessions** — Part 3 Sec.11.1 (`TPM2_StartAuthSession`) does not - describe an ML-KEM bullet alongside RSA-OAEP and ECDH paths, even though - Part 2 Sec.11.4.2 Table 222 defines the `mlkem` arm of `TPMU_ENCRYPTED_SECRET`. - Part 4 v185 (which would normatively specify this) is not yet published. - Current behavior: `TPM2_StartAuthSession` returns `TPM_RC_KEY` for ML-KEM - tpmKey; revisit when Part 4 v185 lands. -2. **External-μ ML-DSA signing** — wolfCrypt has no μ-direct sign API. Part 2 - Sec.12.2.3.7 text says "512-byte external Mu" but FIPS 204 Algorithm 7 Line 6 - produces 64 bytes (SHAKE256 output). Pending wolfCrypt API addition and - TCG errata confirmation. Current behavior: `TPM_RC_SCHEME` for ext-μ paths, - `TPM_RC_EXT_MU` for Pure ML-DSA keys without `allowExternalMu`. See DEC-0006. -3. **ECC KEM arm of Encapsulate/Decapsulate** — Part 2 Sec.10.3.13 Table 100 has - both `mlkem` and `ecdh` arms, but the table note explicitly allows - implementations to modify the union based on supported algorithms. Current - fwTPM supports the `mlkem` arm only. - -### Test Coverage - -`tests/fwtpm_unit_tests.c` includes ten PQC tests exercising the full path: - -- CreatePrimary for MLKEM-768 and MLDSA-65 -- Full Encap/Decap round-trip (shared secret byte match) -- Hash-ML-DSA SignDigest / VerifyDigestSignature round-trip -- Pure ML-DSA sign sequence + verify sequence round-trip -- Dual-source KAT tests (NIST ACVP + wolfSSL internal vectors) for MLDSA-44 - verify, MLDSA-44 keygen determinism, MLKEM-512 encapsulation with pinned - randomness, and MLKEM-512 keygen determinism -- LoadExternal of a NIST ACVP MLDSA-44 public key through the fwTPM handler +The firmware TPM section (overview, building, usage, HAL and porting, +post-quantum, and SPDM) is kept in [`docs/fwtpm/`](fwtpm/overview.md). diff --git a/docs/SWTPM.md b/docs/SWTPM.md index f66ee0ab..fbc69d58 100644 --- a/docs/SWTPM.md +++ b/docs/SWTPM.md @@ -1,272 +1,8 @@ -# wolfTPM with Software Simulator (SWTPM) support +# wolfTPM Software Simulator (SWTPM) -wolfTPM is to be able to use Software TPM (SW TPM) defined by section D.3 of [TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code](https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code.pdf) +This page has moved into the wolfTPM manual. -Software TPM implementations tested: -* [Official TCG Reference](https://github.com/TrustedComputingGroup/TPM): Reference code from the specification maintained by TCG [build steps](#tcg-tpm) -* [IBM (ibmswtpm2) / Ken Goldman](https://github.com/kgoldman/ibmswtpm2): Fork of reference code maintained by IBM (93% identical to official TCG) [build steps](#ibmswtpm2) -* [Microsoft - ms-tpm-20-ref](https://github.com/microsoft/ms-tpm-20-ref): Fork of reference code maintained by Microsoft (100% identical to official TCG) [build steps](#ms-tpm-20-ref) -* [libtpms/swtpm - Stefan Berger](https://github.com/stefanberger/swtpm): Uses libtpms front end interfaces. [build steps](#swtpm) +Read it here: -The software TPM transport is a socket connection by default, but we also support a UART. - -This implementation only uses the TPM command interface typically on port 2321. It does not support the Platform interface typically on port 2322. - -## wolfTPM SWTPM support - -To enable the socket transport for SWTPM use `--enable-swtpm`. By default all software TPM simulators use TCP port 2321. - -```sh -./configure --enable-swtpm -make -``` - -Note: It is not possible to enable more than one transport interface at a time. If building with SWTPM socket interface the built-in TIS and devtpm (/dev/tpm0) interfaces are not available. - -Build Options: - -* `WOLFTPM_SWTPM`: Use socket transport (no TIS layer) -* `TPM2_SWTPM_HOST`: The socket host (default is localhost) -* `TPM2_SWTPM_PORT`: The socket port (default is 2321) - -## wolfTPM SWTPM UART support - -To use the SWTPM protocol over a UART serial connection (instead of TCP sockets), use `--enable-swtpm=uart`. This is intended for communicating with a firmware TPM (fwTPM) running on an embedded target such as the wolfTPM fwTPM server on STM32H5. - -```sh -./configure --enable-swtpm=uart -make -``` - -The serial device path and baud rate can be set at compile time or runtime: - -```sh -# Runtime override via environment variable -TPM2_SWTPM_HOST=/dev/ttyACM0 ./examples/wrap/caps -``` - -Build Options: - -* `WOLFTPM_SWTPM_UART`: Use UART serial transport (set automatically by `--enable-swtpm=uart`) -* `TPM2_SWTPM_HOST`: The serial device path (default is `/dev/ttyACM0` on Linux, `/dev/cu.usbmodem` on macOS). Can be overridden at runtime via the `TPM2_SWTPM_HOST` environment variable. -* `TPM2_SWTPM_PORT`: The baud rate (default is 115200) - -The UART transport uses the same mssim protocol as the socket transport. The serial port is configured as 8N1 raw mode with no flow control. Like the socket transport, the serial port file descriptor is kept open across commands (no reconnect per command). Both transports close the connection during `wolfTPM2_Cleanup`. On the socket transport any transmit/receive failure also closes the connection so the next command reconnects; the UART transport closes only when the per-command `TPM_SESSION_END` write fails. - -#### Security note: environment variable override - -The `TPM2_SWTPM_HOST` environment variable is a development convenience that overrides the compile-time serial device path. On systems where untrusted local users share the environment with the TPM client, an attacker could redirect TPM I/O to a rogue device (e.g. a PTY they control). For production / hardened deployments: - -* Unset `TPM2_SWTPM_HOST` in the process environment, and -* Rely on the compile-time default (set via `TPM2_SWTPM_HOST` as a build `-D` macro) to pin the serial path. - -The same guidance applies to `TPM2_SWTPM_PORT` (baud rate) and, for the socket transport, to using the env var to redirect the TCP host. - -### Example: wolfTPM fwTPM on STM32H5 - -The wolfTPM project includes a firmware TPM server port for STM32 Cortex-M33 targets with TrustZone support. See [wolftpm-examples/STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/pull/1) for build, flash, and test instructions. - -```sh -# Build host client with UART transport -./configure --enable-swtpm=uart -make - -# Run examples against STM32 fwTPM (adjust device path as needed) -export TPM2_SWTPM_HOST=/dev/ttyACM0 -./examples/wrap/caps -./examples/keygen/keygen -ecc -./examples/seal/seal -``` - -## Using a SWTPM - -### SWTPM Power Up and Startup - -The TCG TPM and Microsoft ms-tpm-20-ref implementations require sending power up and startup commands on the platform interface before the command interface is enabled. You can use these commands to issue the required power up and startup: - -```sh -echo -ne "\x00\x00\x00\x01" | nc 127.0.0.1 2322 -echo -ne "\x00\x00\x00\x0B" | nc 127.0.0.1 2322 -``` - -### TCG TPM - -```sh -clone git@github.com:TrustedComputingGroup/TPM.git -cd TPM -cd TPMCmd -./bootstrap -./configure -make -``` - -Run with: `./Simulator/src/tpm2-simulator` - -Run power on and self test. See [SWTPM Power Up and Startup](#swtpm-power-up-and-startup). - -### ibmswtpm2 - -Build steps: - -```sh -git clone https://github.com/kgoldman/ibmswtpm2.git -cd ibmswtpm2/src/ -make -``` - -Run with: `./tpm_server` - -Note: You can use the `-rm` switch to remove the cache file NVChip. Alternatively you can delete the NVChip file (`rm NVChip`) - - -### ms-tpm-20-ref - -Build steps: - -```sh -git clone https://github.com/microsoft/ms-tpm-20-ref -cd ms-tpm-20-ref/TPMCmd -./bootstrap -./configure -make -``` - -Run with: `./Simulator/src/tpm2-simulator` - -Run power on and self test. See [SWTPM Power Up and Startup](#swtpm-power-up-and-startup). - - -### swtpm - -Build libtpms - -```sh -git clone git@github.com:stefanberger/libtpms.git -cd libtpms -./autogen.sh --with-tpm2 --with-openssl --prefix=/usr -make install -``` - -Build swtpm - -```sh -git clone git@github.com:stefanberger/swtpm.git -cd swtpm -./autogen.sh -make install -``` - -Note: On Mac OS X had to do the following first: - -```sh -brew install openssl socat -pip3 install cryptography - -export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" -export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" - -# libtpms had to use --prefix=/usr/local -``` - -Running swtpm - -```sh -mkdir -p /tmp/myvtpm -swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init -``` - -### swtpm with QEMU - -This demonstrates using wolfTPM in QEMU to communicate using the linux -kernel device "/dev/tpmX". You will need to install or build -[swtpm](https://github.com/stefanberger/swtpm). Below are a short -method to build. You may need to consult the instructions for -[libtpms](https://github.com/stefanberger/libtpms/wiki#compile-and-install-on-linux) -and -[swtpm](https://github.com/stefanberger/swtpm/wiki#compile-and-install-on-linux) - -```sh -PREFIX=$PWD/inst -git clone git@github.com:stefanberger/libtpms.git -cd libtpms/ -./autogen.sh --with-openssl --with-tpm2 --prefix=$PREFIX && make install -cd .. -git clone git@github.com:stefanberger/swtpm.git -cd swtpm -PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig/ ./autogen.sh --with-openssl --with-tpm2 \ - --prefix=$PREFIX && \ - make install -cd .. -``` - -You can setup a basic linux installation. Other installation bases can -be used. This step will take some time to install the base linux -system. - -```sh -# download mini install image -curl -O http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/mini.iso -# create qemu image file -qemu-img create -f qcow2 lubuntu.qcow2 5G -# create directory for tpm state and socket -mkdir $PREFIX/mytpm -# start swtpm -$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ - --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & -# start qemu for installation -qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ - -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ - -tpmdev emulator,id=tpm0,chardev=chrtpm \ - -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 -cdrom mini.iso -``` - -Once a base system is installed it's ready to start the qemu and build -wolfSSL and wolfTPM in the qemu instance. - -```sh -# start swtpm again -$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ - --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & -# start qemu system to install and run wolfTPM -qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ - -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ - -tpmdev emulator,id=tpm0,chardev=chrtpm \ - -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 -``` - -To build checkout and build wolfTPM, in the QEMU terminal - -```sh -sudo apt install automake libtool gcc git make - -# get and build wolfSSL -git clone https://github.com/wolfssl/wolfssl.git -pushd wolfssl -./autogen.sh && \ - ./configure --enable-wolftpm --disable-examples --prefix=$PWD/../inst && \ - make install -popd - -# get and build wolfTPM -git clone https://github.com/wolfssl/wolftpm.git -pushd wolftpm -./autogen.sh && \ - ./configure --enable-devtpm --prefix=$PWD/../inst --enable-debug && \ - make install -sudo make check -popd -``` - -You can now run the examples such as `sudo ./examples/wrap/wrap` -within QEMU. Using `sudo` maybe required for access to `/dev/tpm0`. - - -## Running examples - -```sh -./examples/wrap/caps -./examples/pcr/extend -./examples/wrap/wrap_test -``` - -See [examples/README.md](../examples/README.md) for additional example usage. +The Software Simulator material is kept in the System Interfaces page, +[`docs/system-interfaces.md`](system-interfaces.md). diff --git a/docs/WindowTBS.md b/docs/WindowTBS.md index 7bab18dd..2ccb67c2 100644 --- a/docs/WindowTBS.md +++ b/docs/WindowTBS.md @@ -1,88 +1,8 @@ # Using wolfTPM with Windows TBS -wolfTPM can be built to use Windows native TBS (TPM Base Services) +This page has moved into the wolfTPM manual. -When using the Windows TBS interface the NV access is blocked by default. TPM NV storage space is very limited and when filled can cause undefined behaviors, such as failures loading key handles. These are not managed by TBS. +Read it here: -The TPM is designed to return an encrypted private key blob on key creation using `TPM2_Create`, which you can safely store on the disk and load when needed. The symmetric encryption key used to protect the private key blob is only known by the TPM. When you load a key using `TPM2_Load` you get a transient handle, which can be used for signing and even encryption/decryption. - -For primary keys created with `TPM2_CreatePrimary` you get back a handle. There is no encrypted private data returned. That handle will remain loaded until `TPM2_FlushContext` is called. - -For normal key creation using `TPM2_Create` you get back a `TPM2B_PRIVATE outPrivate`, which is the encrypted blob that you can store and load anytime using `TPM2_Load`. - -## Limitations - -wolfTPM has been tested on Windows 10 with TPM 2.0 devices. While -Windows does support TPM 1.2, functionality is limited and not -supported by wolfTPM. - -Presence of TPM 2.0 can be checked by opening PowerShell -and running `Get-PnpDevice -Class SecurityDevices` - -``` -Status Class FriendlyName ------- ----- ------------ -OK SecurityDevices Trusted Platform Module 2.0 -Unknown SecurityDevices Trusted Platform Module 2.0 -``` - -## Building in MSYS2 - -Tested using MSYS2 - -``` -export PREFIX=$PWD/tmp_install - -cd wolfssl -./autogen.sh -./configure --prefix="$PREFIX" --enable-wolftpm -make -make install - -cd wolftpm/ -./autogen.sh -./configure --prefix="$PREFIX" --enable-winapi -make -./examples -``` - -Note: To install the development base tools on MSYS2 use: `pacman -s base-devel` and `pacman -S mingw-w64-x86_64-toolchain`. - -## Building on linux - -Tested using mingw-w32-bin_x86_64-linux_20131221.tar.bz2 -[source](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds/) - -Extract the tools and add them to the `PATH` -``` -mkdir mingw_tools -cd mingw_tools -tar xjvf ../mingw-w32-bin_x86_64-linux_20131221.tar.bz2 -export PATH=$PWD/bin/:$PWD/i686-w64-mingw32/bin:$PATH -cd .. -``` - -Build -``` -export PREFIX=$PWD/tmp_install -export CFLAGS="-DWIN32 -DMINGW -D_WIN32_WINNT=0x0600 -DUSE_WOLF_STRTOK" -export LIBS="-lws2_32" - -cd wolfssl -./autogen.sh -./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-wolftpm -make -make install - -cd ../wolftpm/ -./autogen.sh -./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-winapi -make -cd .. -``` - -## Running on Windows - -To confirm presence and status of TPM on the machine run `tpm.msc` - -See [examples/README.md](/examples/README.md) +The Windows TBS material is kept in the System Interfaces page, +[`docs/system-interfaces.md`](system-interfaces.md). diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 00000000..5af48990 --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,31 @@ +# API Reference + +wolfTPM exposes three layers of headers. This page explains which one to start with. The function-level reference is generated from the header comments with Doxygen and appears on the pages that follow in this section. + +## Wrapper API + +The wrapper API is declared in `wolftpm/tpm2_wrap.h`. All of its functions are named `wolfTPM2_*`. It hides command sequencing, session handling, parameter encryption and key blob management behind a small set of calls, and it is the recommended starting point for applications. Key creation, loading, signing, sealing and NV storage are covered in [Key Management](key-management.md), and quoting and PCR use in [Attestation](attestation.md). + +## Native API + +The native API is declared in `wolftpm/tpm2.h`. It provides the raw `TPM2_*` commands, one function per TPM 2.0 command, along with the structures and constants from the TCG specification. Use it when you need direct control over command parameters or need a command the wrapper does not cover. You build the command arguments yourself and handle sessions and authorization explicitly. + +## HAL IO + +`hal/tpm_io.h` declares the hardware abstraction layer used to move bytes between wolfTPM and the TPM. It is the header to read when you port wolfTPM to a new board or bus. See [HAL IO Callback](hal-io-callback.md). + +## Generated Reference + +The full function-level reference is generated from the header Doxygen comments and appears as the following pages in this section: + +- TPM2 API +- TPM2 Wrapper API +- TPM2 Header File +- TPM2 Wrapper Header File +- TPM2 HAL IO + +## See Also + +- [Key Management](key-management.md) +- [Attestation](attestation.md) +- [HAL IO Callback](hal-io-callback.md) diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 00000000..4f4db603 Binary files /dev/null and b/docs/assets/logo.png differ diff --git a/docs/assets/skin.css b/docs/assets/skin.css new file mode 100644 index 00000000..6f1809a3 --- /dev/null +++ b/docs/assets/skin.css @@ -0,0 +1,110 @@ +.md-header{ + background-color: #fff; +} + +.md-ellipsis{ + color: #1fbeca; + font-size: 1.1rem; +} + +.md-ellipsis-nav { + margin-right: 3%; + color: #1fbeca; + font-size: 16px; + width: 450px; +} + +.md-ellipsis-nav a{ + color:#fff; + background-color: #1fbeca; + padding: 6px; + border-radius: 3.5px; + margin-left: 3px; +} + +.md-ellipsis-nav a:hover{ + color: #1fbeca; + background-color: #000; +} + +@media screen and (max-width: 800px) +{ .md-ellipsis-nav { display: none; } } + +.md-search__input { + background: #f2f2f2; + border: 2px solid #dfdfdf; + color: black; +} + +.md-search__inner { + max-width: 400px; +} + +::placeholder { + color: gray !important; +} + +.md-content { + min-height: 550px; +} + +.md-nav__link { + color: #c46715; +} + +.md-nav__link:is(:focus, :hover){ + color: #1fbeca; +} + +.md-nav__item .md-nav__link--active { + color: #1fbeca; +} + +.md-header__button.md-logo :is(img, svg){ + height: 80px; + width: 80px; +} + +.md-typeset a:focus, .md-typeset a{ + color: #c46715; +} + +.md-typeset a:hover { + color: #1fbeca; +} + +.md-footer { + background-color: #fff; + box-shadow: 0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2); +} + +.md-icon svg { + fill: #1fbeca; +} + +.md-footer-meta { + background-color: #ccc; + height: 30px; +} + +.md-footer-meta__inner{ + bottom: 0; + position: absolute; +} + +.md-copyright__highlight { + font-size: 0.6rem; + color: black; +} + +.md-copyright { + color: black; +} + +html .md-footer-meta.md-typeset a { + color: black; +} + +html .md-footer-meta.md-typeset a:is(:focus, :hover) { + color: #c46715; +} diff --git a/docs/assets/table-code.css b/docs/assets/table-code.css new file mode 100644 index 00000000..389c3679 --- /dev/null +++ b/docs/assets/table-code.css @@ -0,0 +1,20 @@ +/* Keep inline code spans (configure options, property names, etc.) on a + * single line inside tables. The code column then sizes to its content and + * prose columns absorb the wrapping instead. Opt in per manual via the + * extra_css list in its mkdocs.yml. */ +/* display: inline-block is required for WebKit (Safari): it otherwise sizes + * table columns using the hyphen break opportunities inside code spans, then + * line-breaks the span (e.g. --enable-slhdsa) even under white-space: nowrap. + * As an inline-block atom the span's full width feeds into column sizing. + * The word-break/hyphens resets guard the wrapped-prose case (Notes columns), + * where WebKit can still honor the theme's `code { word-break: break-word }` + * break opportunities inside a nowrap inline element. */ +.md-typeset table:not([class]) th code, +.md-typeset table:not([class]) td code { + display: inline-block; + white-space: nowrap; + word-break: normal; + overflow-wrap: normal; + -webkit-hyphens: none; + hyphens: none; +} diff --git a/docs/attestation.md b/docs/attestation.md new file mode 100644 index 00000000..4254966f --- /dev/null +++ b/docs/attestation.md @@ -0,0 +1,465 @@ +# Attestation + +wolfTPM includes examples for local and remote attestation, TPM signed timestamps, endorsement key certificates and device identity keys. This page covers the remote attestation challenge flow, PCR quotes, signed timestamps, EK certificate validation and the manufacturer identity keys. + +## Remote attestation overview + +Remote attestation is the process of a client giving evidence to an attestation server, which checks that the client is in a known state. For this to work, the client and server must first establish trust. This is done with the standard TPM 2.0 commands `TPM2_MakeCredential` and `TPM2_ActivateCredential`. + +1. The client sends the server the public parts of a TPM 2.0 Primary Attestation Key (PAK) and a quote signing Attestation Key (AK). +2. `MakeCredential` uses the public part of the PAK to encrypt a challenge (a secret). Typically the challenge is a digest of the public part of the AK. Only the TPM that can load the private part of the PAK and AK can decrypt it. Both keys carry the `fixedTPM` attribute, so the only TPM that can load them is the one where they were created. +3. The server sends the challenge to the client. +4. `ActivateCredential` uses the loaded PAK and AK to decrypt the challenge and recover the secret. The client can then respond to the server. + +This proves to the server that the client holds the expected TPM identity and attestation key. + +!!! note + The transport used to exchange the challenge and response is up to the developer, because it is implementation specific. One option is a TLS 1.3 client-server connection using wolfSSL. + +The examples used in this flow: + +| Program | Role | +| --- | --- | +| `./examples/attestation/make_credential` | Used by a server to create a remote attestation challenge. | +| `./examples/attestation/activate_credential` | Used by a client to decrypt the challenge and respond. | +| `./examples/attestation/certify` | Certifies (attests) that an object with a given name is loaded in the TPM. | +| `./examples/keygen/create_primary` | Creates a primary key (PK) and attestation key (AK). | + +All of these examples accept `-eh` to use the Endorsement Key and an Attestation Key under the Endorsement Hierarchy. The private part of the EK never leaves the TPM, and the EK is unique to each TPM chip, so a challenge encrypted to the EK can only be opened by that TPM. The drawback is privacy: the EK identifies the TPM, so the identity of the host under attestation is always known. The examples support both an AK under the SRK and an AK under the EK. The developer chooses which to use. + +## Creating keys for attestation + +Use the `keygen` example to create the TPM 2.0 Attestation Key and the Primary Storage Key that serves as the Primary Attestation Key (PAK). + +```sh +$ ./examples/keygen/keygen -rsa +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: RSA + Template: AIK + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +RSA AIK template +Creating new RSA key... +New key created and loaded (pub 280, priv 222 bytes) +Wrote 508 bytes to keyblob.bin +Wrote 288 bytes to srk.pub +Wrote AK Name digest +``` + +The files written here (`keyblob.bin`, `srk.pub` and the AK name digest) are the inputs for the next two steps. See [Key Management](key-management.md) for more on `keygen`. + +## MakeCredential and ActivateCredential + +### Make credential + +An attestation server uses `make_credential` to generate the challenge. The secret is 32 bytes of random data that can serve as a symmetric key seed in some attestation schemes. + +```sh +$ ./examples/attestation/make_credential +Using public key from SRK to create the challenge +Demo how to create a credential challenge for remote attestation +Credential will be stored in cred.blob +wolfTPM2_Init: success +Reading 288 bytes from srk.pub +Reading the private part of the key +Public key for encryption loaded +Read AK Name digest success +TPM2_MakeCredential success +Wrote credential blob and secret to cred.blob, 648 bytes +``` + +The transfer of the PAK and AK public parts between the client and server is not part of this example. + +### Activate credential + +A client uses `activate_credential` to decrypt the challenge. The secret is exposed in plain text and can be sent to the attestation server. + +```sh +$ ./examples/attestation/activate_credential +Using default values +Demo how to create a credential blob for remote attestation +wolfTPM2_Init: success +Credential will be read from cred.blob +Loading SRK: Storage 0x81000200 (282 bytes) +SRK loaded +Reading 508 bytes from keyblob.bin +Reading the private part of the key +AK loaded at 0x80000001 +Read credential blob and secret from cred.blob, 648 bytes +TPM2_ActivateCredential success +``` + +Sending the response containing the secret (in plain text or as a symmetric key seed) back to the server is also outside this example. + +### Certify + +The `certify` example uses `TPM2_Certify` to sign attestation information for another key. This proves that an object with a specific name is loaded in the TPM. A common use is having the restricted IAK sign the attestation information for the IDevID. + +`create_primary` can create RSA or ECC IDevID and IAK keys. They are created under the endorsement hierarchy and follow the TCG "TPM 2.0 Keys for Device Identity and Attestation" specification for primary key policies. The IDevID key is used for external, non-restricted signing. The IAK is used for internal attestation. Here the IAK certifies the IDevID. + +```sh +% ./examples/keygen/create_primary -rsa -eh -iak -keep +TPM2.0 Primary Key generation example + Algorithm: RSA + Unique: IAK + Store Handle: 0x00000000 + Use Parameter Encryption: NULL +Creating new RSA primary key... +Create Primary Handle: 0x80000000 + +% ./examples/keygen/create_primary -rsa -eh -idevid -keep +TPM2.0 Primary Key generation example + Algorithm: RSA + Unique: IDEVID + Store Handle: 0x00000000 + Use Parameter Encryption: NULL +Creating new RSA primary key... +Create Primary Handle: 0x80000001 + +% ./examples/attestation/certify -rsa -certify=0x80000001 -signer=0x80000000 +Certify 0x80000001 with 0x80000000 to generate TPM-signed attestation info +EK Policy Session: Handle 0x3000000 +TPM2_Certify complete +Certify Info 172 +RSA Signature: 256 + +% ./examples/management/flush 0x80000001 +Preparing to free TPM2.0 Resources +Freeing 80000001 object + +% ./examples/management/flush 0x80000000 +Preparing to free TPM2.0 Resources +Freeing 80000000 object +``` + +For ECC, use the same steps and replace `-rsa` with `-ecc`. + +## Quote and PCR attestation + +The `examples/pcr/` folder has tools for working with Platform Configuration Registers (PCRs) and for generating a TPM 2.0 Quote. Build with `./configure --enable-debug` to see more log output. + +| Program | Purpose | +| --- | --- | +| `./examples/pcr/reset` | Clears the content of a PCR (restrictions apply, see below). | +| `./examples/pcr/extend` | Modifies the content of a PCR with an extend operation. | +| `./examples/pcr/quote` | Generates a TPM 2.0 Quote with the PCR digest and a TPM signature. | +| `./examples/pcr/allocate` | Reports which PCR banks the TPM implements and has allocated, and changes the allocation. | +| `./examples/pcr/demo.sh` | Script that demonstrates the tools above. | +| `./examples/pcr/demo-quote-zip.sh` | Script that measures a system file and generates a TPM signed proof of that measurement. | + +### PCR basics + +A PCR can only be changed by an extend operation. At power-up the TPM resets all PCRs to their default value (all zeros or all ones, depending on the PCR). The same PCR value can only be reached by extending with the same digests in the same order. Extending with A, B, C gives a different result than C, B, A, but each order is reproducible. + +`TPM2_Extend` uses a SHA-1 or SHA-256 hash operation to combine the current PCR value with the new digest. + +Every PCR can be extended, but only some can be reset at runtime: + +* PCR0 to 15 are reset at boot and can be cleared again only by a reboot. +* PCR16 is for debugging. All the tools above use it by default, and it is safe to test with. +* PCR17 to 22 are reserved for Dynamic Root of Trust Measurement (DRTM). + +Reset locality follows TCG PC Client: PCR16 and 23 reset at localities 0 to 3, PCR20 to 22 at localities 2 to 4, and PCR17 to 19 at locality 4. Use `-loc=n` to select the locality (see `wolfTPM2_SetLocality`). It applies to the built-in TIS/SPI driver and the fwTPM. + +### Bank allocation + +A TPM keeps a separate set of PCRs per hash algorithm, called a bank. Which banks exist is fixed in silicon, but which are allocated is provisioned with `TPM2_PCR_Allocate` and can be changed. Many parts, including the Infineon SLB9672 and later, allocate only one bank at a time, so moving from SHA-256 to SHA-384 means deallocating SHA-256. SHA-1 is deprecated and is not allocated on current parts. + +!!! warning + The selection replaces the allocation. Any bank not named in the request is deallocated. The command needs the platform hierarchy, which platform firmware has usually disabled under an OS (the TPM answers `TPM_RC_HIERARCHY` regardless of the authorization supplied). Use `wolfTPM2_AllocatePCRBanks_ex` with a session where platform auth is not the empty password. The change takes effect at the next TPM reset, so power cycle the TPM or restart the simulator, then re-read the banks. Changing banks invalidates every `PolicyPCR` digest, and anything sealed to PCR values can no longer be unsealed. + +### Quote + +`TPM2_Quote` puts the PCR digest in a TCG defined `TPMS_ATTEST` structure together with a TPM signature. The signature comes from an Attestation Identity Key (AIK) that only the TPM can use, which gives assurance about the source of the Quote and the PCR digest. + +### Tool usage + +```sh +$ ./examples/pcr/reset -? +Incorrect arguments +Expected usage: +./examples/pcr/reset [pcr] [-loc=n] +* pcr is a PCR index between 0-23 (default 16) +* -loc=n switch to TPM locality n (0-4) before reset + (PCR 17-19 need locality 4; 20-22 need locality 2-4; + enforced by the fwTPM and by discrete TPMs like the ST33) +Demo usage without parameters, resets PCR16. +``` + +```sh +$ ./examples/pcr/extend -? +Incorrect arguments +Expected usage: +./examples/pcr/extend [pcr] [filename] +* pcr is a PCR index between 0-23 (default 16) +* filename points to file(data) to measure + If wolfTPM is built with --disable-wolfcrypt the file + must contain SHA256 digest ready for extend operation. + Otherwise, the extend tool computes the hash using wolfcrypt. +Demo usage without parameters, extends PCR16 with known hash. +``` + +```sh +$ ./examples/pcr/quote -? +Incorrect arguments +Expected usage: +./examples/pcr/quote [pcr] [filename] +* pcr is a PCR index between 0-23 (default 16) +* filename for saving the TPMS_ATTEST structure to a file +Demo usage without parameters, generates quote over PCR16 and +saves the output TPMS_ATTEST structure to "quote.blob" file. +``` + +```sh +$ ./examples/pcr/allocate -? +Expected usage: +./examples/pcr/allocate [-sha1] [-sha256] [-sha384] [-sha512] + [-restore] +* no algorithm flags: report the current allocation and exit +* -shaN: include that bank in the new allocation (repeatable) +* -restore: put the original allocation back before exiting +Demo usage without parameters, reports the PCR banks. + +WARNING: the algorithm flags REPLACE the allocation. Banks not +named are deallocated, every PolicyPCR digest changes, and blobs +sealed to PCR values become unsealable. Many TPMs support only +one active bank at a time. + +The new allocation takes effect at the next TPM reset, so power +cycle the TPM (or restart the simulator) and re-run to confirm. +``` + +With no flags, `allocate` reports the banks the TPM has. The list comes from the TPM's own `TPM_CAP_PCRS` response, so a bank this build has no name for prints as its hash algorithm id, and `pcrSelect` is the raw bitmap: + +```sh +$ ./examples/pcr/allocate +PCR banks: + Bank Allocated pcrSelect + SHA-256 yes FFFFFF + SHA-384 yes FFFFFF + SHA-1 no 000000 +``` + +To move to a SHA-384 only allocation and confirm it after a reset: + +```sh +$ ./examples/pcr/allocate -sha384 +TPM reported: allocationSuccess YES, maxPCR 24, sizeNeeded 1152, sizeAvailable 4608 +PCR allocation staged. It takes effect at the next TPM reset +(Startup(CLEAR) after a _TPM_Init) - power cycle the TPM, or +restart the simulator process, then re-run to confirm. + +$ ./examples/pcr/allocate +PCR banks: + Bank Allocated pcrSelect + SHA-256 no 000000 + SHA-384 yes FFFFFF + SHA-1 no 000000 +``` + +On a TPM that keeps one bank active, asking for two is rejected with `TPM_RC_PCR`. A TPM that accepts the command but lacks space reports `allocationSuccess = NO`, which the wrapper returns as `BUFFER_E` with `sizeNeeded` greater than `sizeAvailable`. Neither case is a wolfTPM error. + +Use `-restore` in scripts so a run leaves the banks as it found them. It replays the exact selection read at startup, bitmaps included, so a partially selected bank comes back partial. + +### Typical demo output + +All PCR examples run without arguments. This is the output of `./examples/pcr/demo.sh`: + +```sh +$ ./examples/pcr/reset +Demo how to reset a PCR (clear the PCR value) +wolfTPM2_Init: success +Trying to reset PCR16... +TPM2_PCR_Reset success +PCR16 digest: + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ +``` + +PCR16 is back to all zeros, so later PCR digests are predictable. This is similar to PCR7 right after boot, but PCR16 lets you test without rebooting. + +```sh +$ ./examples/pcr/extend +Demo how to extend data into a PCR (TPM2.0 measurement) +wolfTPM2_Init: success +Hash to be used for measurement: +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +TPM2_PCR_Extend success +PCR16 digest: + bb 22 75 c4 9f 28 ad 52 ca e6 d5 5e 34 a9 74 a5 | ."u..(.R...^4.t. + 8c 7a 3b a2 6f 97 6e 8e cb be 7a 53 69 18 dc 73 | .z;.o.n...zSi..s +``` + +The new value comes from the old PCR content (all zeros) and the supplied SHA-256 digest. It is always the same if `reset` runs before `extend`. To use your own data, pass the PCR index first (16 is recommended) and a file second. + +```sh +$ ./examples/pcr/quote +Demo of generating signed PCR measurement (TPM2.0 Quote) +wolfTPM2_Init: success +TPM2_CreatePrimary: 0x80000000 (314 bytes) +wolfTPM2_CreateEK: Endorsement 0x80000000 (314 bytes) +TPM2_CreatePrimary: 0x80000001 (282 bytes) +wolfTPM2_CreateSRK: Storage 0x80000001 (282 bytes) +TPM2_StartAuthSession: sessionHandle 0x3000000 +TPM2_Create key: pub 280, priv 212 +TPM2_Load Key Handle 0x80000002 +wolfTPM2_CreateAndLoadAIK: AIK 0x80000002 (280 bytes) +TPM2_Quote: success +TPM with signature attests (type 0x8018): + TPM signed 1 count of PCRs + PCR digest: + c7 d4 27 2a 57 97 7f 66 1f bd 79 30 0a 1b bf ff | ..'*W..f..y0.... + 2e 43 57 cc 44 14 7a 82 11 aa 76 3f 9f 1b 3a 6c | .CW.D.z...v?..:l + TPM generated signature: + 28 dc da 76 33 35 a5 85 2a 0c 0b e8 25 d0 f8 8d | (..v35..*...%... + 1f ce c3 3b 71 64 ed 54 e6 4d 82 af f3 83 18 8e | ...;qd.T.M...... + (remaining signature bytes omitted) +``` + +Before the TPM signs the quote, the example creates an Endorsement Key (EK), which acts as the primary key for the others. It then creates a Storage Key (SRK) and, under it, an Attestation Identity Key (AIK) that signs the quote structure. + +### Measuring a system file (local attestation) + +A system administrator wants to confirm that the `zip` tool on a user's system is genuine and unmodified. The administrator resets PCR16, extends it with a hash of the binary, and generates a quote that serves as a reference for later comparison. This is what `./examples/pcr/demo-quote-zip.sh` does. + +```sh +$ ./examples/pcr/reset 16 +... +Trying to reset PCR16... +TPM2_PCR_Reset success +... +``` + +The `extend` tool hashes `/usr/bin/zip` with wolfCrypt (SHA-256) and wolfTPM issues a `TPM2_PCR_Extend` on PCR16: + +```sh +$ ./examples/pcr/extend 16 /usr/bin/zip +... +TPM2_PCR_Extend success +PCR16 digest: + 2b bd 54 ae 08 5b 59 ef 90 42 d5 ca 5d df b5 b5 | +.T..[Y..B..]... + 74 3a 26 76 d4 39 37 eb b0 53 f5 82 67 6f b4 aa | t:&v.97..S..go.. +``` + +Then the administrator creates a quote as proof of the measurement in PCR16: + +```sh +$ ./examples/pcr/quote 16 zip.quote +... +TPM2_Quote: success +TPM with signature attests (type 0x8018): + TPM signed 1 count of PCRs +... +``` + +The quote is saved to the binary file `zip.quote`. The `TPMS_ATTEST` structure also holds clock and time information. See the next section for time attestation. + +### Quote with encrypted qualifying data + +The qualifying data supplied for a quote can be protected with parameter encryption. See [Examples Overview](examples-overview.md#parameter-encryption). + +## Signed timestamp (GetTime) + +The `signed_timestamp` example creates an Attestation Identity Key (AIK) and uses it to generate a TPM signed timestamp. The timestamp can serve as a protected report of the current system uptime. + +```sh +./examples/timestamp/signed_timestamp +``` + +The example uses an `authSession` (authorization session) and a `policySession` (policy authorization) to enable the Endorsement Hierarchy, which is needed to create the AIK. The AIK then issues a `TPM2_GetTime` command through the native API, which returns a TPM generated and signed timestamp. + +The `clock_set` example increments the TPM2 clock: + +```sh +./examples/timestamp/clock_set [time] +``` + +## Endorsement key certificates + +TPM manufacturers provision endorsement certificates based on a TPM key. The TCG EK Credential Profile defines how they are stored in the TCG NV index range (`TPM_20_TCG_NV_SPACE`). The `get_ek_certs` example enumerates and validates the EK certificates stored there, and creates a primary EK handle that can be used for signing. The `verify_ek_cert` example validates a single EK certificate against the trusted CA list. Some root and intermediate CAs are loaded in `trusted_certs.h`. + +```sh +./examples/endorsement/get_ek_certs +./examples/endorsement/verify_ek_cert +``` + +### Example detail + +1. Get the handles in the TCG NV range with `wolfTPM2_GetHandles` and `TPM_20_TCG_NV_SPACE`. +2. Get the certificate size by reading the public NV information with `wolfTPM2_NVReadPublic`. +3. Read the NV data (certificate DER/ASN.1) from the NV index with `wolfTPM2_NVReadAuth`. +4. Get the EK public template for the NV index with `wolfTPM2_GetKeyTemplate_EKIndex` or `wolfTPM2_GetKeyTemplate_EK`. +5. Create the primary endorsement key with the public template and the `TPM_RH_ENDORSEMENT` hierarchy using `wolfTPM2_CreatePrimaryKey`. +6. Parse the ASN.1/DER certificate with `wc_ParseCert` to get the issuer, serial number and other fields. +7. The URI for the CA issuer certificate is in `extAuthInfoCaIssuer`. +8. Import the certificate public key and compare it with the primary EK public unique area. +9. Validate the EK certificate with the wolfSSL Certificate Manager. Load trusted certificates with `wolfSSL_CertManagerLoadCABuffer` and verify with `wolfSSL_CertManagerVerifyBuffer`. +10. Optionally convert to PEM and export with `wc_DerToPem`. + +### Example certificate chains + +Infineon SLB9672. Certificates can be downloaded from these URLs (replace xxx with the 3 digit CA number): + +* `https://pki.infineon.com/OptigaRsaMfrCAxxx/OptigaRsaMfrCAxxx.crt` +* `https://pki.infineon.com/OptigaEccMfrCAxxx/OptigaEccMfrCAxxx.crt` + +Examples: + +* Infineon OPTIGA(TM) RSA Root CA 2, then Infineon OPTIGA(TM) TPM 2.0 RSA CA 059 +* Infineon OPTIGA(TM) ECC Root CA 2, then Infineon OPTIGA(TM) TPM 2.0 ECC CA 059 + +STMicro ST33KTPM: + +* STSAFE RSA root CA 02 (`http://sw-center.st.com/STSAFE/STSAFERsaRootCA02.crt`), then STSAFE-TPM RSA intermediate CA 10 (`http://sw-center.st.com/STSAFE/stsafetpmrsaint10.crt`) +* STSAFE ECC root CA 02 (`http://sw-center.st.com/STSAFE/STSAFEEccRootCA02.crt`), then STSAFE-TPM ECC intermediate CA 10 (`http://sw-center.st.com/STSAFE/stsafetpmeccint10.crt`) + +Sample output on an ST33KTPM (certificate hex dumps shortened): + +``` +$ ./examples/endorsement/verify_ek_cert +Endorsement Certificate Verify +TPM2: Caps 0x30000415, Did 0x0004, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +TPM2_NV_ReadPublic: Sz 14, Idx 0x1c00002, nameAlg 11, Attr 0x62076801, authPol 0, dataSz 1300, name 34 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 0, Size 768 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 768, Size 532 +EK Data: 1300 + 30 82 05 10 30 82 02 f8 a0 03 02 01 02 02 14 58 | 0...0..........X + ... +wolfTPM2_HashStart: Handle 0x80000002 +wolfTPM2_HashUpdate: Handle 0x80000002, DataSz 764 +wolfTPM2_HashFinish: Handle 0x80000002, DigestSz 48 +Cert Hash: 48 + ... +Issuer Public Exponent 0x10001, Modulus 512 + ... +TPM2_LoadExternal: 0x80000002 +EK Certificate Signature: 512 + ... +TPM2_RSA_Encrypt: 512 +Decrypted Sig: 512 + ... +Expected Hash: 48 + ... +Sig Hash: 48 + ... +Certificate signature is valid +TPM2_FlushContext: Closed handle 0x80000002 +TPM2_FlushContext: Closed handle 0x80000000 +``` + +## Device identity + +The TCG publishes a specification for TPM manufacturer guidance on setting up keys for device identity and attestation. wolfTPM supports it with `WOLFTPM_MFG_IDENTITY`, and it has been tested with the ST33KTPM. + +ST33KTPM samples are provisioned with a default master password, enabled with `TEST_SAMPLE`. To use your own master password, define `TPM2_IAK_SAMPLE_MASTER_PASSWORD`. The master password is hashed together with the device serial number to produce the authentication for accessing these keys. + +The default keys are ECDSA SECP384R1 with SHA2-384. They are stored at the NV indexes defined by `TPM2_IAK_KEY_HANDLE`, `TPM2_IAK_CERT_HANDLE`, `TPM2_IDEVID_KEY_HANDLE` and `TPM2_IDEVID_CERT_HANDLE`. + +## See Also + +* [Examples Overview](examples-overview.md) +* [Key Management](key-management.md) +* [Sealing and NVRAM](sealing-and-nvram.md) +* [Supported Hardware](supported-hardware.md) diff --git a/docs/benchmarks.md b/docs/benchmarks.md new file mode 100644 index 00000000..e6bd0349 --- /dev/null +++ b/docs/benchmarks.md @@ -0,0 +1,84 @@ +# Benchmarks + +This page shows how fast the supported TPM 2.0 devices run common operations, measured with the `examples/bench/bench` program, plus the first post-quantum numbers from SEALSQ QVault silicon. + +## About these numbers + +These are representative captures from real hardware, taken on different host boards and bus speeds. Results vary with the TPM firmware version, bus clock, host platform and build options, so treat them as a guide and run `./examples/bench/bench` on your own setup. + +## TPM 2.0 benchmarks by device + +Average latency per operation, in milliseconds (lower is better). RSA-2048 key generation is a one-off provisioning cost. + +| Device | Bus | RSA-2048 key gen | RSA-2048 private | ECDSA P-256 sign | ECDSA P-256 verify | +|---|---|---|---|---|---| +| Infineon OPTIGA SLB9670 | SPI, 43 MHz | 2196.2 | 163.2 | 68.9 | 113.5 | +| Infineon OPTIGA SLB9672 | SPI, 43 MHz | 1567.7 | 77.0 | 35.6 | 24.1 | +| Infineon OPTIGA SLB9673 | I2C, 400 kHz | 1910.6 | 168.1 | 72.1 | 57.9 | +| STMicro ST33KTPM2XSPI | SPI, 33 MHz | 1944.1 | 90.8 | 25.3 | 36.5 | +| STMicro ST33TPHF2XSPI | SPI, 33 MHz | 7455.0 | 247.8 | 42.3 | 74.0 | +| Microchip ATTPM20 | SPI, 33 MHz | 5275.9 | 117.7 | 58.7 | 43.0 | +| Nations Z32H330 | SPI, 33 MHz | 2183.8 | 133.2 | 23.4 | 36.8 | +| Nations NS350 | SPI, 33 MHz | 2378.9 | 51.7 | 16.8 | 21.9 | +| Nuvoton NPCT650 | not stated | 4479.2 | 540.9 | 190.1 | 265.2 | +| Nuvoton NPCT750 | SPI, 43 MHz | 3408.7 | 70.3 | 56.4 | 39.2 | +| NVIDIA Jetson Orin fTPM (OP-TEE) | `/dev/tpmrm0` | 736.4 | 11.9 | 45.1 | 31.7 | + +The README captures for the ST33TPHF2XSPI RSA key generation ran a single operation, so that figure is the least reliable in the table. + +Example output from `./examples/bench/bench` on an Infineon OPTIGA SLB9672 at 43 MHz: + +``` +./examples/bench/bench +TPM2 Benchmark using Wrapper API's + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +RNG 24 KB took 1.070 seconds, 22.429 KB/s +Benchmark symmetric AES-128-CBC-enc not supported! +Benchmark symmetric AES-128-CBC-dec not supported! +Benchmark symmetric AES-256-CBC-enc not supported! +Benchmark symmetric AES-256-CBC-dec not supported! +Benchmark symmetric AES-128-CTR-enc not supported! +Benchmark symmetric AES-128-CTR-dec not supported! +Benchmark symmetric AES-256-CTR-enc not supported! +Benchmark symmetric AES-256-CTR-dec not supported! +AES-128-CFB-enc 86 KB took 1.001 seconds, 85.890 KB/s +AES-128-CFB-dec 88 KB took 1.020 seconds, 86.267 KB/s +AES-256-CFB-enc 86 KB took 1.023 seconds, 84.073 KB/s +AES-256-CFB-dec 86 KB took 1.019 seconds, 84.370 KB/s +SHA1 88 KB took 1.021 seconds, 86.155 KB/s +SHA256 86 KB took 1.015 seconds, 84.717 KB/s +SHA384 90 KB took 1.007 seconds, 89.405 KB/s +RSA 2048 key gen 10 ops took 15.677 sec, avg 1567.678 ms, 0.638 ops/sec +RSA 2048 Public 110 ops took 1.000 sec, avg 9.095 ms, 109.951 ops/sec +RSA 2048 Private 14 ops took 1.078 sec, avg 76.996 ms, 12.988 ops/sec +RSA 2048 Pub OAEP 51 ops took 1.012 sec, avg 19.838 ms, 50.408 ops/sec +RSA 2048 Priv OAEP 12 ops took 1.053 sec, avg 87.738 ms, 11.398 ops/sec +ECC 256 key gen 8 ops took 1.088 sec, avg 135.956 ms, 7.355 ops/sec +ECDSA 256 sign 29 ops took 1.033 sec, avg 35.621 ms, 28.073 ops/sec +ECDSA 256 verify 42 ops took 1.013 sec, avg 24.114 ms, 41.470 ops/sec +ECDHE 256 agree 16 ops took 1.055 sec, avg 65.948 ms, 15.164 ops/sec +``` + +Devices that do not support a mode print "not supported" for it. + +## Post-quantum (SEALSQ QVault) + +These numbers were measured with `examples/bench/bench` on a Raspberry Pi 5 driving the SEALSQ QVault TPM over SPI. SEALSQ positions this part as the first post-quantum TPM in silicon. + +| Operation | Avg latency | Throughput | +|---|---|---| +| ML-DSA-65 key gen | 2044.7 ms | 0.49 ops/s | +| ML-DSA-65 sign | 581.0 ms | 1.72 ops/s | +| ML-DSA-65 verify | 163.1 ms | 6.13 ops/s | +| ML-KEM-768 key gen | 800.8 ms | 1.25 ops/s | +| ML-KEM-768 encapsulate | 211.8 ms | 4.72 ops/s | +| ML-KEM-768 decapsulate | 425.5 ms | 2.35 ops/s | + +Key generation is a one-off provisioning cost. The ECDSA figures above come from different TPMs, host boards, buses, and firmware, so they are not a like-for-like comparison with these ML-DSA numbers. To compare ECDSA and PQC latencies, run `./examples/bench/bench` for both on the same TPM, host, bus, and build. + +## See Also + +- [Testing and CI](testing.md) +- [Cited Sources](cited-sources.md) +- [Release Notes](release-notes.md) diff --git a/docs/build-options.md b/docs/build-options.md new file mode 100644 index 00000000..cc874735 --- /dev/null +++ b/docs/build-options.md @@ -0,0 +1,165 @@ +# Build Options + +This page is the reference for the Autotools (`./configure`) options and the preprocessor defines that control how wolfTPM is built. Each configure switch lists the macro it defines when one exists. `configure.ac` in the wolfTPM source tree is the authoritative source. + +!!! note + This page documents the Autotools build. The CMake build differs: fwTPM is off by default and the TPM interface is chosen with the `WOLFTPM_INTERFACE` cache variable (`auto`, `SWTPM`, `WINAPI`, `DEVTPM`, `SPI`, `I2C` or `MMIO`) instead of `--enable-*` flags. See [Building wolfTPM](building.md) for CMake. + +## Reading the tables + +- Every `--enable-X` flag also has a `--disable-X` form. The default column shows the state when the flag is not given. +- A few macros are opt-outs. `WOLFTPM2_NO_WRAPPER` is defined by `--disable-wrapper`, and `WOLFTPM2_NO_WOLFCRYPT` is defined by `--disable-wolfcrypt`. The enable forms do not define them. +- The generated `wolftpm/options.h` records the macros chosen at configure time. + +## General and debug + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-debug[=yes\|no\|verbose\|io]` | no | Adds debug code and turns off optimizations. Defines `DEBUG_WOLFTPM`. `verbose` also defines `WOLFTPM_DEBUG_VERBOSE`, and `io` defines both `WOLFTPM_DEBUG_VERBOSE` and `WOLFTPM_DEBUG_IO`. | +| `--enable-examples` | enabled | Build the example programs. | +| `--enable-wrapper` | enabled | Build the wrapper API. `--disable-wrapper` defines `WOLFTPM2_NO_WRAPPER`. | +| `--enable-wolfcrypt` | enabled | Use wolfCrypt for RNG, authorization sessions and parameter encryption. `--disable-wolfcrypt` defines `WOLFTPM2_NO_WOLFCRYPT`. | +| `--with-wolfcrypt=PATH` | `/usr/local` | Path to the wolfSSL install. The directory must contain `lib` and `include`. | +| `--enable-smallstack` | disabled | Defines `WOLFTPM_SMALL_STACK` to reduce stack usage. Also sets `MAX_COMMAND_SIZE=1024`, `MAX_RESPONSE_SIZE=1350` and `MAX_DIGEST_BUFFER=896`. With `--disable-wolfcrypt` it also sets `MAX_SESSION_NUM=1`. | +| `--enable-provisioning` | enabled | Support for provisioning Initial Device Identity (IDevID) and Attestation Identity Keys. Defines `WOLFTPM_PROVISIONING`. | +| `--enable-firmware` | enabled | TPM firmware upgrade support for Infineon SLB9672/SLB9673 and ST ST33. Defines `WOLFTPM_FIRMWARE_UPGRADE`. Use `--disable-firmware` to remove it. | +| `--enable-fuzz` | disabled | Build the fuzz targets. | + +!!! warning + `WOLFTPM_DEBUG_SECRETS` is not set by any configure option and is off by default. Defining it manually prints sensitive material such as auth values, session keys, bind keys, HMAC keys, hierarchy auth and encryption secrets. Use it only for developer debugging. Never enable it in production builds or on devices that log stdout to persistent storage. + +## I/O layer and bus selection + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-spi` | not set | Intent signal for a SPI hardware build. SPI is the default transport when `--enable-i2c` is not set. Adds no macro, but counts as a hardware selection and so turns off the automatic swTPM and fwTPM defaults. Cannot be combined with `--enable-i2c`. | +| `--enable-i2c` | disabled | I2C TPM support. Defines `WOLFTPM_I2C` and automatically defines `WOLFTPM_ADV_IO`. | +| `--enable-mmio` | disabled | Built-in memory-mapped I/O callbacks. Defines `WOLFTPM_MMIO` and automatically defines `WOLFTPM_ADV_IO`. | +| `--enable-advio` | disabled | Advanced I/O callback signature. Defines `WOLFTPM_ADV_IO`. You do not need to pass it separately with I2C or MMIO. | +| `--enable-wolfhal` | disabled | wolfHAL I/O callbacks. Defines `WOLFTPM_WOLFHAL`. Requires the wolfHAL headers and an application-provided `board.h`. See `hal/README.md` for the required `BOARD_*` definitions. | +| `--enable-hal` | enabled | Build the example HAL interfaces. Defines `WOLFTPM_EXAMPLE_HAL`. | +| `--enable-hal-reset[=LINE]` | disabled | TPM nRST reset HAL through the Linux GPIO character device. Always defines `WOLFTPM_HAL_RESET`. A numeric `LINE` also defines `WOLFTPM_RESET_LINE`. Without a line the default is GPIO24 for ST33 and GPIO4 for Nuvoton. Drive it with `TPM2_IoCb_Reset()`. | +| `--enable-checkwaitstate` | depends on chip | TIS and SPI check-wait-state support. Defines `WOLFTPM_CHECK_WAIT_STATE`. Configure turns it on for autodetect and for every build that is not Infineon-only. | +| `--enable-tislock` | disabled | Defines `WOLFTPM_TIS_LOCK`. Uses a named semaphore to serialize TIS commands across processes. Linux only. | + +`--enable-hal-reset` needs the SPI or I2C hardware HAL. Configure rejects it together with swTPM or `--enable-devtpm`. Because swTPM is the default on common hosts, pass `--enable-spi` or `--enable-i2c` with it. + +!!! note + For I2C support on a Raspberry Pi you may need to enable I2C first: + + 1. Edit `/boot/firmware/config.txt` on current Raspberry Pi OS (for example `sudo vim /boot/firmware/config.txt`). Older images use `/boot/config.txt`. + 2. Uncomment `dtparam=i2c_arm=on`. + 3. Reboot with `sudo reboot`. + +## TPM vendors and modules + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-infineon[=slb9670\|slb9672\|slb9673]` | disabled | Plain `--enable-infineon` selects SLB9672 and defines `WOLFTPM_SLB9672`. `--enable-infineon=slb9670` defines `WOLFTPM_SLB9670`. `--enable-infineon=slb9673` defines `WOLFTPM_SLB9673` and is I2C only: use `--enable-i2c` and do not pass `--enable-spi`. | +| `--enable-st33`, `--enable-st` | disabled | ST ST33 support. Defines `WOLFTPM_ST33`. The two flags are equivalent. | +| `--enable-microchip`, `--enable-mchp` | disabled | Microchip ATTPM20 support. Defines `WOLFTPM_MICROCHIP`. The two flags are equivalent. | +| `--enable-nuvoton` | disabled | Nuvoton NPCT65x/NPCT75x support. Defines `WOLFTPM_NUVOTON`. | +| `--enable-nations` | disabled | Nations Technology NS350 support. Defines `WOLFTPM_NATIONS`. | +| `--enable-sealsq` | disabled | SealSQ QVault post-quantum TPM support. Defines `WOLFTPM_SEALSQ`. | +| `--enable-autodetect` | on when no vendor module is selected | Runtime module detection. Defines `WOLFTPM_AUTODETECT`. | + +Selecting an Infineon device with its argument looks like this: + +```sh +./configure --enable-infineon=slb9670 +./configure --enable-infineon=slb9673 --enable-i2c +``` + +## Operating system transports and simulators + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-devtpm` | disabled | Use the Linux kernel driver (`/dev/tpmrm0` or `/dev/tpm0`). Defines `WOLFTPM_LINUX_DEV`. Cannot be combined with swTPM. | +| `--enable-swtpm` | see below | Talk to a simulator over the swtpm TCP protocol. Defines `WOLFTPM_SWTPM` and `TPM2_SWTPM_PORT`. | +| `--enable-swtpm=uart` | disabled | swtpm protocol over a UART serial port, for fwTPM on embedded targets such as STM32H5. Defines `WOLFTPM_SWTPM`, `WOLFTPM_SWTPM_UART` and `TPM2_SWTPM_PORT`, where the port value is the baud rate (default 115200). | +| `--with-swtpm-port=PORT` | 2321 | Sets `TPM2_SWTPM_PORT`. For `--enable-swtpm=uart` it sets the baud rate instead. | +| `--enable-fwtpm` | see below | Build the firmware TPM (fwTPM) server. Requires wolfCrypt. | +| `--enable-winapi` (alias `--enable-wintbs`) | disabled | Use the Windows TBS API. Defines `WOLFTPM_WINAPI`. Cannot be combined with swTPM or devtpm. | + +### Default simulator behavior + +`--enable-swtpm` and `--enable-fwtpm` are on by default when all of these hold: + +- the host CPU is x86_64, amd64 or aarch64; +- the host OS is not Windows (mingw, cygwin, msys, win32); +- wolfCrypt is enabled; +- no hardware path was selected with any of `--enable-spi`, `--enable-i2c`, `--enable-mmio`, `--enable-devtpm`, `--enable-autodetect`, `--enable-winapi`, `--enable-infineon`, `--enable-st`, `--enable-st33`, `--enable-microchip`, `--enable-nuvoton`, `--enable-nations` or `--enable-sealsq`. + +This applies to macOS and BSD as well as Linux. Everywhere else the default is off. + +!!! warning + A bare `./configure` on these hosts can define both `WOLFTPM_AUTODETECT` and `WOLFTPM_SWTPM`. `WOLFTPM_SWTPM` suppresses the kernel-device detection, so such a build never tries `/dev/tpmrm0` or `/dev/tpm0`. To use a real TPM, pass `--enable-autodetect`, `--enable-devtpm` or a vendor flag explicitly. Explicit `--enable-autodetect` prevents the simulator default and gives the kernel-first behavior: on Linux it tries `/dev/tpmrm0` or `/dev/tpm0` at runtime and falls back to SPI if the kernel driver is not available. + +### fwTPM macros + +| Macro | Where it is set | +| --- | --- | +| `WOLFTPM_FWTPM_BUILD` | Added to the generated `options.h` for any fwTPM build. This is the marker that test scripts look for. | +| `WOLFTPM_FWTPM` | Set only on the fwTPM server and fuzz targets. It gates server-side code in the shared sources. | +| `WOLFTPM_FWTPM_HAL`, `WOLFTPM_ADV_IO` | Added for TIS and shared-memory builds, that is fwTPM without `--enable-swtpm`. Not supported on Windows. | + +### fwTPM-only and NV modes + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-fwtpm-only` | disabled | Build only the fwTPM server. Skips the client library, wrapper and examples, and defines `WOLFTPM2_NO_WRAPPER`. Implies `--enable-fwtpm` and needs wolfCrypt. Not compatible with `--enable-spdm`. | +| `--enable-fwtpm-nv-appendonly` | disabled | Append-only NV journal mode for write-once flash fwTPM ports. Defines `WOLFTPM_FWTPM_NV_APPEND_ONLY`. | + +## SPDM + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-spdm` | disabled | SPDM support. Defines `WOLFTPM_SPDM`. Needs the wolfSPDM submodule: run `git submodule update --init lib/wolfSPDM`. With fwTPM it also defines `WOLFTPM_SPDM_RESPONDER`. | +| `--enable-tcg` | auto under `--enable-spdm` | SPDM TCG Binding mode. Defines `WOLFTPM_SPDM_TCG`. Turned on automatically with fwTPM, Nuvoton or Nations. | +| `--enable-psk` | auto with Nations | SPDM PSK mode. Defines `WOLFTPM_SPDM_PSK`. Requires `--enable-tcg`. | + +Related rules enforced by configure: + +- `--enable-tcg` and `--enable-psk` require `--enable-spdm`. +- `--enable-nuvoton` with SPDM requires `--enable-tcg` and defines `WOLFSPDM_NUVOTON`. +- `--enable-nations` with SPDM requires both `--enable-tcg` and `--enable-psk` and defines `WOLFSPDM_NATIONS`. +- fwTPM with SPDM requires at least one of `--enable-tcg` or `--enable-psk`. +- `--with-wolfspdm` is removed and now fails configure. Use `--enable-spdm`. +- A debug build with SPDM also defines `WOLFSPDM_DEBUG`. + +## Post-quantum (v1.85) + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-v185` | auto-detect | Full TPM 2.0 v1.85 features: ML-DSA and ML-KEM, sign and verify sequence and digest commands, new response codes and capability properties. Defines `WOLFTPM_V185`. Auto-enabled for fwTPM builds when wolfCrypt has both ML-DSA and ML-KEM. | +| `--enable-pqc` | auto-detect | Lean post-quantum subset (ML-DSA and ML-KEM only). Defines `WOLFTPM_PQC`. A fwTPM build promotes it to full v1.85. `--enable-v185` wins if both are given. | +| `--enable-mldsa[=all\|sign-only\|verify-only\|no]` | all | Limit ML-DSA. `sign-only` defines `WOLFTPM_NO_MLDSA_VERIFY`, `verify-only` defines `WOLFTPM_NO_MLDSA_SIGN`, and `no` defines `WOLFTPM_NO_MLDSA`. | +| `--enable-mlkem[=all\|enc\|dec\|no]` | all | Limit ML-KEM. `enc` defines `WOLFTPM_NO_MLKEM_DECAP`, `dec` defines `WOLFTPM_NO_MLKEM_ENCAP`, and `no` defines `WOLFTPM_NO_MLKEM`. | +| `--disable-hash-mldsa` | pre-hash enabled | Drops pre-hash ML-DSA key support. Defines `WOLFTPM_NO_HASH_MLDSA`. | + +Use `--disable-v185` or `--disable-pqc` to turn off post-quantum support, including the auto-detect. Setting both `--enable-mldsa=no` and `--enable-mlkem=no` is an error. With wolfCrypt enabled, PQC needs wolfSSL 5.9.2-stable or later built with ML-DSA (`--enable-mldsa`, or the wolfSSL alias `--enable-dilithium`) and ML-KEM (`--enable-mlkem`). With `--disable-wolfcrypt`, PQC is command marshaling only. + +## Preprocessor defines + +These are not configure options. Set them with `CFLAGS`, for example `./configure CFLAGS="-DWOLFTPM_MAX_RETRIES=3"`. + +| Macro | Effect | +| --- | --- | +| `WOLFTPM_USE_SYMMETRIC` | Enables symmetric AES, hashing and HMAC support for the TLS examples. | +| `WOLFTPM2_USE_SW_ECDHE` | Stops the TLS examples from using the TPM for ECC ephemeral key generation and the shared secret. | +| `TLS_BENCH_MODE` | Enables TLS benchmarking mode. | +| `NO_TPM_BENCH` | Disables the TPM benchmarking example. | +| `WOLFTPM2_ECC_DEFAULT_CURVE` | Curve used by the named wrapper templates that do not take an explicit curve, currently SRK and AIK. Defaults to `TPM_ECC_NIST_P256`, or the smallest enabled curve that meets `ECC_MIN_KEY_SZ`. Override with `-DWOLFTPM2_ECC_DEFAULT_CURVE=TPM_ECC_NIST_P384`. `wolfTPM2_GetKeyTemplate_ECC` and `_ECC_ex` take an explicit curve, so this macro does not remap them, except that P-256 is substituted when `NO_ECC256` is set. | +| `WOLFTPM_MAX_RETRIES` | Default number of times a command is resubmitted when the TPM returns `TPM_RC_RETRY` (the TPM is momentarily busy, for example while persisting the `daUsed` flag on first authorization use of an externally provisioned key without `noDA`). Default 0, which is disabled. Opt in at runtime with `TPM2_SetCommandRetries()` or at build time with `-DWOLFTPM_MAX_RETRIES=N`. wolfTPM does not set `noDA` on every key it creates: the generic key-template APIs use the attributes the caller passes in, and the EK template omits `noDA`, so those keys can hit this condition. | +| `WOLFTPM_NO_RETRY` | Compiles out the `TPM_RC_RETRY` resubmit handling. `TPM_RC_RETRY` is returned to the caller. Conflicts with `WOLFTPM_MAX_RETRIES` greater than 0. | +| `WOLFTPM_LOCALITY_DEFAULT` | TIS locality requested at startup (default 0). Change it at runtime with `wolfTPM2_SetLocality()` on SPI, memory-mapped and swtpm transports. The wolfTPM I2C HAL does not implement locality selection and uses locality 0 only, so a non-zero `wolfTPM2_SetLocality()` on I2C returns `NOT_COMPILED_IN`. | +| `WOLFTPM_TIS_RESET_STALE_LOCALITY` | At startup, releases any active locality other than `WOLFTPM_LOCALITY_DEFAULT` so the default can be granted. Recovers a TPM left wedged when a previous session did not release its locality. Off by default. Use only on single-master buses, since on a shared bus it could clear a locality another master holds. The nRST reset HAL is the alternative. | +| `WOLFTPM_LOCALITY_TIMEOUT_TRIES` | Poll attempts when requesting a locality at runtime (default 1000). Kept small so a locality that cannot be granted fails fast. | +| `WOLFTPM_RESET_LINE` | nRST GPIO line number for the reset HAL. Set it with `--enable-hal-reset=LINE`. | + +## See Also + +- [Building wolfTPM](building.md) +- [System Interfaces](system-interfaces.md) +- [Supported Hardware](supported-hardware.md) +- [Getting Started](getting-started.md) diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 00000000..3853795e --- /dev/null +++ b/docs/building.md @@ -0,0 +1,426 @@ +# Building wolfTPM + +wolfTPM is built on top of wolfSSL (wolfCrypt) and can be built with autotools, CMake, or directly into a bare-metal project using a `user_settings.h` file. This page covers each build method. Per-vendor build steps are on the [Supported Hardware](supported-hardware.md) page, and the full list of configure switches is on the [Build Options](build-options.md) page. + +## Building wolfSSL + +wolfSSL must be built and installed first. It can be downloaded from the [downloads page](https://wolfssl.com/download/) or cloned from GitHub: + +```bash +git clone https://github.com/wolfSSL/wolfssl.git +cd wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +sudo ldconfig +``` + +`autogen.sh` requires automake and libtool: `sudo apt-get install automake libtool`. + +The `--enable-wolftpm` option is equivalent to passing these options: + +```bash +./configure --enable-certgen --enable-certreq --enable-certext \ + --enable-pkcs7 --enable-cryptocb --enable-aescfb +``` + +## Using an alternate wolfSSL directory + +To build wolfTPM against a wolfSSL installed in a non-default location, install wolfSSL to a prefix and point wolfTPM at it with `--with-wolfcrypt`: + +```bash +# cd /your-wolfssl-repo +./autogen.sh # as necessary +./configure --prefix=~/workspace/my_wolfssl_bin --enable-all +make install + +# then for some other library such as wolfTPM: + +# cd /your-wolftpm-repo +./configure --enable-swtpm --with-wolfcrypt=~/workspace/my_wolfssl_bin +``` + +## Building with autotools + +Once wolfSSL is installed, download wolfTPM from the [downloads page](https://wolfssl.com/download/) or clone it from GitHub, then build it: + +```bash +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +./autogen.sh +./configure +make +``` + +Add the options you need to `./configure`. For example, `--enable-devtpm` uses the Linux kernel TPM device, and `--enable-swtpm` uses a TPM simulator. See [Build Options](build-options.md) for the list, and [Supported Hardware](supported-hardware.md) for the options each TPM module needs. + +On Linux x86_64 and aarch64, a bare `./configure` auto-enables the software TPM backends so that `make check` works without hardware. See [System Interfaces](system-interfaces.md). + +## Building using CMake + +CMake supports compiling in many environments, including Visual Studio if CMake support is installed. The commands below can be run in a `Developer Command Prompt`. + +```bash +mkdir build +cd build +# to use installed wolfSSL location (library and headers) +cmake .. -DWITH_WOLFSSL=/prefix/to/wolfssl/install/ +# OR to use a wolfSSL source tree +cmake .. -DWITH_WOLFSSL_TREE=/path/to/wolfssl/ +# build +cmake --build . +``` + +Use `-DWITH_WOLFSSL=` when wolfSSL is already installed (library and headers), or `-DWITH_WOLFSSL_TREE=` to build against a wolfSSL source tree. + +## Bare-metal build + +wolfTPM can be built for bare-metal embedded environments where no operating system is present. In this approach you compile the wolfTPM source files directly into your project instead of using autotools or CMake. It is common for microcontrollers such as ARM Cortex-M, RISC-V, UltraScale+/Versal, Microblaze, and others. + +### Prerequisites + +- wolfCrypt library source code +- wolfTPM library source code +- A TPM 2.0 module connected via SPI (or I2C) + +### Step 1: Define preprocessor macros + +Add these preprocessor macros to your project build settings or compiler command line: + +``` +WOLFTPM_USER_SETTINGS +WOLFSSL_USER_SETTINGS +``` + +These macros tell wolfTPM and wolfSSL to look for a `user_settings.h` file instead of using the autoconf-generated `options.h` file. + +### Step 2: Create a user_settings.h file + +Create a `user_settings.h` file in your project that contains the build configuration options for both wolfSSL and wolfTPM. A reference configuration file is available in the wolfSSL repository: [examples/configs/user_settings_wolftpm.h](https://github.com/wolfSSL/wolfssl/blob/master/examples/configs/user_settings_wolftpm.h). + +Example `user_settings.h` for wolfTPM: + +```c +/* System */ +#define WOLFSSL_GENERAL_ALIGNMENT 4 +#define SINGLE_THREADED +#define WOLFCRYPT_ONLY +#define SIZEOF_LONG_LONG 8 + +/* Platform - bare metal */ +#define NO_FILESYSTEM +#define NO_WRITEV +#define NO_MAIN_DRIVER +#define NO_DEV_RANDOM +#define NO_ERROR_STRINGS +#define NO_SIG_WRAPPER + +/* wolfTPM required features */ +#define WOLF_CRYPTO_CB +#define WOLFSSL_PUBLIC_MP +#define WOLFSSL_AES_CFB +#define HAVE_AES_DECRYPT + +/* ECC options */ +#define HAVE_ECC +#define ECC_TIMING_RESISTANT + +/* RSA options */ +#undef NO_RSA +#define WOLFSSL_KEY_GEN +#define WC_RSA_BLINDING + +/* Big math library */ +#define WOLFSSL_SP_MATH_ALL /* sp_int.c */ +#define WOLFSSL_SP_SMALL +#define SP_INT_BITS 4096 +/* #define SP_WORD_SIZE 32 */ + +/* SHA options: SHA-256 stays enabled, so do not define NO_SHA256 */ +#define WOLFSSL_SHA512 +#define WOLFSSL_SHA384 + +/* Disable unneeded features to reduce footprint */ +#define NO_PKCS8 +#define NO_PKCS12 +#define NO_PWDBASED +#define NO_DSA +#define NO_DES3 +#define NO_RC4 +#define NO_PSK +#define NO_MD4 +#define NO_MD5 +#define WOLFSSL_NO_SHAKE128 +#define WOLFSSL_NO_SHAKE256 +#define NO_DH + +/* Other interesting size reduction options */ +#if 0 + #define RSA_LOW_MEM + #define WOLFSSL_AES_SMALL_TABLES + #define USE_SLOW_SHA + #define USE_SLOW_SHA256 + #define USE_SLOW_SHA512 + #define NO_AES_192 +#endif + +/* Custom random seed source - implement your own */ +#define HAVE_HASHDRBG +#define CUSTOM_RAND_GENERATE_SEED my_rng_seed +``` + +!!! warning + The `NO_*` macros disable algorithms. wolfTPM wrappers and sessions need SHA-256, so never define `NO_SHA256` in this file. + +If you use `CUSTOM_RAND_GENERATE_SEED`, implement your own RNG seed function. This example gets the seed from the TPM with parameter encryption enabled: + +```c +int my_rng_seed(byte* seed, word32 sz) +{ + int rc; + + /* enable parameter encryption for the RNG request */ + rc = wolfTPM2_SetAuthSession(&wolftpm_dev, 0, &wolftpm_session, + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | + TPMA_SESSION_continueSession)); + if (rc == 0) { + rc = wolfTPM2_GetRandom(&wolftpm_dev, seed, sz); + } + wolfTPM2_UnsetAuthSession(&wolftpm_dev, 0, &wolftpm_session); + return rc; +} +``` + +### Step 3: Configure include paths + +Add these directories to your project's include paths: + +1. The wolfSSL root directory, for example `/path/to/wolfssl` +2. The wolfTPM root directory, for example `/path/to/wolftpm` +3. The directory that holds your `user_settings.h` + +Example compiler flags: + +``` +-I/path/to/wolfssl +-I/path/to/wolftpm +-I/path/to/your/project/include +``` + +### Step 4: Add source files + +Add the required source files from wolfSSL and wolfTPM to your project. + +wolfCrypt source files (minimum required for wolfTPM): + +``` +wolfssl/wolfcrypt/src/aes.c +wolfssl/wolfcrypt/src/asn.c +wolfssl/wolfcrypt/src/cryptocb.c +wolfssl/wolfcrypt/src/ecc.c +wolfssl/wolfcrypt/src/hash.c +wolfssl/wolfcrypt/src/hmac.c +wolfssl/wolfcrypt/src/random.c +wolfssl/wolfcrypt/src/rsa.c +wolfssl/wolfcrypt/src/sha.c +wolfssl/wolfcrypt/src/sha256.c +wolfssl/wolfcrypt/src/sha512.c +wolfssl/wolfcrypt/src/sp_int.c +wolfssl/wolfcrypt/src/wc_port.c +wolfssl/wolfcrypt/src/wolfmath.c +``` + +wolfTPM source files: + +``` +wolftpm/src/tpm2.c +wolftpm/src/tpm2_util.c +wolftpm/src/tpm2_packet.c +wolftpm/src/tpm2_tis.c +wolftpm/src/tpm2_wrap.c +wolftpm/src/tpm2_asn.c +wolftpm/src/tpm2_crypto.c +wolftpm/src/tpm2_param_enc.c +wolftpm/src/tpm2_cryptocb.c +wolftpm/src/tpm2_linux.c +``` + +This list matches `src_libwolftpm_la_SOURCES` in `src/include.am`. `tpm2_swtpm.c`, `tpm2_winapi.c` and `tpm2_spdm.c` are only needed for their respective optional builds. The HAL source (one of the `hal/tpm_io*.c` files, see below) is added separately. + +### Step 5: Implement the SPI HAL callback + +wolfTPM needs a single SPI transmit and receive callback to communicate with the TPM module. Implement it for your hardware platform. Reference implementations are in the `hal/` directory of the wolfTPM repository: + +- [hal/tpm_io_xilinx.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_xilinx.c) for Xilinx Microblaze +- [hal/tpm_io_st.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_st.c) for STM32 +- [hal/tpm_io_infineon.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_infineon.c) for Infineon Tricore +- [hal/tpm_io_microchip.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_microchip.c) for Microchip + +#### Standard I/O callback + +The standard SPI callback has this signature: + +```c +typedef int (*TPM2HalIoCb)( + TPM2_CTX* ctx, + const byte* txBuf, byte* rxBuf, + word16 xferSz, + void* userCtx +); +``` + +Example implementation: + +```c +#include +#include + +int TPM2_IoCb(TPM2_CTX* ctx, + const byte* txBuf, byte* rxBuf, word16 xferSz, + void* userCtx) +{ + int ret = TPM_RC_FAILURE; + + /* TODO: Assert SPI chip select */ + spi_cs_assert(); + + /* Perform SPI transfer: send txBuf and receive into rxBuf */ + if (spi_transfer(txBuf, rxBuf, xferSz) == 0) { + ret = TPM_RC_SUCCESS; + } + + /* TODO: De-assert SPI chip select */ + spi_cs_deassert(); + + (void)ctx; + (void)userCtx; + + return ret; +} +``` + +#### Advanced I/O callback + +For platforms that need more control, enable `WOLFTPM_ADV_IO` to use the advanced callback: + +```c +typedef int (*TPM2HalIoCb)( + TPM2_CTX* ctx, + INT32 isRead, UINT32 addr, + BYTE* xferBuf, UINT16 xferSz, + void* userCtx +); +``` + +This gives access to the register address and the read or write direction, for platforms that need separate read and write operations. + +### Step 6: Initialize and use wolfTPM + +After the setup is complete, initialize wolfTPM and start communicating with the TPM: + +```c +#include + +int main(void) +{ + int rc; + WOLFTPM2_DEV dev; + + /* Initialize wolfTPM */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (rc != TPM_RC_SUCCESS) { + /* Handle error */ + return rc; + } + + /* Get TPM capabilities */ + WOLFTPM2_CAPS caps; + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (rc == TPM_RC_SUCCESS) { + /* Use TPM ... */ + } + + /* Cleanup */ + wolfTPM2_Cleanup(&dev); + + return 0; +} +``` + +### Optional build configurations + +To reduce the memory footprint in constrained environments, consider these options in `user_settings.h`: + +```c +/* Reduce stack usage */ +#define WOLFTPM_SMALL_STACK + +/* Disable wrapper layer if using native API only */ +#define WOLFTPM2_NO_WRAPPER + +/* Use smaller RSA key sizes only */ +#define MAX_RSA_KEY_BITS 2048 +``` + +If you know your TPM module type at compile time, select it. Select exactly one module variant, not several: + +```c +/* For Infineon, pick exactly one of these */ +#define WOLFTPM_SLB9670 +/* #define WOLFTPM_SLB9672 */ +/* #define WOLFTPM_SLB9673 */ + +/* For ST ST33 */ +#define WOLFTPM_ST33 + +/* For Nuvoton */ +#define WOLFTPM_NUVOTON + +/* For Microchip ATTPM20 */ +#define WOLFTPM_MICROCHIP +``` + +If no module is specified, define `WOLFTPM_AUTODETECT` to detect the module at runtime. That is the default under `./configure`, but a `user_settings.h` build with no module and no `WOLFTPM_AUTODETECT` falls back to the Infineon SLB9672 (SPI) or SLB9673 (I2C), so define `WOLFTPM_AUTODETECT` explicitly for runtime detection. + +For TPM modules connected via I2C instead of SPI: + +```c +#define WOLFTPM_I2C +#define WOLFTPM_ADV_IO +``` + +You must implement the advanced I/O callback for I2C communication. + +### Cryptographic key storage + +In bare-metal environments, the TPM provides secure storage for cryptographic keys, isolated from main processor memory. Key material never leaves the TPM in plaintext form. + +- Keys created with `TPM2_CreatePrimary` reside in the TPM and return a handle. +- Keys created with `TPM2_Create` return an encrypted blob that can be stored in non-volatile memory and reloaded using `TPM2_Load`. +- Use `TPM2_EvictControl` to store keys persistently in the TPM NVRAM. + +This keeps cryptographic keys protected even if the main processor memory is compromised. + +### Troubleshooting + +SPI communication issues: + +1. Verify SPI clock polarity and phase (typically CPOL=0, CPHA=0 for a TPM). +2. Check the SPI clock speed. Start slow (1 to 10 MHz) and increase. +3. Verify chip select is asserted low during the entire send and receive. +4. Some TPMs require wait states during SPI operations, which means extra bytes are read until the MSB is set to signal response readiness (enabled with `WOLFTPM_CHECK_WAIT_STATE`). +5. Enable debug output with `DEBUG_WOLFTPM` (general), `WOLFTPM_DEBUG_VERBOSE` (detailed), or `WOLFTPM_DEBUG_IO` (SPI and I2C transactions). + +Build errors: + +1. Ensure `WOLFSSL_USER_SETTINGS` and `WOLFTPM_USER_SETTINGS` are defined. +2. Verify the include paths are correct. +3. Check that all required source files are included in the build. + +## See Also + +- [Getting Started](getting-started.md) +- [Build Options](build-options.md) +- [Supported Hardware](supported-hardware.md) +- [System Interfaces](system-interfaces.md) diff --git a/docs/cited-sources.md b/docs/cited-sources.md new file mode 100644 index 00000000..03b9c38f --- /dev/null +++ b/docs/cited-sources.md @@ -0,0 +1,23 @@ +# Cited Sources + +This page lists the references used while writing this manual: the two works cited in the original introduction, followed by the specifications the manual refers to. + +## References + +1. Wikipedia contributors. (2018, May 30). Trusted Platform Module. In _Wikipedia, The Free Encyclopedia_. Retrieved 22:46, June 20, 2018. +2. Arthur W., Challener D., Goldman K. (2015). Platform Configuration Registers. In: _A Practical Guide to TPM 2.0_. Apress, Berkeley, CA. + +## Specifications + +| Specification | Body | Where it applies | +|---|---|---| +| TPM 2.0 Library Specification, versions 1.38, 1.59, 1.84 and 1.85 | Trusted Computing Group (TCG) | The TPM 2.0 command set, structures and behavior that wolfTPM and the fwTPM implement. Version 1.85 adds the post-quantum commands. | +| FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM) | NIST | Post-quantum key encapsulation (ML-KEM-768). | +| FIPS 204, Module-Lattice-Based Digital Signature Standard (ML-DSA) | NIST | Post-quantum signatures (ML-DSA-65). | +| DSP0274, Security Protocol and Data Model (SPDM) Specification | DMTF | The SPDM secured transport used with supported TPM modules and the fwTPM. | + +## See Also + +- [Benchmarks](benchmarks.md) +- [Release Notes](release-notes.md) +- [API Reference](api-reference.md) diff --git a/docs/csharp-wrapper.md b/docs/csharp-wrapper.md new file mode 100644 index 00000000..03b7194e --- /dev/null +++ b/docs/csharp-wrapper.md @@ -0,0 +1,183 @@ +# C# Wrapper + +The `wrapper/CSharp` directory contains a C# wrapper for the wolfTPM TPM 2.0 API. It binds to the native `wolftpm` library through P/Invoke, so the native library must be built first. The tests use NUnit and run on .NET (Windows) or Mono (Linux). + +Build wolfSSL as described in the wolfTPM `README.md`, then build wolfTPM as described below for your platform. On Linux, tests use the swtpm TCP simulator. + +## Windows + +A Visual Studio solution is provided for building the wrappers. To run the tests, update the `.runsettings` file to add the location of `wolftpm.dll`. The file has a placeholder for a vcpkg build, but CMake can also be used to build wolfTPM with Visual Studio. + +Example CMake settings for building wolfTPM on Windows: + +``` +"WOLFTPM_INTERFACE": "WINAPI", +"WOLFTPM_EXAMPLES": "no", +"WOLFTPM_DEBUG": "yes", +"WITH_WOLFSSL": "C:/Users/[username]/wolfssl/out/install/windows-default" +``` + +## Linux + +The wrapper has been tested with the swtpm TCP protocol for use with the simulator. See [SWTPM](system-interfaces.md) for building and running the simulator. + +Build wolfTPM: + +```sh +./autogen.sh +./configure --enable-swtpm +make all +make check +``` + +Install the prerequisites for Mono and NUnit: + +```sh +apt install mono-tools-devel nunit nunit-console +``` + +Then build the wrapper and its tests, and run them: + +```sh +cd wrapper/CSharp +mcs wolfTPM.cs wolfTPM-tests.cs -r:/usr/lib/cli/nunit.framework-2.6.3/nunit.framework.dll -t:library + +# run the selftest case +LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll -run=tpm_csharp_test.WolfTPMTest.TrySelfTest + +# run all tests +LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll +``` + +The selftest run prints output similar to the following: + +``` +Selected test(s): tpm_csharp_test.WolfTPMTest.TrySelfTest + +wolfSSL Entering wolfCrypt_Init +. +Tests run: 1, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0.1530346 seconds + + Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0 + +wolfSSL Entering wolfCrypt_Cleanup +``` + +## API Overview + +All wrapper types are in the `wolfTPM` namespace in `wrapper/CSharp/wolfTPM.cs`. Each one is a thin class around a native wolfTPM object that is allocated and freed through P/Invoke calls into the `wolftpm` library. + +| Type | Purpose | +| --- | --- | +| `Device` | The TPM connection. Holds the native `WOLFTPM2_DEV` and exposes every TPM operation. | +| `Key` | A loaded TPM key, such as the storage root key (SRK) or a primary key. | +| `KeyBlob` | A created key (public and private parts) that can be loaded, used, and saved to a byte array. | +| `Template` | A TPM public template that describes the type and attributes of a new key. | +| `Session` | A TPM authorization session, used for HMAC sessions with parameter encryption. | +| `Csr` | A certificate signing request helper that holds the subject, key usage, and custom extensions. | +| `WolfTpm2Exception` | The exception thrown when a native call fails. | +| `Status` | Enum of common return codes: `TPM_RC_SUCCESS`, `TPM_RC_HANDLE`, `TPM_RC_NV_UNAVAILABLE`, `TPM_RC_SIGNATURE`, `BAD_FUNC_ARG`, and `NOT_COMPILED_IN`. | + +The file also defines enums that mirror native values: `TPM2_Object` (object attribute bits such as `sensitiveDataOrigin`, `userWithAuth`, `decrypt`, `sign`, `noDA`), `TPM2_Alg` (for example `RSA`, `ECC`, `SHA256`, `RSASSA`, `CFB`, `XOR`, `NULL`), `TPM2_ECC` (curves), `SE` (session type), `SESSION_mask`, `TPM_RH` (hierarchies such as `OWNER`, `ENDORSEMENT`, `PLATFORM`), and `X509_Format` (`PEM` or `DER`). + +### Device Lifetime + +`Device` implements `IDisposable`. The constructor calls the native `wolfTPM2_New()`, which also initializes the TPM, so a new `Device` is ready to use. `Dispose()` calls `wolfTPM2_Free()` and clears the pointer. A finalizer calls the same cleanup if you forget, but you should wrap the device in a `using` statement or call `Dispose()` yourself. + +`Key`, `KeyBlob`, `Template`, `Session`, and `Csr` follow the same pattern: the constructor allocates the native object and `Dispose()` frees it. The native return code from the free call is ignored. + +`Device.Ref` returns the native device pointer. `Device` also defines these constants: `MAX_KEYBLOB_BYTES` (2048), `MAX_TPM_BUFFER` (2048), and `INVALID_DEVID` (-2). The first two are buffer sizes used by the tests and may need to be larger on your platform. + +### Errors and Return Values + +Most methods return an `int` and throw `WolfTpm2Exception` on failure, so you do not need to check the result for the common case. The exception has an `ErrorCode` property with the native return code. Its `Message` includes the native function name, the code in hex, and the text from `TPM2_GetRCString`. `Device.GetErrorString(int)` and `Device.GetErrorString(Status)` give the same text for any code. + +A few methods treat some codes as non-fatal and return them instead of throwing: + +- `ReadPublicKey` returns `TPM_RC_HANDLE` when no object exists at the handle. +- `StoreKey` returns `TPM_RC_NV_UNAVAILABLE`. +- `VerifyHashScheme` returns `TPM_RC_SIGNATURE` when the signature does not match. +- `Csr.SetCustomExtension` returns `NOT_COMPILED_IN` when the native library was built without support for it. + +Methods that produce data return a positive size on success: `KeyBlob.GetKeyBlobAsBuffer`, `Device.RsaEncrypt`, `Device.RsaDecrypt`, `Device.SignHashScheme`, `Device.GenerateCSR`, and `Csr.MakeAndSign`. `UnloadHandle` calls the native function directly and returns its code without throwing. + +### Keys, Blobs, and Sessions + +- A `Key` is filled by `CreateSRK`, `CreatePrimaryKey`, `ReadPublicKey`, `LoadRsaPublicKey`, `LoadRsaPrivateKey`, or `ImportRsaPrivateKey`. `GetHandle()` returns the native handle pointer, and `SetKeyAuthPassword` sets the key password. +- A `KeyBlob` is filled by `CreateKey` using a parent `Key` and a `Template`, then loaded with `LoadKey`. `GetKeyBlobAsBuffer` exports it so it can be stored on disk and restored in another process with `SetKeyBlobFromBuffer`. After restoring, load it again with `LoadKey` and call `SetKeyAuthPassword` before using it. +- `Device.StoreKey` and `Device.DeleteKey` move a key or key blob into or out of persistent storage (NV) under a hierarchy such as `TPM_RH.OWNER`. +- Loaded TPM objects stay loaded in the TPM until you free them. Call `Device.UnloadHandle` with the `Key`, `KeyBlob`, or `Session` when you are done. `Dispose()` only frees the managed wrapper and its native memory. +- A `Session` is started with `StartAuth(device, parentKey, encDecAlg)` where `encDecAlg` is `TPM2_Alg.NULL`, `CFB`, or `XOR`. It starts an HMAC session, binds it to authorization slot 1 (or the index given to `Session(int index)`), and enables parameter encryption. End it with `StopAuth(device)`. `Device.StartSession`, `SetAuthSession`, and `ClearAuthSession` are the lower-level calls behind this. + +### Template and Csr + +`Template` fills a native key template: `GetKeyTemplate_RSA`, `GetKeyTemplate_ECC`, `GetKeyTemplate_Symmetric`, the EK, SRK, and AIK variants (`GetKeyTemplate_RSA_EK`, `GetKeyTemplate_ECC_EK`, `GetKeyTemplate_RSA_SRK`, `GetKeyTemplate_ECC_SRK`, `GetKeyTemplate_RSA_AIK`, `GetKeyTemplate_ECC_AIK`), and `SetKeyTemplate_Unique`. + +For a one-call certificate request, use `Device.GenerateCSR` with a subject string, a key usage string, and an `X509_Format`. For more control, build a `Csr` with `SetSubject`, `SetKeyUsage`, and `SetCustomExtension`, then call `MakeAndSign`. Set the `selfSign` argument of the extended overloads to a non-zero value to get a self-signed certificate instead of a request. The extended `Csr.MakeAndSign(..., sigType, selfSign)` overload currently throws on every successful call (it treats the returned output size as an error), so for a self-signed certificate use `Device.GenerateCSR(..., selfSignCert)` until the wrapper is fixed. + +### Other Device Methods + +`SelfTest`, `GetRandom`, `RsaEncrypt`, `RsaDecrypt`, `SignHashScheme`, `VerifyHashScheme`, and `GetHandleValue` are also on `Device`. See the XML comments in `wolfTPM.cs` for each parameter. + +### Example + +This example creates a storage root key, creates and loads an RSA key under it, signs a digest, and verifies the signature. It follows the pattern used in `wolfTPM-tests.cs`. + +```csharp +using System; +using wolfTPM; + +class Example +{ + static void Main() + { + using (Device device = new Device()) + using (Key srk = new Key()) + using (KeyBlob blob = new KeyBlob()) + using (Template template = new Template()) + { + try + { + device.SelfTest(); + device.CreateSRK(srk, TPM2_Alg.RSA, "StorageKeyAuth"); + + template.GetKeyTemplate_RSA((ulong)( + TPM2_Object.sensitiveDataOrigin | + TPM2_Object.userWithAuth | + TPM2_Object.decrypt | + TPM2_Object.sign | + TPM2_Object.noDA)); + + device.CreateKey(blob, srk, template, "MyKeyAuth"); + device.LoadKey(blob, srk); + + byte[] digest = new byte[32]; + device.GetRandom(digest); + + byte[] sig = new byte[256]; + int sigSz = device.SignHashScheme(blob, digest, sig, + TPM2_Alg.RSASSA, TPM2_Alg.SHA256); + Console.WriteLine("Signature is {0} bytes", sigSz); + + int rc = device.VerifyHashScheme(blob, sig, digest, + TPM2_Alg.RSASSA, TPM2_Alg.SHA256); + Console.WriteLine(rc == (int)Status.TPM_RC_SUCCESS ? + "Signature verified" : "Signature invalid"); + + device.UnloadHandle(blob); + device.UnloadHandle(srk); + } + catch (WolfTpm2Exception e) + { + Console.WriteLine("TPM error: " + e.Message); + } + } + } +} +``` + +## See Also + +- [SWTPM](system-interfaces.md) +- [Build Options](build-options.md) +- [Rust Wrapper](rust-wrapper.md) diff --git a/docs/dev/docs-build.md b/docs/dev/docs-build.md new file mode 100644 index 00000000..d7f32373 --- /dev/null +++ b/docs/dev/docs-build.md @@ -0,0 +1,53 @@ +# Building the wolfTPM manual + +This file is for maintainers. It is not part of the published manual (the build +excludes `docs/dev/`). + +## Layout + +`docs/` is the single source of the manual. The `wolfSSL/documentation` repo +renders it to HTML and PDF for the website; nothing in `documentation/wolfTPM/` +holds manual content any more. + +- `docs/*.md` are the English manual pages. Each one is a page in `mkdocs.yml` + `nav`, and the set of pages in the nav must match the files on disk. +- `docs/fwtpm/` is the self-contained firmware TPM section. +- `docs/ja/` is the Japanese mirror, built from `mkdocs-ja.yml`. +- `docs/assets/` holds the logo and CSS for local `mkdocs serve` previews only. + The website build takes those from the documentation repo's `common/`. +- `docs/dev/` holds maintainer notes like this one and is kept out of the manual. +- The API reference pages (`group__*.md`, `*_8h.md`) are generated at build time + by Doxygen and doxybook2 from the headers, so they are listed in the nav but + do not exist in `docs/`. + +Keep the `mkdocs.yml` nav and the `mkdocs-ja.yml` nav in step with the pages. + +## Local build + +Run from the repo root: + +```sh +git clone --recurse-submodules https://github.com/wolfSSL/documentation.git build/documentation +git -C build/documentation checkout "$(cat tools/docs-manual/documentation-rev)" +docker build --pull -t wolftpm-docs:local docker/docs +docker run --rm --user "$(id -u):$(id -g)" --env HOME=/tmp \ + --mount "type=bind,source=$PWD,target=/work/wolfTPM" \ + --workdir /work/wolfTPM wolftpm-docs:local \ + python3 tools/docs_manual.py build \ + --documentation-root /work/wolfTPM/build/documentation \ + --source-root /work/wolfTPM --target all +``` + +Outputs land in `build/documentation/wolfTPM/`: `html/` and `wolfTPM-Manual.pdf`. +Add `--lang ja` for the Japanese manual (`wolfTPM-Manual-jp.pdf`). For a quick +HTML preview without the full toolchain, `mkdocs serve` against `mkdocs.yml` +works once `mkdocs` and `mkdocs-material` are installed; the generated API pages +show as warnings because Doxygen has not run. + +## Website + +The `wolfSSL/documentation` repo has a `wolfTPM` target that clones this repo at +a pinned ref and runs `tools/docs_manual.py`. The nightly build publishes to +`https://www.wolfssl.com/documentation/manuals/wolftpm/`. The website upload list +lives outside these public repos; if it names manuals explicitly rather than +publishing all build output, it needs a one-time wolfTPM entry. diff --git a/docs/embedded-integrations.md b/docs/embedded-integrations.md new file mode 100644 index 00000000..837ce124 --- /dev/null +++ b/docs/embedded-integrations.md @@ -0,0 +1,522 @@ +# Embedded Integrations + +This page collects the platform and IDE integrations shipped with wolfTPM: Espressif ESP-IDF, Zephyr, QNX, IAR Embedded Workbench, Visual Studio, and Das U-Boot. For the STM32 Cube Pack, see [STM32CubeIDE](stm32cube.md). + +## Espressif ESP-IDF + +The Espressif project lives in `IDE/Espressif`. Wolf-specific settings for wolfTPM are in the wolfSSL `user_settings.h` file, typically found in `[project]/components/wolfssl/include`. + +Build from a shell with ESP-IDF available (shown here for VisualGDB using v5.2): + +```sh +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM/IDE/Espressif + +# set your path to ESP-IDF +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.2 + +. ${WRK_IDF_PATH}/export.sh +idf.py build +``` + +### Memory + +The initial minimum memory requirement is 35KB of stack. See `sdkconfig.defaults`. The memory currently assigned is 50960. + +### Pin Assignments (I2C) + +The following pin assignments are used by default. You can change them in `menuconfig`. + +| | SDA | SCL | +| --- | --- | --- | +| ESP I2C Master | I2C_MASTER_SDA | I2C_MASTER_SCL | +| TPM2 Device | SDA | SCL | + +For the default values of `I2C_MASTER_SDA` and `I2C_MASTER_SCL`, see `Example Configuration` in `menuconfig`. No external pull-up resistors are needed on SDA and SCL, because the driver enables the internal pull-ups. + +### Troubleshooting I2C + +- Printing to the UART during an I2C transaction can affect timing and cause errors. +- Make sure the TPM module has been reset after a flash update. +- Check the wiring: `SCL` to `SCL`, `SDA` to `SDA`. Also connect GND. Vcc is 3.3V only. +- Make sure the proper pins are connected on the ESP32. The default SCL is `GPIO 19` and the default SDA is `GPIO 18`. +- Test with a single I2C device before testing alongside other I2C boards. +- When using multiple I2C boards, check for appropriate pull-ups. See the data sheet. +- Reset the TPM device again. Press the button on the TPM SLB9673 eval board, or set TPM pin 17 as appropriate. + +## Zephyr + +The Zephyr port is in the `zephyr` directory of the wolfTPM source tree. It targets the [Zephyr Project](https://www.zephyrproject.org/) and provides the following: + +| Path | Contents | +| --- | --- | +| `modules/lib/wolftpm` | wolfTPM library code | +| `modules/lib/wolftpm/zephyr/` | Configuration and CMake files for wolfTPM as a Zephyr module | +| `modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_caps` | wolfTPM capabilities sample application | +| `modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test` | wolfTPM wrapper test application | + +### Set Up as a Zephyr Module + +Follow the [Zephyr getting started guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html) to set up a Zephyr project. Then add wolfTPM as a project in your `west.yml`: + +```yaml +manifest: + remotes: + # + - name: wolftpm + url-base: https://github.com/wolfssl + + projects: + # + - name: wolftpm + path: modules/lib/wolftpm + revision: master + remote: wolftpm +``` + +!!! note + wolfTPM depends on wolfSSL, so also add wolfSSL to the `west.yml` in the same way. + +Update west's modules: + +```sh +west update +``` + +West now recognizes wolftpm as a module and includes its Kconfig and `CMakeLists.txt` in the build system. + +### Build and Run the Wrap Test + +To build apps without running `west zephyr-export`, set `CMAKE_PREFIX_PATH` to the location of the Zephyr SDK and build from the `zephyr` directory. For example: + +```sh +CMAKE_PREFIX_PATH=/path/to/zephyr-sdk- west build -p always -b qemu_x86 ../modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test/ +``` + +Build and run `wolftpm_wrap_test`: + +```sh +cd [zephyrproject] +west build -p auto -b qemu_x86 modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test +west build -t run +``` + +### Build and Run the Capabilities Sample + +Build and run `wolftpm_wrap_caps`: + +```sh +cd [zephyrproject] +west build -p auto -b qemu_x86 modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_caps +west build -t run +``` + +## QNX + +These steps create a QNX Momentics project that uses wolfTPM over the QNX SPI driver. The files are in `IDE/QNX`. + +### Create a QNX Application + +1. Create folders for libraries (`lib`) and includes (`inc`). +2. Add the library sources to the `lib` directory as `wolfssl` and `wolftpm`. +3. Edit the Makefile to build the sources and include directories: + +``` +# wolfSSL and wolfTPM library includes/sources +INCLUDES += -I./inc -I./lib/wolftpm -I./lib/wolfssl +CCFLAGS_all += -DWOLFSSL_USER_SETTINGS -DWOLFTPM_USER_SETTINGS + +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/*.c) +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/port/arm/*.c) +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/port/xilinx/*.c) +SRCS += $(call wildcard, lib/wolftpm/src/*.c) + +# The QNX SPI Driver +LIBS += -lspi-master +``` + +4. Create `inc/user_settings.h` for all wolf-specific settings. Here is a template: + +```c +#ifndef WOLF_USER_SETTINGS_H +#define WOLF_USER_SETTINGS_H + +/* TPM */ +#define WOLFTPM_AUTODETECT +#define WOLFTPM_CHECK_WAIT_STATE +#define WOLFTPM_ADV_IO /* use advanced IO HAL callback */ +#define TPM_TIMEOUT_TRIES 100000 + +/* always perform self-test (some chips require) */ +#define WOLFTPM_PERFORM_SELFTEST + +/* Reduce stack use */ +#define MAX_COMMAND_SIZE 1024 +#define MAX_RESPONSE_SIZE 1350 +#define MAX_DIGEST_BUFFER 896 + +/* Debugging */ +#if 1 + #define DEBUG_WOLFTPM + //#define WOLFTPM_DEBUG_VERBOSE + //#define WOLFTPM_DEBUG_IO + //#define WOLFTPM_DEBUG_TIMEOUT +#endif + +/* Platform */ +#define WOLFCRYPT_ONLY +#define SINGLE_THREADED +#define NO_FILESYSTEM +#define WOLFSSL_IGNORE_FILE_WARN +#define WOLFSSL_HAVE_MIN +#define WOLFSSL_HAVE_MAX + +/* Math */ +#define ECC_TIMING_RESISTANT +#define TFM_TIMING_RESISTANT +#define USE_FAST_MATH +#define FP_MAX_BITS (2 * 4096) +#define WOLFSSL_NO_HASH_RAW +#define ALT_ECC_SIZE + +/* Enables */ +#define HAVE_ECC +#define ECC_SHAMIR +#define HAVE_AESGCM +#define GCM_TABLE_4BIT + +/* Disables */ +#define NO_MAIN_DRIVER +#define NO_WOLFSSL_MEMORY +#define NO_ASN +#define NO_ASN_TIME +#define NO_CODING +#define NO_CERTS +#define NO_PSK + +#define NO_PWDBASED +#define NO_DSA +#define NO_RC4 +#define NO_MD4 +#define NO_MD5 +#define NO_SHA +#define NO_HC128 +#define NO_RABBIT +#define NO_DES3 + +#endif /* !WOLF_USER_SETTINGS_H */ +``` + +5. For the wolfTPM HAL, use `tpm_io.c` directly or copy the required HAL interface into your own `.c` file. See [HAL I/O Callback](hal-io-callback.md). +6. Add the wolfTPM example code to your own `.c` file. +7. Consider the QNX BSP SPI master patch below. It lets multiple calls run with chip select asserted, which the SPI wait states require. + +### QNX SPI Master Patch for Manual Chip Select + +Edit the following QNX BSP files. + +1. `bsp/src/hardware/spi/xzynq/aarch64/dll.le.zcu102/xzynq_spi.c`: + +```diff +@@ -442,7 +442,7 @@ static void xzynq_setup(xzynq_spi_t *dev, uint32_t device) + spi_debug1("%s: CONFIG_SPI_REG = 0x%x", __func__, dev->ctrl[id]); + #endif + +- if(dev->fcs) { ++ if(dev->fcs || (devlist[id].cfg.mode & SPI_MODE_MAN_CS)) { + out32(base + XZYNQ_SPI_CR_OFFSET, dev->ctrl[id] | XZYNQ_SPI_CR_MAN_CS); + } else { + out32(base + XZYNQ_SPI_CR_OFFSET, dev->ctrl[id]); +@@ -621,7 +621,7 @@ void *xzynq_xfer(void *hdl, uint32_t device, uint8_t *buf, int *len) + reset = 1; + } + +- if(!dev->fcs) { ++ if(!dev->fcs && !(devlist[id].cfg.mode & SPI_MODE_MAN_CS)) { + xzynq_spi_slave_select(dev, id, 0); + } +``` + +2. `bsp/src/hardware/spi/xzynq/config.c`: + +```diff +@@ -72,6 +73,16 @@ int xzynq_cfg(void *hdl, spi_cfg_t *cfg, int cs) + /* Enable ModeFail generation */ + ctrl |= XZYNQ_SPI_CR_MFAIL_EN; + ++ if (cfg->mode & SPI_MODE_MAN_CS) ++ ctrl |= XZYNQ_SPI_CR_MAN_CS; /* enable manual CS mode */ ++ ++ if (cfg->mode & SPI_MODE_CLEAR_CS) { ++ /* make sure all chip selects are de-asserted */ ++ /* set all CS bits high to de-assert */ ++ out32(base + XZYNQ_SPI_CR_OFFSET, ++ in32(base + XZYNQ_SPI_CR_OFFSET) | XZYNQ_SPI_CR_CS); ++ } ++ +``` + +3. `target/qnx7/usr/include/hw/spi-master.h`: + +```diff +@@ -71,6 +71,8 @@ typedef struct { + #define SPI_MODE_RDY_LEVEL (2 << 14) /* Low level signal */ + #define SPI_MODE_IDLE_INSERT (1 << 16) ++#define SPI_MODE_MAN_CS (1 << 17) /* Manual Chip select */ ++#define SPI_MODE_CLEAR_CS (1 << 18) /* Clear all chip selects (used with SPI_MODE_MAN_CS) */ + + #define SPI_MODE_LOCKED (1 << 31) /* The device is locked by another client */ +``` + +For questions, email support@wolfssl.com. + +## IAR-EWARM + +The `IDE/IAR-EWARM` directory holds an IAR Embedded Workbench for ARM project for the TPM 2.0 wrapper API. It has no README, so the notes below come from the project files. + +| Path | Contents | +| --- | --- | +| `ewarm-tpm2.eww` | IAR workspace | +| `ewarm-tpm2.ewp` | IAR project | +| `source/main.c` | Application entry point | +| `source/tpm_main.c` | TPM example code using `wolftpm/tpm2.h` and `wolftpm/tpm2_wrap.h` | +| `header/tpm_main.h` | Header for the example code | + +Open `ewarm-tpm2.eww` in IAR Embedded Workbench to build. The example uses fixed handles for the storage key (`0x81000000`), RSA key (`0x81000010`), RSA public key (`0x81000011`), and an NV certificate index (`0x01800000`). + +### IAR Project Settings + +These settings come from `ewarm-tpm2.ewp`. The project uses the ARM toolchain and has Debug and Release configurations. + +| Setting | Value | +| --- | --- | +| Include paths | `$PROJ_DIR$\..\..` (the wolfTPM root, so `#include ` resolves) and `$PROJ_DIR$\header` | +| Debug preprocessor define | `WOLFTPM2_NO_WOLFCRYPT` | +| Release preprocessor define | `NDEBUG` | +| wolfTPM sources in the `lib/wolftpm` group | `src/tpm2.c`, `src/tpm2_packet.c`, `src/tpm2_tis.c`, `src/tpm2_wrap.c` | +| Application sources | `source/main.c`, `source/tpm_main.c` | + +The project does not add wolfSSL sources or include paths, and it does not define `WOLFTPM_USER_SETTINGS`. The Debug configuration builds wolfTPM without wolfCrypt through `WOLFTPM2_NO_WOLFCRYPT`. The Release configuration does not define it, so a Release build needs wolfSSL headers and sources added to the project. Adjust the include paths and defines to match how you build wolfSSL for your target. + +!!! note + The project file does not set a device or core. Select your target device in Options, General Options, Target before building. The project file was last saved by IAR EWARM 8.30.1 (build 17146). No other IAR versions are recorded in the repository, so none are listed as tested. + +### IAR HAL + +The project compiles `src/tpm2_tis.c`, so it uses the standard TPM TIS layer with the IO callback HAL (see [HAL I/O Callback](hal-io-callback.md)). It does not include a ready-made SPI driver. `source/tpm_main.c` defines a stub callback, `TPM2_IoCb`, that returns `TPM_RC_FAILURE` until you replace the `TODO` line with a call to your own SPI transfer routine. The callback is passed to `wolfTPM2_Init` in `TPM2_Cust_Example`. + +The example then reads the persistent storage key at `0x81000000`. If it is missing, it creates an RSA primary storage key, makes it persistent, and does the same for the RSA key at `0x81000010`. It uses the passwords `ThisIsMyStorageKeyAuth` and `ThisIsMyKeyAuth`, and it unloads both handles and calls `wolfTPM2_Cleanup` before it returns. + +## Visual Studio + +The `IDE/VisualStudio` directory has a Visual Studio solution, `wolftpm.sln`, with projects for building wolfSSL, wolfTPM, and some examples: `wolfssl.vcxproj`, `wolftpm.vcxproj`, `wrap_test.vcxproj`, `wolfcrypt_test.vcxproj`, and `tls_server.vcxproj`. The solution and projects are based on Visual Studio 2015 and can be retargeted to a newer version when opened. + +All build settings are in `IDE/VisualStudio/user_settings.h`. The projects assume the `wolftpm` and `wolfssl` directories sit next to each other. + +The solution supports the FIPS Ready bundle from the wolfSSL website. To use it, enable the `#if 0` FIPS section in `user_settings.h`. See `wolfssl/IDE/WIN10/README.txt` in the wolfSSL source for how to set the FIPS integrity check in `fips_test.c` at run time. + +### Build Steps + +1. Place the `wolftpm` and `wolfssl` source directories next to each other. The projects use include paths such as `../../` and `../../../wolfssl/`. +2. Open `IDE/VisualStudio/wolftpm.sln`. The projects specify platform toolset `v110`, so Visual Studio asks to retarget them to the toolset you have installed. +3. Choose a configuration (`Debug`, `Release`, `DLL Debug`, or `DLL Release`) and a platform (`Win32` or `x64`). +4. Build the solution. `wolftpm` references the `wolfssl` project, so wolfSSL builds first. + +The wolfTPM CI workflow builds the solution from the command line with MSBuild and the `v142` toolset, using the `Debug` configuration on `x64`: + +```sh +msbuild /m /p:PlatformToolset=v142 /p:Platform=x64 /p:Configuration=Debug wolftpm\IDE\VisualStudio\wolftpm.sln +``` + +The solution contains five projects: `wolfssl`, `wolftpm`, `wolfcrypt_test`, `wrap_test` (built from `examples/wrap/wrap_test.c`), and `tls_server`. + +### Role of user_settings.h + +The `wolftpm` project defines `WOLFSSL_USER_SETTINGS` and `WOLFTPM_USER_SETTINGS`, so both libraries read `IDE/VisualStudio/user_settings.h` instead of a generated `options.h`. The file is a template for wolfTPM with TLS 1.2 and 1.3. Settings that matter to wolfTPM include: + +| Define | Purpose | +| --- | --- | +| `WOLFTPM_WINAPI` | Set when `_WIN32` is defined. Selects the Windows TBS transport. | +| `WOLFSSL_AES_CFB` | Required for TPM parameter encryption. | +| `WOLFSSL_PUBLIC_MP` | Exposes `mp_` math functions, needed for TPM ECC secret encryption. | +| `WOLFTPM_AUTODETECT` | Supports any TPM model with safe defaults. | +| `WOLF_CRYPTO_CB` and `HAVE_PK_CALLBACKS` | Callbacks used to run crypto on the TPM. | +| `WOLFSSL_CERT_GEN`, `WOLFSSL_CERT_REQ`, `WOLFSSL_CERT_EXT` | Certificate and CSR generation. | + +The file also has a disabled `#if 0` FIPS section, a math option (`WOLFSSL_SP_MATH_ALL` without FIPS), and a debug section with `DEBUG_WOLFSSL` turned on. + +### Windows TPM Transport + +The Visual Studio projects use the Windows TBS (TPM Base Services) interface, not SPI or a simulator. `user_settings.h` defines `WOLFTPM_WINAPI` on Windows, `wolftpm.vcxproj` compiles `src/tpm2_winapi.c`, and the example projects (`wrap_test`, `tls_server`) and the DLL configurations of `wolftpm` link `tbs.lib`. In this mode wolfTPM calls the TBS API from `tbs.h`. It rejects an IO callback or user context, so pass `NULL` for both to `wolfTPM2_Init`. See [Windows TBS](system-interfaces.md) for NV access limits and how to run the examples. + +## U-Boot + +wolfTPM provides experimental support for Das U-Boot, with these features: + +- Uses the software SPI driver in U-Boot for TPM communication. +- Implements TPM 2.0 driver functionality through its internal TIS layer. +- Provides native API access to all TPM 2.0 commands. +- Includes the wrapper API for common TPM 2.0 operations. +- Supports two integration paths: + - `__linux__`: uses the existing tpm interface through `tpm2_linux.c`. + - `__UBOOT__`: direct SPI communication through `tpm_io_uboot.c`. + +The example files are in `examples/u-boot`. + +### U-Boot Commands + +These commands are available through the `wolftpm` interface. + +Basic commands: + +| Command | Description | +| --- | --- | +| `help` | Show help text. | +| `device [num device]` | Show all devices or set the specified device. | +| `info` | Show information about the TPM. | +| `state` | Show internal state from the TPM, if available. | +| `autostart` | Initialize the TPM, perform a Startup(clear), and run a full selftest sequence. | +| `init` | Initialize the software stack. Must be the first command. | +| `startup []` | Issue a TPM2_Startup command. `` is `TPM2_SU_CLEAR` (reset state) or `TPM2_SU_STATE` (preserved state). `[]` is an optional shutdown with "off". | +| `self_test ` | Test TPM capabilities. `` is "full" (all tests) or "continue" (untested tests only). | + +PCR operations: + +| Command | Description | +| --- | --- | +| `pcr_extend []` | Extend a PCR with a digest. | +| `pcr_read []` | Read a PCR to memory. | +| `pcr_allocate []` | Reconfigure a PCR bank algorithm. | +| `pcr_setauthpolicy` or `pcr_setauthvalue []` | Change the PCR access key. | +| `pcr_print` | Print the current PCR state. | + +Security management: + +| Command | Description | +| --- | --- | +| `clear ` | Issue TPM2_Clear. `` is `TPM2_RH_LOCKOUT` or `TPM2_RH_PLATFORM`. | +| `change_auth []` | Change a hierarchy password. `` is `TPM2_RH_LOCKOUT`, `TPM2_RH_ENDORSEMENT`, `TPM2_RH_OWNER`, or `TPM2_RH_PLATFORM`. | +| `dam_reset []` | Reset the internal error counter. | +| `dam_parameters []` | Set dictionary attack mitigation (DAM) parameters. | +| `caps` | Show TPM capabilities and info. | + +Firmware management: + +| Command | Description | +| --- | --- | +| `firmware_update ` | Update the TPM firmware. | +| `firmware_cancel` | Cancel a TPM firmware update. | + +### Enable wolfTPM in U-Boot + +Add these options to your board's defconfig: + +``` +CONFIG_TPM=y +CONFIG_TPM_V2=y +CONFIG_TPM_WOLF=y +CONFIG_CMD_WOLFTPM=y +``` + +Or use `make menuconfig` and enable: + +- Device Drivers, TPM, TPM 2.0 Support +- Device Drivers, TPM, wolfTPM Support +- Command line interface, Security commands, Enable wolfTPM commands + +### Build and Run with QEMU + +This procedure runs U-Boot with wolfTPM under QEMU, using a TPM simulator. + +1. Install swtpm: + +```sh +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +./autogen.sh +make +``` + +2. Build U-Boot: + +```sh +make distclean +export CROSS_COMPILE=aarch64-linux-gnu- +export ARCH=aarch64 +make qemu_arm64_defconfig +make -j4 +``` + +3. Create the TPM state directory: + +```sh +mkdir -p /tmp/mytpm1 +``` + +4. Start swtpm in the first terminal: + +```sh +swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --log level=20 +``` + +5. Start QEMU in a second terminal: + +```sh +qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 -bios u-boot.bin -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis-device,tpmdev=tpm0 +``` + +6. Example boot output: + +``` +U-Boot 2025.07-rc1-ge15cbf232ddf-dirty (May 06 2025 - 16:25:56 -0700) + +DRAM: 128 MiB +using memory 0x46658000-0x47698000 for malloc() +Core: 52 devices, 15 uclasses, devicetree: board +Flash: 64 MiB +Loading Environment from Flash... *** Warning - bad CRC, using default environment + +In: serial,usbkbd +Out: serial,vidconsole +Err: serial,vidconsole +No USB controllers found +Net: eth0: virtio-net#32 + +Hit any key to stop autoboot: 0 +=> tpm2 help +tpm2 - Issue a TPMv2.x command + +Usage: +tpm2 [] + +device [num device] + Show all devices or set the specified device +info + Show information about the TPM. +``` + +7. Example commands: + +``` +=> tpm2 info +tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] +=> tpm2 startup TPM2_SU_CLEAR +=> tpm2 get_capability 0x6 0x20e 0x200 1 +Capabilities read from TPM: +Property 0x6a2e45a9: 0x6c3646a9 +=> tpm2 pcr_read 10 0x100000 +PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 +``` + +8. To exit QEMU, press Ctrl-A followed by X. + +## See Also + +- [STM32CubeIDE](stm32cube.md) +- [Building](building.md) +- [System Interfaces](system-interfaces.md) +- [HAL I/O Callback](hal-io-callback.md) +- [Supported Hardware](supported-hardware.md) +- [Windows TBS](system-interfaces.md) diff --git a/docs/examples-overview.md b/docs/examples-overview.md new file mode 100644 index 00000000..67039ad7 --- /dev/null +++ b/docs/examples-overview.md @@ -0,0 +1,104 @@ +# Examples Overview + +The wolfTPM examples show how to use a TPM 2.0 module through both the native `TPM2_*` API and the `wolfTPM2_*` wrapper API. They build with the library and are ready to run after a successful install. To connect them to your hardware platform, see the `TPM2_IoCb` function in `tpm_io.c` and the [HAL I/O callback guide](hal-io-callback.md). + +The examples create RSA and ECC keys in NV for testing, using the handles defined in `./examples/tpm_test.h` (see [Run flags and test handles](#run-flags-and-test-handles)). The PKCS #7 and TLS examples need CSRs generated and signed with a test script. See the CSR and certificate signing section of `examples/README.md` for the steps. + +Some examples are vendor specific, such as the extra GPIO examples for the ST33 and NPCT75x TPMs. These only work on that hardware. + +## Native API test + +Demonstrates calling the native `TPM2_*` APIs. + +```sh +./examples/native/native_test +``` + +## Wrapper API test + +Demonstrates calling the `wolfTPM2_*` wrapper APIs. + +```sh +./examples/wrap/wrap_test +``` + +## Crypto primitive examples + +Small, focused examples for common TPM crypto operations: + +```sh +./examples/wrap/getrandom [bytes] +./examples/wrap/hash [-sha384|-sha512] +./examples/wrap/encrypt_decrypt [-aescfb|-aesctr|-aescbc] +./examples/keygen/ecdh +``` + +| Command | What it does | +| --- | --- | +| `getrandom [bytes]` | Gets random bytes from the TPM RNG (default 32). | +| `hash` | Hashes a message with a TPM hash sequence. SHA-256 is the default; use `-sha384` or `-sha512` to change it. | +| `encrypt_decrypt` | Symmetric encrypt/decrypt round trip. AES-CFB is the default. | +| `ecdh` | ECDH (P-256) key agreement that produces a shared secret. | + +!!! note + Many TPMs disable `TPM2_EncryptDecrypt` entirely because of export controls. The `encrypt_decrypt` example skips gracefully when the command is unavailable. + +## Parameter encryption + +To enable parameter encryption in the examples, use `-aes` for AES-CFB mode or `-xor` for XOR mode. Only some TPM commands and responses support it. If the `TPM2_` API entry has `CMD_FLAG_ENC2` or `CMD_FLAG_DEC2` set in its flags, the command uses parameter encryption or decryption. + +Only the first parameter of a TPM command can be encrypted, and it must be of type `TPM2B_DATA`. Examples are the password auth of a TPM key or the qualifying data of a TPM2.0 Quote. The request and the response can be encrypted together or separately. The `sessionAttributes` control this: + +* `TPMA_SESSION_decrypt` for the command request +* `TPMA_SESSION_encrypt` for the command response + +Either one can be set alone, or both can be set in the same authorization session. This is up to the developer. + +Examples that use parameter encryption: + +* Key generation with an encrypted authorization value. See [Key Management](key-management.md). +* A secure vault for keys with encrypted NV authorization. See [Sealing and NVRAM](sealing-and-nvram.md). +* A TPM2.0 Quote with encrypted user data. The qualifying data supplied for a Quote is arbitrary data that goes into the signed Quote structure. With parameter encryption the host sends it to the TPM in encrypted form, which protects it from man-in-the-middle attacks. See [Attestation](attestation.md). + +### Post-quantum session keys (v1.85) + +On a v1.85 PQC capable TPM, the parameter encryption session can be keyed with a post-quantum primary instead of an RSA or ECC storage key. ML-KEM is decrypt capable and is used as the session salt key. ML-DSA is sign only and is used as the session bind key. The RSA or ECC storage key, where one is needed (for example as the parent of a created child), is unchanged. + +Pass `-mlkem[=512|768|1024]` to salt the session with an ML-KEM key, or `-mldsa[=44|65|87]` to bind it to an ML-DSA key. These flags are accepted by `wrap_test`, `pcr/quote`, `nvram/store` and `nvram/counter`. The `keygen` example uses `-paramkey=mlkem[=...]` and `-paramkey=mldsa[=...]` instead, because `-mlkem` and `-mldsa` there select the child key type. + +```sh +./examples/wrap/wrap_test -aes -mlkem=768 +./examples/pcr/quote 16 quote.blob -ecc -xor -mldsa=65 +./examples/nvram/counter -aes -mldsa=65 +./examples/keygen/keygen keyblob.bin -ecc -aes -paramkey=mlkem=768 +``` + +## Run flags and test handles + +The handles used by the examples are defined in `./examples/tpm_test.h`. + +| Define | Value | Purpose | +| --- | --- | --- | +| `TPM2_DEMO_STORAGE_KEY_HANDLE` | `0x81000200` | Persistent storage key (RSA) | +| `TPM2_DEMO_STORAGE_EC_KEY_HANDLE` | `0x81000201` | Persistent storage key (ECC) | +| `TPM2_DEMO_PERSISTENT_KEY_HANDLE` | `0x81000202` | Persistent key for common use | +| `TPM2_DEMO_HMAC_KEY_HANDLE` | `0x81000210` | Persistent HMAC key | + +The RSA and ECC test keys and certificates use an index offset added to a base address: + +| Define | Index | Handle | Type | +|----------------------------------------|----------|----------------------------|----------------------| +| `TPM2_DEMO_RSA_KEY_HANDLE` | `0x20` | `0x81000000 + 0x20` | Persistent key | +| `TPM2_DEMO_RSA_CERT_HANDLE` | `0x20` | `0x01800000 + 0x20` | NV index | +| `TPM2_DEMO_ECC_KEY_HANDLE` | `0x21` | `0x81000000 + 0x21` | Persistent key | +| `TPM2_DEMO_ECC_CERT_HANDLE` | `0x21` | `0x01800000 + 0x21` | NV index | + +!!! warning + To run the TLS server and client examples on the same machine, build wolfTPM with `WOLFTPM_TIS_LOCK` (`./configure --enable-tislock`). It adds a named semaphore that protects concurrent access to the SPI device between processes. + +## See Also + +* [Key Management](key-management.md) +* [Attestation](attestation.md) +* [Sealing and NVRAM](sealing-and-nvram.md) +* [HAL I/O callback guide](hal-io-callback.md) diff --git a/docs/firmware-update.md b/docs/firmware-update.md new file mode 100644 index 00000000..a2357cde --- /dev/null +++ b/docs/firmware-update.md @@ -0,0 +1,368 @@ +# Firmware Update + +wolfTPM can update the firmware of some TPM 2.0 modules. Enable the examples and library support by configuring with `--enable-firmware`. Supported parts: + +- Infineon SLB9672 (SPI) and SLB9673 (I2C) TPM 2.0 modules. Infineon has open sourced its firmware update. +- STMicroelectronics ST33KTPM TPM 2.0 modules. Support covers generation 1 firmware (RSA signed manifest), generation 9 firmware below 512 (ECDSA signed manifest) and generation 9 firmware at 512 and above (LMS signature requirement). + +Firmware update programs are in `examples/firmware/`: `ifx_fw_extract.c`, `ifx_fw_update.c`, `st33_fw_update.c` and the policy helper `firmware_policy.c`. + +## Infineon firmware (extract and update) + +### Extracting the firmware + +Infineon releases firmware as a .bin file (for example `TPM20_15.23.17664.0_R1.BIN`). The .bin contains a 16 byte GUID header, at least one manifest based on key group, and the firmware. A typical manifest is 3KB and the firmware is 920KB. + +The host side tool `ifx_fw_extract` extracts the manifest and firmware data file required for a TPM upgrade. + +```sh +# Build host tool +make + +# Help +./ifx_fw_extract --help +Usage: + ifx_fw_extract + ifx_fw_extract + +# Find key groups in .bin +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 + +# Extract manifest and firmware data files for key group +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN 7 TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 +Chosen group found: 00000007 +Manifest size is 3224 +Data size is 934693 +Writing TPM20_26.13.17770.0_R1.MANIFEST +Writing TPM20_26.13.17770.0_R1.DATA +``` + +### Updating the firmware + +The `ifx_fw_update` tool uses the manifest (header) and the firmware data file. + +The TPM has a vendor capability for getting the key group id. It is populated in `WOLFTPM2_CAPS.keyGroupId` when `wolfTPM2_GetCapabilities` is called. This value should match the `keygroup_id` given to the extract tool. + +```sh +# Help +./ifx_fw_update --help +Infineon Firmware Update Usage: + ./ifx_fw_update (get info) + ./ifx_fw_update --abandon (cancel) + ./ifx_fw_update --policytest (safe policy auth self-test) + ./ifx_fw_update [policy opts] + ./ifx_fw_update (default auth) +Policy options (caller-supplied authorization): + --policy provision+satisfy a PolicyCommandCode + --policyor provision+satisfy a PolicyOR (multi-branch) + --sha256|--sha384|--sha512 policy hash (default SHA-256) + +# Run without arguments to display the current firmware information, +# including key group id and operational mode +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) + +# Run with manifest and firmware files +./ifx_fw_update TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Infineon Firmware Update Tool + Manifest File: TPM20_26.13.17770.0_R1.MANIFEST + Firmware File: TPM20_26.13.17770.0_R1.DATA +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +TPM2_FlushContext: Closed handle 0x3000000 +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +Firmware manifest chunk 1024 offset (0 / 3224), state 1 +Firmware manifest chunk 1024 offset (1024 / 3224), state 2 +Firmware manifest chunk 1024 offset (2048 / 3224), state 2 +Firmware manifest chunk 152 offset (3072 / 3224), state 0 +Firmware data chunk offset 0 +Firmware data chunk offset 1024 +Firmware data chunk offset 2048 +Firmware data chunk offset 3072 +... +Firmware data chunk offset 932864 +Firmware data chunk offset 933888 +Firmware data done +Mfg IFX (1), Vendor , Fw 0.0 (0x0) +Operational mode: After finalize or abandon, reboot required (0x4) +KeyGroupId 0x7, FwCounter 1253 (254 same) +TPM2_Shutdown failed 304: Unknown + +# Reset or power cycle TPM +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1253 (254 same) +``` + +## ST33 firmware update + +Build with `--enable-st33 --enable-firmware` to enable this example. + +### Firmware format auto-detection + +ST33KTPM firmware update detects the required format from the TPM firmware version. The manifest (blob0) is a 33 byte fixed header followed by the firmware digest and the signature over it, so its size follows the algorithms that generation signs with: + +- Generation 1 (major version 1, for example 1.257 or 1.771): non-LMS format. + - Manifest size: 321 bytes (SHA-256 digest, RSAPSS-2048 signature). + - Always non-LMS, no matter how high the minor version goes. +- Generation 9 below 512 (for example 9.257): non-LMS format. + - Manifest size: 177 bytes (SHA-384 digest, ECDSA P-384 signature). +- Generation 9 at 512 and above (for example 9.512): LMS (Leighton-Micali Signature) format. + - Manifest size: 2697 bytes (includes the embedded LMS signature). + +The LMS requirement is a generation 9 rule, so both `fwVerMajor` and `fwVerMinor` from the TPM capabilities are consulted. The example also confirms its choice against the file itself: everything after blob0 is a chain of `[type][length]` records that ends exactly at the end of the file, and only the correct manifest size lands on the final byte. No manual format selection is needed. + +### Identifying the part + +What `TPM_PT_VENDOR_STRING_1..4` reports on an ST33TPHF2X depends on the firmware. Early 1.x firmware reports binary rather than text, so the `Vendor` field prints empty. Later 1.x firmware reports ASCII, for example `ST33TPHF2XSPI`. The change is present by firmware 1.771 and absent at 1.258. Which firmware introduced it is not known. The firmware major version is the reliable identifier either way, and it tracks the part and interface line: + +| `fwVerMajor` | Part line | Example firmware image | +| --- | --- | --- | +| 1 | ST33TPHF2X, SPI firmware line | `TPM_ST33TPHF2XSPI_00010301.fi` | +| 2 | ST33TPHF2X, I2C firmware line | `TPM_ST33TPHF2XI2C_00020200.fi` | +| 9 | ST33KTPM2X | `TPM_ST33KTPM2X_00090200_V1.fi` | +| 10 (`0x000a`) | ST33KTPM2A | `TPM_ST33KTPM2A_000a0200.fi` | +| 11 (`0x000b`) | ST33KTPMQ | (none on hand) | + +The manifest header carries the same version: a zero byte followed by the firmware version the image upgrades to, in the `TPM_PT_FIRMWARE_VERSION_1` layout (`00 | 00 02 02 00` is 2.512). `st33_fw_update` prints both and refuses an image whose major version does not match the running part. + +See [Supported hardware](supported-hardware.md) for how the ST33 firmware line relates to the firmware version. + +### Field upgrade command codes + +ST33 implements the field upgrade with one of two command code pairs. The wrong one is answered with `TPM_RC_COMMAND_CODE` (`0x143`) before the manifest is even parsed: + +| Pair | Start | Data | +| --- | --- | --- | +| Standard TCG | `TPM_CC_FieldUpgradeStart` (`0x0000012F`) | `TPM_CC_FieldUpgradeData` (`0x00000141`) | +| ST33KTPM vendor | `0x2000030C` | `0x2000030D` | + +wolfTPM asks the TPM which pair it implements by querying `TPM_CAP_COMMANDS` for the two start codes. That is authoritative and needs no table of parts. ST's own reference tool instead infers the pair from version numbers (standard codes when the running firmware minor version is below 256, or when the image targets firmware generation 2). wolfTPM falls back to that same rule, `wolfTPM2_ST33_FwUpgradeCommands()`, only when the TPM will not answer (which is the case once it has entered firmware upgrade mode) or when it lists both pairs. + +The probe matters: an ST33KTPMQ at firmware 11.1 implements only the vendor pair even though its minor version is below 256, so the version rule alone would pick the wrong codes for it. + +Nothing needs to be selected by hand. When a caller-supplied policy is used, the `PolicyCommandCode` is bound to whichever start code will actually be sent, and `st33_fw_update` reports whether the codes came from the TPM or were inferred. + +Running `st33_fw_update` with no firmware file also reports which of the four codes the attached part implements, read from `TPM_CAP_COMMANDS`. This is read-only and is the quickest way to diagnose a `TPM_RC_COMMAND_CODE` on a new part: + +```sh +./st33_fw_update +... +Field upgrade command set: + 0x0000012f FieldUpgradeStart (standard): implemented + 0x00000141 FieldUpgradeData (standard): implemented + 0x2000030c FieldUpgradeStartVendor (ST33KTPM): not implemented + 0x2000030d FieldUpgradeDataVendor (ST33KTPM): not implemented +``` + +A firmware major version outside the known families is treated as unknown rather than guessed at. No manifest size is asserted for it, the tool reports that the size is taken from the image, and the block-chain check in `st33_detect_blob0` establishes the real size from the file itself. That way a part from a newer line, such as an ST33KTPMQ, is not refused an image on the strength of a rule that does not apply to it. + +### Updating the firmware + +The `st33_fw_update` tool detects the firmware format automatically. + +```sh +# Help +./st33_fw_update --help +ST33 Firmware Update Usage: + ./st33_fw_update (get info) + ./st33_fw_update --abandon (cancel) + ./st33_fw_update --policytest (safe policy auth self-test) + ./st33_fw_update [policy opts] + ./st33_fw_update (default password auth) +Policy options (caller-supplied authorization): + --policy provision+satisfy a PolicyCommandCode + --policyor provision+satisfy a PolicyOR (multi-branch) + --sha256|--sha384|--sha512 policy hash (default SHA-256) + +Firmware format is auto-detected from TPM firmware version and the file: + - Generation 1 (e.g. 1.771): Non-LMS format (321 byte manifest) + - Generation 9 below 512: Non-LMS format (177 byte manifest) + - Generation 9 at 512 and above: LMS format (2697 byte manifest) + +# Run without arguments to display the current firmware information. +# This capture is an ST33TPHF2XSPI, which implements only the vendor codes. +./st33_fw_update +ST33 Firmware Update Tool +TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e +TPM2_Startup pass +Mfg STM (2), Vendor , Fw 1.258 (0x0) +Firmware version details: Major=1, Minor=258, Vendor=0x0 +Part line: ST33TPHF2X (SPI firmware line) +Firmware generation: 1 +Firmware update: Non-LMS format required (321 byte manifest) +Field upgrade command set: + 0x0000012f FieldUpgradeStart (standard): not implemented + 0x00000141 FieldUpgradeData (standard): not implemented + 0x2000030c FieldUpgradeStartVendor (ST33KTPM): implemented + 0x2000030d FieldUpgradeDataVendor (ST33KTPM): implemented + +# Run with firmware file (format auto-detected from TPM version) +./st33_fw_update TPM_ST33KTPM2X_00090200_V1.fi +ST33 Firmware Update Tool + Firmware File: TPM_ST33KTPM2X_00090200_V1.fi +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0) +Firmware version details: Major=9, Minor=257, Vendor=0x0 +Part line: ST33KTPM2X +Firmware generation: 9 below 512 +Firmware update: Non-LMS format required (177 byte manifest) + Format: Non-LMS (blob0 177 bytes, verified against the block chain) +Firmware Update: + Total file size: 364290 bytes + Manifest (blob0): 177 bytes + Firmware data: 364113 bytes + Image targets firmware: 9.512 (ST33KTPM2X) + Command codes: start 0x2000030c, data 0x2000030d +... +Firmware update completed successfully. +Please reset or power cycle the TPM. +``` + +!!! note + Firmware files cannot be made public and must be obtained separately from STMicroelectronics. + +### LMS firmware + +For a generation 9 TPM with firmware at 512 and above, the LMS format is required: + +```sh +./st33_fw_update ST33KTPM2X_FAC_00090200_V2.fi +ST33 Firmware Update Tool + Firmware File: ST33KTPM2X_FAC_00090200_V2.fi +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 3 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.512 (0x0) +Firmware version details: Major=9, Minor=512, Vendor=0x0 +Firmware generation: 9 at 512 and above +Firmware update: LMS format required (2697 byte manifest) + Format: LMS (blob0 2697 bytes, verified against the block chain) +Firmware Update: + Total file size: 360092 bytes + Manifest (blob0): 2697 bytes + Firmware data: 357395 bytes +... +Firmware update completed successfully. +Please reset or power cycle the TPM. +``` + +### Cancel an update + +```sh +./st33_fw_update --abandon +ST33 Firmware Update Tool +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0) +Firmware version details: Major=9, Minor=257, Vendor=0x0 +Firmware generation: 9 below 512 +Firmware update: Non-LMS format required (177 byte manifest) +Firmware Update Abandon: +Success: Please reset or power cycle TPM +``` + +The same tool is also described in the main README as a short block: `./examples/firmware/st33_fw_update` displays firmware information, `--abandon` cancels any in-progress update, and passing a `` file performs the update with the format auto-detected from the TPM firmware version. + +## Policy-based authorization (advanced) + +By default wolfTPM manages the platform hierarchy authorization for the firmware update start command internally. On Infineon it installs and satisfies a `PolicyCommandCode(TPM_CC_FieldUpgradeStartVendor)` policy on the platform primary policy. On ST33 it uses password authorization (`TPM_RS_PW`) with an empty platform password. This assumes the platform hierarchy has default (empty) authorization. + +Deployments that gate firmware upgrade behind their own platform policy (for example a signed-policy check, a PCR state, or a multi-branch `PolicyOR`) can supply an already-satisfied authorization session using `wolfTPM2_FirmwareUpgradeHash_ex()`. When a session is supplied: + +- **Infineon**: the library does not overwrite your platform primary policy. You provision the platform `authPolicy` yourself (through `TPM2_SetPrimaryPolicy` with `authHandle = TPM_RH_PLATFORM`, using SHA2-256 or SHA2-512) and pass a session that satisfies it. This applies to the library. The `--policy` and `--policyor` example modes are themselves such a caller, and their helper (`examples/firmware/firmware_policy.c`) does overwrite the platform `authPolicy` with a digest it generates. Do not run those modes on a system whose platform hierarchy already carries a policy you need. +- **ST33**: the supplied session replaces the default `TPM_RS_PW` password authorization. + +Supported session contract: the vendor `FieldUpgradeStart` command is sent with an authorization area carrying only the session handle, with an empty `nonceCaller`, zero session attributes and an empty HMAC. The supplied session must therefore be an unsalted, unbound `TPM_SE_POLICY` session with no auth value and no parameter encryption. Policies satisfied with `wolfTPM2_PolicyAuthValue()` or `wolfTPM2_PolicyPassword()` are not supported, because the session HMAC they require is not serialized on this path. Such a session is rejected with `BAD_FUNC_ARG` before anything is sent to the TPM. `PolicyPCR`, `PolicySigned`, `PolicySecret`, `PolicyAuthorize`, `PolicyCommandCode` and `PolicyOR` branches are all fine. + +Both SHA2-256 (non-PQC) and SHA2-512 (PQC) policy digests are supported, because the session hash is chosen with `wolfTPM2_StartSession_ex(..., authHash)` and `wolfTPM2_PolicyOR()` carries per-branch digest sizes. + +Example: satisfy a multi-branch `PolicyOR` (up to 8 branches, SHA2-512 shown) and start the upgrade under it: + +```c +WOLFTPM2_SESSION session; +TPML_DIGEST orList; +uint8_t manifest_hash[TPM_SHA512_DIGEST_SIZE]; +int rc; + +/* zero both structs: orList must not carry uninitialized branch sizes */ +XMEMSET(&session, 0, sizeof(session)); +XMEMSET(&orList, 0, sizeof(orList)); + +/* start a policy session using the desired policy hash (SHA2-512 for PQC) */ +rc = wolfTPM2_StartSession_ex(&dev, &session, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL, TPM_ALG_SHA512); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* Satisfy one branch (PCR, PolicySigned, PolicyAuthorize, PolicyCommandCode, + * ...), then OR against the full branch list the platform authPolicy encodes. + * Set count and each digests[i].size/buffer for every branch you populate. + * PolicyOR requires at least 2 branches. */ +orList.count = 2; +/* orList.digests[0].size = ...; XMEMCPY(orList.digests[0].buffer, ...); */ +/* orList.digests[1].size = ...; XMEMCPY(orList.digests[1].buffer, ...); */ +rc = wolfTPM2_PolicyOR(&dev, &session, &orList); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* hash the manifest with the matching algorithm, then start the upgrade under + * the caller-satisfied session (NULL would use the library-default auth) */ +rc = wc_Sha512Hash(manifest, manifest_sz, manifest_hash); +if (rc != 0) goto cleanup; +rc = wolfTPM2_FirmwareUpgradeHash_ex(&dev, TPM_ALG_SHA512, + manifest_hash, (uint32_t)sizeof(manifest_hash), + manifest, manifest_sz, fwDataCb, fwCbCtx, &session); + +cleanup: +/* On a successful FieldUpgradeStart the TPM consumes the session and the + * library sets session.handle.hndl to TPM_RH_NULL (0x40000007). It is NOT + * zeroed, so do not test for == 0 to detect consumption. Calling + * wolfTPM2_UnloadHandle is always safe: it is a no-op on TPM_RH_NULL, so this + * only releases a session that is still loaded. */ +if (session.handle.hndl != 0) + wolfTPM2_UnloadHandle(&dev, &session.handle); +``` + +Passing `NULL` for the final `startSession` argument makes `wolfTPM2_FirmwareUpgradeHash_ex()` behave exactly like `wolfTPM2_FirmwareUpgradeHash()` (library-managed authorization), so existing code is unaffected. + +### Destructive: provisioning replaces any existing platform policy + +!!! warning + `--policy` and `--policyor` call `TPM2_SetPrimaryPolicy` on the platform hierarchy with a digest the example generates. TPM 2.0 provides no way to read a hierarchy's `authPolicy` back: there is no read command, and `TPMA_PERMANENT` reports only `authValue` state. The example therefore cannot detect an existing policy, cannot preserve it, and cannot restore it. Cleanup removes the policy rather than restoring whatever was there before. + +If your platform hierarchy is gated by a policy you need to keep, do not run these modes. The example prints this warning at provisioning time. `--policytest` is unaffected: it is non-destructive and never calls `TPM2_SetPrimaryPolicy`. + +The modes also require the normal operational mode. In recovery and finalize modes the library skips `FieldUpgradeStart` entirely, so a caller-supplied session would never be used, and the example refuses rather than installing a policy nothing will exercise. On ST33, if the TPM is already in firmware-upgrade mode the policy flags are likewise rejected, since the start command has already run. + +### Rollback of the example-provisioned policy + +The example `--policy` and `--policyor` modes provision the platform hierarchy `authPolicy` with `TPM2_SetPrimaryPolicy` before the upgrade. On failure the example clears it again so a later default-auth run is not locked out. On success the required TPM reset clears it. + +- Rollback normally uses platform password authorization. Per TPM 2.0 Part 1 Sec. 19.7 a hierarchy is authorized by either its `authValue` or its `authPolicy`, so installing an `authPolicy` does not disable the password path. With the default empty `platformAuth` the clear always succeeds. +- `--policyor` also provisions a `PolicyCommandCode(TPM_CC_SetPrimaryPolicy)` branch alongside the firmware-start branch, so the policy can authorize its own removal. If the password path fails (a deployment that set a non-default `platformAuth`), the example retries the clear under that branch. +- `--policy` provisions a single `PolicyCommandCode(FieldUpgradeStart)` branch and therefore has no policy-based rollback path. It relies entirely on `platformAuth` still being usable. +- Rollback is attempted only when the example actually installed the policy, so an early failure (a missing firmware file, for example) never clears a policy the deployment provisioned itself. +- A failed rollback is reported explicitly and becomes the exit status. If a run is interrupted before cleanup, or the clear fails, the platform hierarchy still requires the policy until the TPM is reset or power cycled. + +## See Also + +- [Supported hardware](supported-hardware.md) +- [Sealing and NVRAM](sealing-and-nvram.md) +- [TLS and certificates](tls-and-certificates.md) +- [Management and GPIO](management-and-gpio.md) diff --git a/docs/fwtpm/building.md b/docs/fwtpm/building.md new file mode 100644 index 00000000..1591b59d --- /dev/null +++ b/docs/fwtpm/building.md @@ -0,0 +1,222 @@ +# Building the fwTPM + +This page covers how to build the fwTPM server, the configure options and compile defines that control it, and the compile-time macros that tune size and features. For what the fwTPM is, see the [Overview](overview.md). + +## Prerequisites + +wolfSSL must be built with TPM support, keygen, and `WC_RSA_NO_PADDING`: + +```sh +cd wolfssl +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +``` + +## Build the fwTPM Server + +**Socket transport (SWTPM protocol, default for development):** + +```sh +cd wolftpm +./configure --enable-fwtpm --enable-swtpm +make +``` + +This produces `src/fwtpm/fwtpm_server` and builds the wolfTPM client library with `WOLFTPM_SWTPM` for socket-based communication. + +**TIS and shared-memory transport (for fwTPM HAL integration):** + +```sh +./configure --enable-fwtpm --disable-swtpm +make +``` + +When `--enable-swtpm` is omitted, the build uses TIS shared-memory transport (`WOLFTPM_FWTPM_HAL`, `WOLFTPM_ADV_IO`) and compiles `fwtpm_tis.c` into the server. + +**fwTPM server only (no client library or examples):** + +```sh +./configure --enable-fwtpm-only --enable-swtpm +make +``` + +This builds only the `fwtpm_server` binary and skips `libwolftpm`, examples, and tests. It is useful for embedded targets that only need the TPM server. + +**Debug build:** + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-debug +make +``` + +## Build Output + +| Artifact | Description | +|----------|-------------| +| `src/fwtpm/fwtpm_server` | Standalone fwTPM server binary | +| `src/.libs/libwolftpm.*` | wolfTPM client library | + +## Key Build Flags + +| Configure Option | Effect | +|-----------------|--------| +| `--enable-fwtpm` | Build `fwtpm_server` binary (alongside client library) | +| `--enable-fwtpm-only` | Build only `fwtpm_server` (no client library, examples, or tests) | +| `--enable-swtpm` | Use SWTPM TCP socket transport (ports 2321 and 2322) | +| `--enable-fwtpm-nv-appendonly` | Append-only NV journal for write-once flash ports (off by default) | +| `--enable-pqc` (the fwTPM build promotes it to `--enable-v185`) | TPM 2.0 v1.85 post-quantum support (see [Post-Quantum Support](post-quantum.md)) | +| `--enable-spdm` | SPDM responder (with `--enable-tcg` or `--enable-psk`; see [SPDM Responder](spdm.md)) | +| `--enable-fuzz` | Fuzzing build | +| `--enable-debug` | Enable debug logging | + +| Compile Define | Set By | +|---------------|--------| +| `WOLFTPM_FWTPM` | Automatically set for the `fwtpm_server` target only | +| `WOLFTPM_SWTPM` | `--enable-swtpm` | +| `WOLFTPM_FWTPM_HAL` | `--enable-fwtpm --disable-swtpm` | +| `WOLFTPM_FWTPM_TIS` | `--enable-fwtpm --disable-swtpm` | +| `WOLFTPM_ADV_IO` | Set with `WOLFTPM_FWTPM_HAL` | +| `WOLFTPM_FWTPM_NV_APPEND_ONLY` | `--enable-fwtpm-nv-appendonly` (CMake `WOLFTPM_FWTPM_NV_APPEND_ONLY=yes`) | +| `WOLFTPM_FWTPM_TCG_TEST` | Manually (`CFLAGS=-DWOLFTPM_FWTPM_TCG_TEST`); off by default | + +No vendor commands are registered by default. Define `WOLFTPM_FWTPM_TCG_TEST` to compile in the optional `TPM2_Vendor_TCG_Test` (`0x20000000`) echo command. + +## Command-Code Enforcement + +A valid command code carries only the 16-bit index plus, for vendor commands, the V bit (`CC_VEND`, bit 29). Codes with any other reserved bit set, or codes not in the dispatch table, are rejected with `TPM_RC_COMMAND_CODE`. `TPM2_GetCapability(TPM_CAP_COMMANDS)` returns proper `TPMA_CC` values (index, handle attributes, and V bit, ordered by command code). + +## Configuration Macros + +All macros are compile-time overridable (for example `-DFWTPM_MAX_OBJECTS=8`). + +| Macro | Default | Description | +|-------|---------|-------------| +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | Maximum command and response buffer size (bytes) | +| `FWTPM_MAX_RANDOM_BYTES` | 48 | Maximum bytes per `GetRandom` call | +| `FWTPM_MAX_OBJECTS` | 3 | Maximum concurrently loaded transient objects | +| `FWTPM_MAX_PERSISTENT` | 8 | Maximum persistent objects (via `EvictControl`) | +| `FWTPM_MAX_PRIVKEY_DER` | 1280 (256 with `NO_RSA`) | Maximum DER-encoded private key size (bytes) | +| `FWTPM_MAX_HASH_SEQ` | 4 | Maximum concurrent hash and HMAC sequences | +| `FWTPM_MAX_PRIMARY_CACHE` | 4 | Cached primary keys per hierarchy and template | +| `FWTPM_MAX_SESSIONS` | 4 | Maximum concurrent auth sessions | +| `FWTPM_MAX_NV_INDICES` | 16 | Maximum NV RAM index slots; omitted from `FWTPM_CTX` with `FWTPM_NO_NV` | +| `FWTPM_MAX_NV_DATA` | 2048 | Maximum data per NV index (bytes) | +| `FWTPM_DA_DEFAULT_MAX_TRIES` | 32 | DA failed-auth count before lockout | +| `FWTPM_DA_DEFAULT_RECOVERY` | 600 | DA self-heal interval (seconds per try) | +| `FWTPM_DA_DEFAULT_LOCKOUT_RECOVERY` | 86400 | lockoutAuth recovery time (seconds) | +| `FWTPM_DA_MAX_TRIES_LIMIT` | 0xFFFF | Upper clamp for a replayed `maxTries` or `failedTries` | +| `FWTPM_MAX_DATA_BUF` | 1024 | Internal buffer for HMAC, hash, general data | +| `FWTPM_MAX_PUB_BUF` | 512 | Internal buffer for public area, signatures | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | Internal buffer for DER signatures, ECC points | +| `FWTPM_MAX_ATTEST_BUF` | 1024 | Internal buffer for attestation marshaling | +| `FWTPM_MAX_CMD_AUTHS` | 3 | Maximum authorization sessions per command (TPM spec hard cap) | +| `FWTPM_MAX_SENSITIVE_SIZE` | `FWTPM_MAX_PRIVKEY_DER + 128` | Maximum marshaled sensitive area (private key, auth, and nonce headroom) | +| `FWTPM_MAX_SIGN_SEQ` | 4 | Maximum concurrent v1.85 PQC sign and verify sequences | +| `FWTPM_MAX_SYM_KEY_SIZE` | 32 | Symmetric key buffer (sized for AES-256) | +| `FWTPM_MAX_HMAC_KEY_SIZE` | 64 | HMAC key buffer (sized for SHA-512 block) | +| `FWTPM_MAX_HMAC_DIGEST_SIZE` | 64 | HMAC output buffer (sized for SHA-512) | +| `FWTPM_CMD_PORT` | 2321 | Default TCP command port | +| `FWTPM_PLAT_PORT` | 2322 | Default TCP platform port | +| `FWTPM_NV_FILE` | `"fwtpm_nv.bin"` | Default NV storage file path | +| `FWTPM_NV_MAX_WRITE_ALIGN` | 64 | Max append-only program granule in bytes (upper bound on a HAL's `writeAlign`); sizes the pending-granule buffer when `WOLFTPM_FWTPM_NV_APPEND_ONLY` is set | +| `FWTPM_PCR_BANKS` | 2 | Number of PCR banks (SHA-256 and SHA-384) | +| `FWTPM_TIS_BURST_COUNT` | 64 | TIS FIFO burst count (bytes per transfer) | +| `FWTPM_TIS_FIFO_SIZE` | 4096 | TIS command and response FIFO size | + +### Stack and Heap Control + +| Macro | Effect | +|-------|--------| +| `WOLFTPM_SMALL_STACK` | Use heap allocation for large stack objects | +| `WOLFTPM2_NO_HEAP` | Forbid heap allocation (all stack) | + +!!! note + `WOLFTPM_SMALL_STACK` and `WOLFTPM2_NO_HEAP` are mutually exclusive. Defining both is a compile error. + +### v1.85 Embedded RAM Impact + +Enabling `--enable-pqc` (or `--enable-v185`) lifts several internal buffers to accommodate PQC key and signature sizes. The defaults shrink automatically at compile time based on which ML-DSA and ML-KEM parameter sets wolfCrypt was built with (`WOLFSSL_NO_ML_DSA_44/65/87`, `WOLFSSL_NO_KYBER512/768/1024`). Boards that only enable the smaller parameter sets get smaller buffers with no per-board override. + +**Buffer sizes by enabled parameter set:** + +| Macro | Classical | MLDSA-44 + MLKEM-512 | MLDSA-65 + MLKEM-768 | MLDSA-87 + MLKEM-1024 | +|----------------------------|------------|--------------------|--------------------|--------------------| +| `FWTPM_TIS_FIFO_SIZE` | 4096 | 4096 | 8192 | 8192 | +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 4096 | 8192 | 8192 | +| `FWTPM_MAX_PUB_BUF` | 512 | 1440 | 2080 | 2720 | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | 2548 | 3437 | 4755 | +| `FWTPM_MAX_KEM_CT_BUF` | n/a | 832 | 1152 | 1632 | + +Sizing logic lives in `wolftpm/fwtpm/fwtpm.h` (constants `FWTPM_MAX_MLDSA_SIG_SIZE`, `FWTPM_MAX_MLDSA_PUB_SIZE`, `FWTPM_MAX_MLKEM_CT_SIZE`, `FWTPM_MAX_MLKEM_PUB_SIZE`) and `wolftpm/fwtpm/fwtpm_tis.h` (FIFO size). The ML-DSA constants come from wolfCrypt's `WC_MLDSA_{44,65,87}_*_SIZE` macros. The ML-KEM constants are FIPS 203 spec values, because wolfCrypt's `WC_ML_KEM_*_SIZE` macros cannot be evaluated by the preprocessor. + +The 8192 lifts on the FIFO and command buffers only apply when MLDSA-65 or MLDSA-87 is enabled, because their signatures do not fit a 4096-byte response with TPM headers. MLDSA-44-only and MLKEM-only v1.85 builds stay at 4096. + +**Per-deployment override:** every macro above is still `#ifndef`-guarded, so a board can override individually on the compile line if the automatic default is wrong for its workload (for example `-DFWTPM_TIS_FIFO_SIZE=2048`). + +**Heap versus stack:** building with `WOLFTPM_SMALL_STACK` moves the large per-call buffers off the stack into `XMALLOC` and `XFREE` regions. The PQC paths already use `FWTPM_DECLARE_BUF` and `FWTPM_ALLOC_BUF`, which respect this flag, so no source changes are required. `WOLFTPM2_NO_HEAP` is supported but pays the full stack cost, so pair it with the smallest PQC parameter set you can. + +### Algorithm Feature Macros + +These macros use wolfCrypt's existing compile-time options to control which cryptographic algorithms are available in `fwtpm_server`. If an algorithm is disabled, the corresponding TPM commands are excluded from the build. + +| Macro | Default | Effect | +|-------|---------|--------| +| `NO_RSA` | not defined | Excludes RSA keygen, sign, verify, `RSA_Encrypt`, `RSA_Decrypt` | +| `HAVE_ECC` | defined | Enables ECC keygen, sign, verify, `ECDH_KeyGen`, `ECDH_ZGen`, `ECC_Parameters` | +| `HAVE_ECC384` | defined | Enables P-384 curve support | +| `HAVE_ECC521` or `HAVE_ALL_CURVES` | build-dependent | Enables P-521 when `MAX_ECC_KEY_BITS >= 521` provides 66-byte TPM ECC fields | +| `ECC_MIN_KEY_SZ` | wolfCrypt-defined | Excludes smaller curves from `ECC_Parameters` and `TPM_CAP_ECC_CURVES` | +| `NO_AES` | not defined | Excludes `EncryptDecrypt`, `EncryptDecrypt2`, AES parameter encryption | +| `WOLFSSL_SHA384` | defined | Enables SHA-384 PCR bank | + +When an algorithm is disabled, commands that exclusively use that algorithm are removed from the dispatch table at compile time. Commands that support multiple algorithms (for example `CreatePrimary` and `Sign`) remain available but return `TPM_RC_ASYMMETRIC` for the disabled algorithm type. + +### TPM Feature Group Macros + +These fwTPM-specific macros disable entire groups of TPM 2.0 functionality to reduce code size on constrained targets. + +| Macro | Default | Commands Excluded | +|-------|---------|-------------------| +| `FWTPM_NO_ATTESTATION` | not defined | `Quote`, `Certify`, `CertifyCreation`, `GetTime`, `NV_Certify` | +| `FWTPM_NO_NV` | not defined | `NV_DefineSpace`, `NV_UndefineSpace`, `NV_ReadPublic`, `NV_Write`, `NV_Read`, `NV_Extend`, `NV_Increment`, `NV_WriteLock`, `NV_ReadLock`, `NV_Certify`; also removes the in-memory NV index slots from `FWTPM_CTX` | +| `FWTPM_NO_POLICY` | not defined | `PolicyGetDigest`, `PolicyRestart`, `PolicyPCR`, `PolicyPassword`, `PolicyAuthValue`, `PolicyCommandCode`, `PolicyOR`, `PolicySecret`, `PolicyAuthorize`, `PolicyNV` | +| `FWTPM_NO_CREDENTIAL` | not defined | `MakeCredential`, `ActivateCredential` | +| `FWTPM_NO_DA` | not defined | `DictionaryAttackParameters`, `DictionaryAttackLockReset`, and all lockout accounting | +| `FWTPM_NO_PARAM_ENC` | not defined | Command and response parameter (XOR and AES-CFB) encryption support in sessions | +| `FWTPM_NO_KEY_MIGRATION` | not defined | `Import`, `Duplicate`, `Rewrap` | +| `FWTPM_NO_ECDH` | not defined | `ECDH_KeyGen`, `ECDH_ZGen`, `EC_Ephemeral`, `ZGen_2Phase`, `ECC_Parameters` (ECDSA sign and verify retained), plus the `ecEphemeral*` commit state in `FWTPM_CTX` | +| `FWTPM_NO_HASH_CMDS` | not defined | `Hash`, `HMAC`, `HMAC_Start`, `HashSequenceStart`, `SequenceUpdate`, `SequenceComplete`, `EventSequenceComplete`, and the `FWTPM_CTX` hash-sequence slots | +| `FWTPM_NO_CONTEXT` | not defined | `ContextSave`, `ContextLoad` (`FlushContext` retained), plus the per-boot context protection key and saved-context replay list in `FWTPM_CTX` | +| `FWTPM_NO_SYM_ENCRYPT` | not defined | `EncryptDecrypt`, `EncryptDecrypt2` | +| `FWTPM_NO_CLOCK` | not defined | `ReadClock`, `ClockSet`, `ClockRateAdjust` | + +Removing a command group also removes it from the `TPM2_GetCapability(TPM_CAP_COMMANDS)` advertisement and the `TPM_PT_TOTAL_COMMANDS` count, since both are derived from the dispatch table. When `WOLFTPM_MLDSA` is built, `SequenceUpdate` alone is retained under `FWTPM_NO_HASH_CMDS`, because ML-DSA verify sequences stream their message through it. `SequenceComplete` is not shared (ML-DSA sequences finalize through `TPM2_SignSequenceComplete` and `TPM2_VerifySequenceComplete`), so it is gated out with the rest of the hash commands rather than advertised as a command that can never succeed. + +The `FWTPM_DA_USED_RETRY` macro (off by default) does not remove commands. It makes the server return `TPM_RC_RETRY` on the first DA-protected auth use after startup, emulating a real TPM persisting `daUsed`. See Dictionary Attack Protection in the [Overview](overview.md). + +**Minimal build example.** There is no umbrella macro. Select the command groups to drop explicitly, so each is a deliberate choice. For example, to build a small ECC-only signing and NV fTPM (this set drops attestation and keeps `Sign`, `VerifySignature`, PCR, and NV): + +```sh +./configure --enable-fwtpm --enable-swtpm \ + CFLAGS="-DNO_RSA \ + -DFWTPM_NO_POLICY -DFWTPM_NO_ATTESTATION -DFWTPM_NO_CREDENTIAL \ + -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC -DFWTPM_NO_KEY_MIGRATION \ + -DFWTPM_NO_ECDH -DFWTPM_NO_HASH_CMDS -DFWTPM_NO_CONTEXT \ + -DFWTPM_NO_SYM_ENCRYPT -DFWTPM_NO_CLOCK" +``` + +That set retains a core fTPM: `Startup`, `Shutdown`, `SelfTest`, `GetRandom`, `GetCapability`, the `PCR_*` commands, `Create`, `CreatePrimary`, `Load`, `ReadPublic`, `FlushContext`, `Sign`, `VerifySignature`, the `NV_*` commands, and session support (`StartAuthSession` and `Unseal`). Add `-DFWTPM_NO_NV` to also drop NV, or drop any `-DFWTPM_NO_*` above to keep that group. This ECC-only build is small enough to run as a soft-core fTPM on a constrained FPGA (see the MicroBlaze V example in the `wolftpm-examples` repository, which fits an ECC-only fTPM into about 192 KB of on-chip memory). + +**Dependencies:** + +- `FWTPM_NO_NV` also removes `NV_Certify`, even if `FWTPM_NO_ATTESTATION` is not set. +- `NO_RSA` implies no RSA attestation signatures. ECC-only attestation still works with `HAVE_ECC`. + +## See Also + +- [Overview](overview.md) +- [Usage](usage.md) +- [HAL and Porting](hal-and-porting.md) +- [Post-Quantum Support](post-quantum.md) +- [SPDM Responder](spdm.md) diff --git a/docs/fwtpm/hal-and-porting.md b/docs/fwtpm/hal-and-porting.md new file mode 100644 index 00000000..b16b75c0 --- /dev/null +++ b/docs/fwtpm/hal-and-porting.md @@ -0,0 +1,169 @@ +# HAL and Porting + +The fwTPM provides hardware abstraction layers (HALs) so it can be ported to embedded targets without modifying the core logic. There is an IO HAL for the transport, an NV HAL for persistent storage, and an optional clock HAL. Full reference ports for several boards live in the [wolftpm-examples](https://github.com/wolfSSL/wolftpm-examples) repository. + +## IO HAL (Transport) + +The IO HAL abstracts the transport between the fwTPM server and its clients. The default implementation uses TCP sockets (SWTPM protocol). For embedded targets, replace it with SPI, I2C, UART, or shared memory callbacks. + +**Callback structure** (defined as `FWTPM_IO_HAL` in `fwtpm.h`): + +| Callback | Signature | Description | +|----------|-----------|-------------| +| `send` | `int (*)(void* ctx, const void* buf, int sz)` | Send data to client | +| `recv` | `int (*)(void* ctx, void* buf, int sz)` | Receive data from client | +| `wait` | `int (*)(void* ctx)` | Wait for data or connections. Returns a bitmask: `0x01`=command data, `0x02`=platform data, `0x04`=new command connection, `0x08`=new platform connection | +| `accept` | `int (*)(void* ctx, int type)` | Accept new connection (type: 0=command, 1=platform) | +| `close_conn` | `void (*)(void* ctx, int type)` | Close connection (type: 0=command, 1=platform) | +| `ctx` | `void*` | User context pointer | + +**Registration:** + +```c +FWTPM_IO_HAL myHal; +myHal.send = my_send; +myHal.recv = my_recv; +myHal.wait = my_wait; +myHal.accept = my_accept; +myHal.close_conn = my_close; +myHal.ctx = &myTransportCtx; + +FWTPM_IO_SetHAL(&ctx, &myHal); +``` + +## NV HAL (Persistent Storage) + +The NV HAL abstracts persistent storage. The default implementation uses a local file (`fwtpm_nv.bin`). For embedded targets, replace it with flash, EEPROM, or other non-volatile storage callbacks. + +**Callback structure** (defined as `FWTPM_NV_HAL` in `fwtpm.h`): + +| Callback | Signature | Description | +|----------|-----------|-------------| +| `read` | `int (*)(void* ctx, word32 offset, byte* buf, word32 size)` | Read from NV at offset | +| `write` | `int (*)(void* ctx, word32 offset, const byte* buf, word32 size)` | Write to NV at offset | +| `erase` | see `fwtpm.h` | Erase the NV region (used by flash ports and by compaction) | +| `ctx` | `void*` | User context pointer | +| `maxSize` | `word32` | Size of the NV region in bytes | +| `appendOnly`, `writeAlign` | fields | Append-only mode and program granule size (see below) | +| `get_integrity_key` | callback | Supplies a device secret used to authenticate the journal | + +**Registration:** + +```c +FWTPM_NV_HAL myNvHal; +myNvHal.read = my_flash_read; +myNvHal.write = my_flash_write; +myNvHal.ctx = &myFlashCtx; + +FWTPM_NV_SetHAL(&ctx, &myNvHal); +``` + +Register the HAL before `FWTPM_Init()`. + +### NV Storage HAL for Embedded Ports + +NV access goes through `FWTPM_NV_HAL` (`read`, `write`, `erase`, `ctx`, `maxSize`, `get_integrity_key`). The default backend is a file. An embedded port supplies its own HAL and registers it before `FWTPM_Init()`. + +The journal is log-structured. On a byte-addressable backend (the file default) it writes TLV entries at byte-granular offsets, rewrites the header in place, and rewrites a trailing integrity MAC after every append. Internal flash and NOR are write-once and aligned to the program granularity, so they cannot service in-place rewrites. + +For those parts, build with `--enable-fwtpm-nv-appendonly` (`-DWOLFTPM_FWTPM_NV_APPEND_ONLY`, CMake `WOLFTPM_FWTPM_NV_APPEND_ONLY=yes`) and set `appendOnly` and `writeAlign` on the HAL. The journal then runs in append-only mode: + +- The header is written only at compaction. +- `writePos` is derived by scanning on load. +- Each commit is sealed with an appended MAC-checkpoint entry, padded up to `writeAlign`. + +The existing `read`, `write`, and `erase` HAL is the integration point. There is no separate adapter. + +```c +/* Native flash HAL. In append-only mode the journal only ever calls write() + * with writeAlign-aligned, forward, into-erased bytes, so write() is a simple + * flash program; erase() erases the region (sector loop); read() reads raw. */ +FWTPM_NV_HAL hal; +XMEMSET(&hal, 0, sizeof(hal)); +hal.read = myRead; hal.write = myProgram; hal.erase = myErase; +hal.ctx = myCtx; hal.maxSize = NV_SIZE; +hal.appendOnly = 1; +hal.writeAlign = PROG_SIZE; /* flash word size, e.g. 16 (STM32H5) */ +hal.get_integrity_key = myDeviceSecret;/* recommended on flash */ +FWTPM_NV_SetHAL(&ctx, &hal); /* before FWTPM_Init() */ +``` + +In append-only mode the journal buffers a pending program granule internally and flushes full, aligned granules through `write()`. A programmed cell is never rewritten, and a whole sector is erased only on compaction. The header sector is therefore not erased on every append, and a torn final commit (for example from power loss) is ignored on the next load while all previously committed state survives. + +A `get_integrity_key` callback is strongly recommended on flash, so the MAC checkpoints authenticate the journal and reject a torn or tampered tail. Setting `writeAlign <= 1` selects no buffering, so byte-writable NV (EEPROM or FRAM) works with a plain `write()`. + +!!! warning + Compaction still erases the whole region before rewriting, so a power loss during compaction itself remains a vulnerable window. A future two-region ping-pong layout would close it. + +## Clock HAL + +The clock HAL is optional. It supplies `get_ms()`, which returns milliseconds since boot. Register it with `FWTPM_Clock_SetHAL()` before `FWTPM_Init()`. With a clock HAL registered, dictionary attack protection self-heals over time (see [Overview](overview.md)). + +## Porting Example + +A bare-metal embedded target with SPI transport and SPI flash NV: + +```c +FWTPM_CTX ctx; +XMEMSET(&ctx, 0, sizeof(ctx)); + +/* Set custom NV storage before FWTPM_Init, which loads NV state through it */ +FWTPM_NV_HAL nvHal = { + .read = spi_flash_read, + .write = spi_flash_write, + .ctx = &flashHandle +}; +FWTPM_NV_SetHAL(&ctx, &nvHal); + +FWTPM_Init(&ctx); + +/* Set custom IO transport after FWTPM_Init, which does not preserve the IO HAL */ +FWTPM_IO_HAL ioHal = { + .send = spi_slave_send, + .recv = spi_slave_recv, + .wait = spi_slave_poll, + .accept = NULL, /* not connection-oriented */ + .close_conn = NULL, + .ctx = &spiHandle +}; +FWTPM_IO_SetHAL(&ctx, &ioHal); + +/* Initialize IO and run */ +FWTPM_IO_Init(&ctx); +FWTPM_IO_ServerLoop(&ctx); /* blocks */ + +FWTPM_IO_Cleanup(&ctx); +FWTPM_Cleanup(&ctx); +``` + +## Available Ports + +| Port | Repository | Description | +|------|-----------|-------------| +| STM32H5 | [STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) | STM32H5 Cortex-M33 with TrustZone (CMSE); internal-flash NV | +| PolarFire SoC | [Microchip/fwtpm-polarfire-miv](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/fwtpm-polarfire-miv) | MPFS250T; fwTPM bare-metal in M-mode on a U54 RISC-V hart (HSS AMP alongside Linux), TIS over shared L2-LIM memory | +| Zynq UltraScale+ ZCU102 | [Xilinx/fwtpm-zcu102-r5](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zcu102-r5) | ZynqMP MPSoC; fwTPM bare-metal on the Cortex-R5 RPU pair in lock-step, OpenAMP RPMsg client on the A53 (PetaLinux); volatile DDR NV or persistent QSPI | + +## Porting Guide + +To add a new platform, implement these HAL callbacks: + +1. **NV Storage HAL** (`FWTPM_NV_HAL`): `read()`, `write()`, and `erase()` for persistent flash storage. Register it with `FWTPM_NV_SetHAL()` before `FWTPM_Init()`. + + The NV journal is log-structured. On a byte-addressable backend it writes at byte-granular offsets and rewrites the header and a trailing integrity MAC in place after every append. Internal flash and NOR are write-once and aligned to the program granularity, so they cannot service in-place rewrites. For those, build with `--enable-fwtpm-nv-appendonly` and set `hal.appendOnly = 1` and `hal.writeAlign = ` (for example 16 on STM32H5) before `FWTPM_NV_SetHAL()`. + + The journal then writes the header only at compaction, derives `writePos` by scanning on load, seals each commit with an appended, program-granule-aligned MAC checkpoint, and buffers a pending program granule internally. It only ever calls `write()` with `writeAlign`-aligned, forward, into-erased bytes. Your `write()` is therefore a simple flash program with no buffering or read-modify-write in the port, `erase()` erases the region (sector loop), and `read()` reads raw bytes. A programmed cell is never rewritten and a whole sector is erased only on compaction, so the header sector is not worn on every append and a torn final commit is ignored on the next load. Provide a `get_integrity_key` on `FWTPM_NV_HAL` so the checkpoints authenticate the journal. Setting `writeAlign <= 1` disables buffering for byte-writable NV such as EEPROM or FRAM. + +2. **Clock HAL** (optional): `get_ms()` returning milliseconds since boot. Register it with `FWTPM_Clock_SetHAL()` before `FWTPM_Init()`. + +3. **Entry point**: zero `FWTPM_CTX`, register the HALs, call `FWTPM_Init()`, then process TPM commands with `FWTPM_ProcessCommand()`. + +See the STM32 port in wolftpm-examples for a complete reference implementation. + +## See Also + +- [Overview](overview.md) +- [Building](building.md) +- [Usage](usage.md) +- [Post-Quantum Support](post-quantum.md) +- [SPDM Responder](spdm.md) diff --git a/docs/fwtpm/overview.md b/docs/fwtpm/overview.md new file mode 100644 index 00000000..e9a63b31 --- /dev/null +++ b/docs/fwtpm/overview.md @@ -0,0 +1,379 @@ +# fwTPM Overview + +The wolfTPM fwTPM (also called fTPM) is a firmware TPM 2.0 built on wolfCrypt cryptographic primitives. It is not only an emulator for tests. It is a portable TPM 2.0 command processor that runs as a standalone server process (`fwtpm_server`) or is linked into an embedded firmware image. A default build with RSA, ECC, AES, and every feature group enabled has 103 of the 112 TPM 2.0 Revision 1.38 command codes in its dispatch table. The eight Version 185 post-quantum commands raise that to 111. See Command Coverage below for the counting convention and the documented limitations, such as the minimal self-test and the missing `SU_STATE` resume support. + +The fwTPM can be used for testing, and it can also be used in production, security-critical, and isolated deployments where a discrete TPM chip is not available or not wanted. In those deployments the security of the TPM depends on the platform that hosts it. A firmware TPM does not provide the physical isolation of a discrete TPM chip on its own, so the integrator must supply the isolation (a separate core, a TrustZone secure world, or similar) and must protect the NV storage. The default file-based NV store keeps hierarchy seeds, authorization values, and private keys in plaintext, and `fwtpm_server` itself is a development and test tool. The fwTPM also brings post-quantum cryptography and SPDM to platforms without TPM silicon. + +Example integration models: + +- **Embedded and IoT platforms** without a discrete TPM chip (bare-metal via an SPI or I2C TIS HAL) +- **Isolated deployments**, such as a TPM running on a separate core, a TrustZone secure world, or a lock-step real-time core next to a Linux application processor. The isolation comes from the platform, not from the fwTPM. +- **Development and testing** of TPM-dependent applications (drop-in for swtpm or the Microsoft TPM simulator) +- **CI/CD pipelines** that need TPM functionality (socket transport compatible with tpm2-tools) +- **Prototyping** TPM workflows before hardware is available +- **Post-quantum and SPDM work** without TPM silicon (see [Post-Quantum Support](post-quantum.md) and [SPDM Responder](spdm.md)) + +## Features + +- TPM 2.0 command processor covering 103 of the 112 Revision 1.38 command codes in a default build, with the limitations listed in Command Coverage. +- TCP socket transport using the Microsoft TPM simulator protocol, compatible with wolfTPM examples and tpm2-tools. Both the mssim and swtpm TCTI protocols are auto-detected on the command port. +- TIS register-level transport over POSIX shared memory, or over SPI or I2C for bare-metal integration. +- HAL abstractions for I/O and NV storage, so the core logic does not change when porting. See [HAL and Porting](hal-and-porting.md). +- Post-quantum cryptography with `--enable-pqc`: ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation per TCG TPM 2.0 Library Specification Version 185. `--enable-pqc` and `--enable-v185` are distinct project-wide modes, but configure promotes `--enable-pqc` to the full Version 185 mode when building the fwTPM, so the two behave the same for the fwTPM. Configure auto-detects PQC when `--enable-fwtpm` is built against a wolfCrypt that has both. See [Post-Quantum Support](post-quantum.md). +- SPDM 1.3 responder for testing the SPDM stack without silicon. See [SPDM Responder](spdm.md). +- Compile-time feature gates (`FWTPM_NO_*`) to shrink the build for constrained targets. See [Building](building.md). + +## Architecture + +``` ++---------------------+ +-------------------------------+ +| wolfTPM Client App | | fwtpm_server (or embedded) | +| (examples, tests) | | | ++----------+----------+ | +-------------------------+ | + | | | Transport Layer | | + TCP (SWTPM protocol) | | (socket or TIS) | | + or TIS shared memory | +------------+------------+ | + or SPI/I2C TIS | | | + | | +------------v------------+ | + +--------------->| | FWTPM_ProcessCommand | | + | | (fwtpm_command.c) | | + | +------+-----------+------+ | + | | | | + | +------v-----+ +---v------+ | + | | wolfCrypt | | NV | | + | | (RSA, ECC, | | backend | | + | | SHA, HMAC,| | (fwtpm_ | | + | | RNG, AES) | | nv.c) | | + | +------------+ +----------+ | + +-------------------------------+ +``` + +Both the socket and TIS transports pass each command to `FWTPM_ProcessCommand`. The command handlers then use wolfCrypt and the NV backend. The flow is the same for the standalone server and for an embedded integration. + +**Components:** + +| File | Role | +|------|------| +| `fwtpm_command.c` | TPM 2.0 command processor and dispatch table | +| `fwtpm_io.c` | Transport layer: SWTPM TCP socket protocol (enabled by the swtpm configuration; builds without it use the TIS path) | +| `fwtpm_nv.c` | NV storage: file-based (default); HAL-abstracted, with a built-in append-only mode for write-once flash | +| `fwtpm_tis.c` | TIS register state machine (transport-agnostic) | +| `fwtpm_tis_shm.c` | POSIX shared memory and semaphore TIS transport | +| `fwtpm_main.c` | Server entry point, CLI argument parsing | +| `tpm2_util.c` | Shared utilities (hash helpers, ForceZero, PrintBin) | +| `tpm2_packet.c` | TPM packet marshaling and unmarshaling | +| `tpm2_param_enc.c` | Parameter encryption (XOR and AES session encryption) | + +## Supported TPM 2.0 Commands + +This section lists representative commands and is not exhaustive. It omits supported commands such as `PCR_Event`, `PCR_Allocate`, `ClockRateAdjust`, several policy commands, and some algorithm-dependent commands. The Command Coverage section below has the dispatch-table breakdown. A default build (no `FWTPM_NO_*` macro set) includes every group below. Setting a gate macro removes that group's commands from the dispatch table, from `TPM2_GetCapability(TPM_CAP_COMMANDS)`, and from the `TPM_PT_TOTAL_COMMANDS` count. See [Building](building.md) for the gates. + +### Startup and Self-Test + +| Command | Description | +|---------|-------------| +| `TPM2_Startup` | Initialize TPM (SU_CLEAR or SU_STATE) | +| `TPM2_Shutdown` | Save state and prepare for power-off | +| `TPM2_SelfTest` | Minimal self-test: a SHA-256 known-answer test and an RNG check. The source calls this nonconformant. | +| `TPM2_IncrementalSelfTest` | No-op stub that returns an empty to-do list | +| `TPM2_GetTestResult` | Return self-test result | + +### Random Number Generation + +| Command | Description | +|---------|-------------| +| `TPM2_GetRandom` | Generate random bytes (max 48 per call) | +| `TPM2_StirRandom` | Add entropy to RNG state | + +### Capability + +| Command | Description | +|---------|-------------| +| `TPM2_GetCapability` | Query TPM properties, algorithms, handles | + +### Key Management + +| Command | Description | +|---------|-------------| +| `TPM2_CreatePrimary` | Create primary key under a hierarchy | +| `TPM2_Create` | Create child key under a parent | +| `TPM2_CreateLoaded` | Create and load key in one command | +| `TPM2_Load` | Load key from private and public parts | +| `TPM2_LoadExternal` | Load external (software) key | +| `TPM2_Import` | Import externally wrapped key | +| `TPM2_Duplicate` | Export key for transfer (inner and outer wrapping) | +| `TPM2_Rewrap` | Re-wrap a duplicated object from the old parent to a new parent | +| `TPM2_FlushContext` | Unload a transient object or session | +| `TPM2_ContextSave` | Save object or session context | +| `TPM2_ContextLoad` | Restore saved context | +| `TPM2_ReadPublic` | Read public area of a loaded key | +| `TPM2_ObjectChangeAuth` | Change authorization of a key | +| `TPM2_EvictControl` | Make transient key persistent (or remove) | +| `TPM2_HierarchyControl` | Enable or disable a hierarchy | +| `TPM2_HierarchyChangeAuth` | Change hierarchy authorization value | +| `TPM2_Clear` | Regenerate the storage primary seed, reset owner and endorsement authorization and policy state, and schedule eligible objects for removal. Does not regenerate the platform seed or the endorsement seed. | +| `TPM2_ChangePPS` | Replace platform primary seed | +| `TPM2_ChangeEPS` | Replace endorsement primary seed | + +### Cryptographic Operations + +| Command | Description | +|---------|-------------| +| `TPM2_Sign` | Sign digest with loaded key | +| `TPM2_VerifySignature` | Verify signature against loaded key | +| `TPM2_RSA_Encrypt` | RSA encryption (OAEP, PKCS1) | +| `TPM2_RSA_Decrypt` | RSA decryption | +| `TPM2_EncryptDecrypt` | Symmetric encrypt and decrypt | +| `TPM2_EncryptDecrypt2` | Symmetric encrypt and decrypt (alternate) | +| `TPM2_Hash` | Single-shot hash computation | +| `TPM2_HMAC` | Single-shot HMAC computation | +| `TPM2_ECDH_KeyGen` | Generate ephemeral ECC key pair | +| `TPM2_ECDH_ZGen` | Compute ECDH shared secret | +| `TPM2_ECC_Parameters` | Get ECC curve parameters | +| `TPM2_TestParms` | Validate algorithm parameter support | + +### Hash Sequences + +| Command | Description | +|---------|-------------| +| `TPM2_HashSequenceStart` | Start a hash sequence | +| `TPM2_HMAC_Start` | Start an HMAC sequence | +| `TPM2_SequenceUpdate` | Add data to a hash or HMAC sequence | +| `TPM2_SequenceComplete` | Finalize hash or HMAC sequence and get result | +| `TPM2_EventSequenceComplete` | Finalize hash sequence and extend PCR | + +### Sealing + +| Command | Description | +|---------|-------------| +| `TPM2_Unseal` | Unseal data from a sealed object | + +### PCR (Platform Configuration Registers) + +| Command | Description | +|---------|-------------| +| `TPM2_PCR_Read` | Read PCR values | +| `TPM2_PCR_Extend` | Extend a PCR with a digest | +| `TPM2_PCR_Reset` | Reset a resettable PCR | + +### Clock + +| Command | Description | +|---------|-------------| +| `TPM2_ReadClock` | Read TPM clock values | +| `TPM2_ClockSet` | Set TPM clock | + +### Sessions and Authorization + +| Command | Description | +|---------|-------------| +| `TPM2_StartAuthSession` | Create HMAC, policy, or trial session | + +### Policy + +| Command | Description | +|---------|-------------| +| `TPM2_PolicyGetDigest` | Get current policy session digest | +| `TPM2_PolicyRestart` | Reset policy session digest | +| `TPM2_PolicyPCR` | Bind policy to PCR values | +| `TPM2_PolicyPassword` | Include password in policy | +| `TPM2_PolicyAuthValue` | Include auth value in policy | +| `TPM2_PolicyCommandCode` | Restrict policy to specific command | +| `TPM2_PolicyOR` | Logical OR of policy branches | +| `TPM2_PolicySecret` | Authorization with secret | +| `TPM2_PolicyAuthorize` | Approve policy with signing key | +| `TPM2_PolicyNV` | Policy based on NV index comparison | +| `TPM2_PolicyLocality` | Restrict policy to specific locality | +| `TPM2_PolicySigned` | Authorize policy with external signing key | + +### Dictionary Attack (DA) Protection + +| Command | Description | +|---------|-------------| +| `TPM2_DictionaryAttackParameters` | Set `maxTries`, `recoveryTime`, `lockoutRecovery` | +| `TPM2_DictionaryAttackLockReset` | Reset the failed-tries counter (lockoutAuth) | + +The fwTPM implements dictionary-attack protection modeled on the TPM 2.0 specification (Part 1, Section 19.8). A failed authorization of a DA-protected entity increments `failedTries`. Once it reaches `maxTries` the TPM returns `TPM_RC_LOCKOUT`. `failedTries` is persisted in NV on every failure, so a power cycle cannot reset it. + +When a clock HAL is registered (`FWTPM_Clock_SetHAL`), the counter self-heals one try per `recoveryTime` seconds, and a non-orderly shutdown adds a one-try penalty. On clockless builds neither applies: the persisted `failedTries` counter does not self-heal, and recovery is only through `DictionaryAttackLockReset` or `Clear`, so routine unclean power-off cannot accumulate into lockout. + +A failed `lockoutAuth` locks the lockout hierarchy. On a build with a clock HAL, that lock persists across reboot and clears after `lockoutRecovery` seconds, except when `lockoutRecovery` is 0 (reboot-only recovery). On a clockless build, the failed-`lockoutAuth` lock is cleared on every startup. With a clock HAL, the clock HAL reports milliseconds since boot, so this timer measures continuous post-boot uptime, not wall-clock time across reboots. A device that reboots more often than `lockoutRecovery` extends its effective recovery window. + +There are two separate gates. A failed `lockoutAuth` blocks later uses of `lockoutAuth` (`DictionaryAttackLockReset`, `DictionaryAttackParameters`, and lockout-authorized `Clear`). Reaching `maxTries` blocks authorization of DA-protected objects, NV indices, and bound entities, and the TPM returns `TPM_RC_LOCKOUT`. The platform hierarchy is always an escape hatch: `TPM2_ClearControl(platformAuth, clearDisable=NO)` followed by `TPM2_Clear(platformAuth)` recovers even when `disableClear` was set. `Startup` and `Shutdown` are never DA-gated, so a reboot in lockout can always recover. Entities marked `noDA` (`TPMA_OBJECT_noDA` on objects, `TPMA_NV_NO_DA` on NV indices) never feed the counter and stay usable during lockout. + +`TPM2_GetCapability(TPM_CAP_TPM_PROPERTIES)` reports `TPM_PT_MAX_AUTH_FAIL`, `TPM_PT_LOCKOUT_INTERVAL`, `TPM_PT_LOCKOUT_RECOVERY`, `TPM_PT_LOCKOUT_COUNTER`, and the `inLockout` bit of `TPM_PT_PERMANENT`. + +Durable accounting writes the NV FLAGS entry on each DA-protected failure (and on the first DA-protected auth use per boot). The counter stops increasing while it is at `maxTries`, but clock-based self-healing can lower it, which allows further failed attempts and NV writes in the same boot, so the number of writes per boot is not strictly bounded. On flash-backed targets it still adds wear and makes failed-auth latency NV-bound, so size the NV backend accordingly. + +The first use of a DA-protected (non-`noDA`) authorization after startup can make a TPM persist a `daUsed` flag to NV and return `TPM_RC_RETRY` ("resubmit the identical command") while it writes. The TCG architecture describes this as one possible implementation approach, not a requirement for every TPM. Build with `FWTPM_DA_USED_RETRY` to emulate it so clients exercise their resubmit and retry handling. It is off by default, and DA accounting and persistence are active regardless. Compile out all DA logic with `FWTPM_NO_DA`. + +Coverage: DA, noDA, lockout, self-heal, and persistence unit tests in `tests/fwtpm_unit_tests.c`, the `examples/management/da_check` end-to-end example (add `-lockout` for the destructive lockout and recovery path), and the `tests/fwtpm_da_retry.sh` harness that exercises the `TPM_RC_RETRY` path against a `FWTPM_DA_USED_RETRY` build. + +### Non-Volatile Storage (NV) + +| Command | Description | +|---------|-------------| +| `TPM2_NV_DefineSpace` | Create an NV index | +| `TPM2_NV_UndefineSpace` | Delete an NV index | +| `TPM2_NV_ReadPublic` | Read NV index public metadata | +| `TPM2_NV_Write` | Write data to NV index | +| `TPM2_NV_Read` | Read data from NV index | +| `TPM2_NV_Extend` | Extend NV index (hash-extend) | +| `TPM2_NV_Increment` | Increment NV counter | +| `TPM2_NV_WriteLock` | Lock NV index for writes | +| `TPM2_NV_ReadLock` | Lock NV index for reads | +| `TPM2_NV_SetBits` | OR bits into NV bit field index | +| `TPM2_NV_ChangeAuth` | Change NV index authorization value | + +### Attestation and Credentials + +| Command | Description | +|---------|-------------| +| `TPM2_Quote` | Generate signed PCR quote | +| `TPM2_Certify` | Certify a loaded key | +| `TPM2_CertifyCreation` | Prove key was created by this TPM | +| `TPM2_GetTime` | Signed attestation of TPM clock | +| `TPM2_NV_Certify` | Certify NV index contents | +| `TPM2_MakeCredential` | Create credential blob for a key | +| `TPM2_ActivateCredential` | Unwrap credential blob | + +## Command Coverage + +### Implemented (103 Revision 1.38 command codes) + +This page counts command codes, not command names, and excludes `TPM_CC_Vendor_TCG_Test` from standard totals. Revision 1.38 defines 112 standard command codes. With RSA, ECC, AES, and all feature groups enabled, the dispatch table holds 103 of them, which is about 92% of the Revision 1.38 set. The Version 185 post-quantum commands add 8. Reaching 113 entries requires `WOLFTPM_SPDM` (one more command, `PolicyTransportSPDM`) and the test-only vendor command as well. + +**Core set, never gated (36 commands):** +Startup, Shutdown, SelfTest, IncrementalSelfTest, GetTestResult, GetRandom, StirRandom, GetCapability, TestParms, PCR_Read, PCR_Extend, PCR_Reset, PCR_Event, PCR_Allocate, PCR_SetAuthPolicy, PCR_SetAuthValue, CreatePrimary, FlushContext, ReadPublic, Clear, ClearControl, ChangeEPS, ChangePPS, HierarchyControl, HierarchyChangeAuth, SetPrimaryPolicy, EvictControl, Create, ObjectChangeAuth, Load, Sign, VerifySignature, StartAuthSession, Unseal, LoadExternal, CreateLoaded + +These are present in every build. + +**Optional vendor command (off by default, `WOLFTPM_FWTPM_TCG_TEST`):** +Vendor_TCG_Test + +**Conditional on algorithm (`NO_RSA`, `HAVE_ECC`, `NO_AES`):** +RSA_Encrypt, RSA_Decrypt, ECDH_KeyGen, ECDH_ZGen, ECC_Parameters, EC_Ephemeral, ZGen_2Phase, EncryptDecrypt, EncryptDecrypt2 + +**Conditional on feature macros:** + +- `FWTPM_NO_POLICY`: PolicyGetDigest, PolicyRestart, PolicyPCR, PolicyPassword, PolicyAuthValue, PolicyCommandCode, PolicyOR, PolicySecret, PolicyAuthorize, PolicyLocality, PolicySigned, PolicyNV, PolicyPhysicalPresence, PolicyCpHash, PolicyNameHash, PolicyDuplicationSelect, PolicyNvWritten, PolicyTemplate, PolicyCounterTimer, PolicyTicket, PolicyAuthorizeNV (21 commands). Also gates the conditional `PolicyTransportSPDM` command. +- `FWTPM_NO_NV`: NV_DefineSpace, NV_UndefineSpace, NV_UndefineSpaceSpecial, NV_ReadPublic, NV_Write, NV_Read, NV_Extend, NV_Increment, NV_WriteLock, NV_ReadLock, NV_SetBits, NV_ChangeAuth, NV_GlobalWriteLock (13 commands). Also gates PolicyNV and PolicyAuthorizeNV when policy is enabled and removes the in-memory NV index slots from `FWTPM_CTX`. NV_Certify is gated by `FWTPM_NO_NV` as well as `FWTPM_NO_ATTESTATION`. +- `FWTPM_NO_ATTESTATION`: Quote, Certify, CertifyCreation, GetTime, NV_Certify (NV_Certify is also removed by `FWTPM_NO_NV`) +- `FWTPM_NO_CREDENTIAL`: MakeCredential, ActivateCredential +- `FWTPM_NO_DA`: DictionaryAttackLockReset, DictionaryAttackParameters (2 commands) +- `FWTPM_NO_PARAM_ENC`: Disables parameter encryption and decryption for command and response parameters. Sessions still work for HMAC auth, but encrypted transport is disabled. Reduces code size by removing AES-CFB and XOR parameter encryption. +- `FWTPM_NO_KEY_MIGRATION`: Import, Duplicate, Rewrap (3 commands). Shared key helpers used by Create and Load are retained. +- `FWTPM_NO_ECDH`: ECDH_KeyGen, ECDH_ZGen, EC_Ephemeral, ZGen_2Phase, ECC_Parameters (5 commands). ECDSA sign and verify are retained. Also drops the `ecEphemeral*` commit state from `FWTPM_CTX`. +- `FWTPM_NO_HASH_CMDS`: Hash, HMAC, HMAC_Start, HashSequenceStart, SequenceUpdate, SequenceComplete, EventSequenceComplete (7 commands). When `WOLFTPM_MLDSA` is built, only SequenceUpdate is retained, because the ML-DSA verify sequences stream their message through it. SequenceComplete is not shared: ML-DSA sequences finalize through SignSequenceComplete and VerifySequenceComplete, so advertising it in a gated build would expose a command that can never succeed. Also drops the per-instance hash-sequence slots (`hashSeq[FWTPM_MAX_HASH_SEQ]`) from `FWTPM_CTX`. +- `FWTPM_NO_CONTEXT`: ContextSave, ContextLoad (2 commands). FlushContext is retained. Also drops the per-boot context protection key and the saved-context replay list from `FWTPM_CTX`. +- `FWTPM_NO_SYM_ENCRYPT`: EncryptDecrypt, EncryptDecrypt2 (2 commands). Nests inside `NO_AES`. AES itself is retained for session parameter encryption, AES-GCM, and (unless `FWTPM_NO_CONTEXT` is also set) context protection. +- `FWTPM_NO_CLOCK`: ReadClock, ClockSet, ClockRateAdjust (3 commands). GetTime is under `FWTPM_NO_ATTESTATION`, not this flag. +- `FWTPM_NO_PP`: PolicyPhysicalPresence and physical-presence enforcement. Drops the physical-presence HAL, the platform latch, and `FWTPM_PP_SetHAL`. + +These gates are independent and there is intentionally no umbrella macro: pick exactly the groups your fTPM does not need. Applying every gate leaves the core set of 36 always-present commands, plus whatever the algorithm configuration keeps (keeping NV, or adding `FWTPM_NO_NV` to drop it). See the MicroBlaze V example in the `wolftpm-examples` repository (listed in [Usage](usage.md)) for a worked selection. + +### Missing Commands + +#### Revision 1.38 baseline (9 missing command codes) + +Medium (moderate logic, builds on existing infrastructure): + +| Command | Spec Section | Difficulty | Notes | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_SetCommandCodeAuditStatus` | 21.2 | Medium | Manage list of commands that are audited. Needs audit bitmap in context | +| `TPM2_PP_Commands` | 26.2 | Medium | Manage physical presence command list. Needs PP command bitmap | + +Hard (complex crypto or new subsystems): + +| Command | Spec Section | Difficulty | Notes | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_GetSessionAuditDigest` | 18.5 | Hard | Sign session audit digest. Requires session audit tracking (running hash of all commands in session). New subsystem | +| `TPM2_GetCommandAuditDigest` | 18.6 | Hard | Sign command audit digest. Requires command audit log with running hash. New subsystem | +| `TPM2_Commit` | 19.2 | Hard | DAA and anonymous attestation ephemeral key. Complex ECC point math (K, L, E generation). Needs DAA support in wolfCrypt | +| `TPM2_SetAlgorithmSet` | 26.3 | Hard | Vendor-specific algorithm configuration. Rarely implemented, can return TPM_RC_COMMAND_CODE | +| `TPM2_FieldUpgradeStart` | 27.2 | Hard | Firmware upgrade initiation. Vendor-specific, requires secure update infrastructure | +| `TPM2_FieldUpgradeData` | 27.3 | Hard | Firmware upgrade data blocks. Vendor-specific | +| `TPM2_FirmwareRead` | 27.4 | Hard | Read firmware for backup. Vendor-specific | + +#### Revision 1.59 additions (5 new command codes) + +`TPM2_MAC` shares command code 0x155 with `TPM2_HMAC`, and `TPM2_MAC_Start` shares 0x15B with `TPM2_HMAC_Start`, so they add no new codes. The source shows only the HMAC form (no CMAC handling was found), so the symmetric-key MAC form is not confirmed as supported. + +| Command | Spec Section | Difficulty | Notes | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_MAC` | 15.6 | Medium | Block cipher MAC (CMAC). Like HMAC but uses symmetric key. Needs wolfCrypt CMAC | +| `TPM2_MAC_Start` | 17.3 | Medium | Start MAC sequence. Mirrors HMAC_Start for CMAC | +| `TPM2_CertifyX509` | 18.8 | Hard | Generate partial X.509 certificate. Complex ASN.1 construction, caller provides tbsCert template. Deprecated in Version 184 | +| `TPM2_AC_GetCapability` | 32.2 | Hard | Deprecated in Version 184. Attached component capability query. Hardware-specific, rarely needed for software TPM | +| `TPM2_AC_Send` | 32.3 | Hard | Deprecated in Version 184. Send data to attached component. Hardware-specific | +| `TPM2_Policy_AC_SendSelect` | 32.4 | Medium | Deprecated in Version 184. Policy for AC_Send. Like other policy commands | +| `TPM2_ACT_SetTimeout` | 33.2 | Medium | Set authenticated countdown timer. Needs ACT state and timer infrastructure | + +#### Version 184 additions (9 command codes, 8 missing) + +Version 184 marks `CreateLoaded`, `AC_GetCapability`, `AC_Send`, `Policy_AC_SendSelect`, and `CertifyX509` as deprecated. `CreateLoaded` is still implemented here. + +| Command | Spec Section | Difficulty | Notes | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_ECC_Encrypt` | 14.8 | Medium | ECC-based encryption using the TPM-defined construction from Part 1 Annex C (ephemeral ECDH point, KDF-derived masking, and integrity data). The command does not expose a choice of scheme. | +| `TPM2_ECC_Decrypt` | 14.9 | Medium | ECC-based decryption. Paired with ECC_Encrypt | +| `TPM2_PolicyCapability` | 23.x | Easy | Assert TPM capability value in policy session | +| `TPM2_PolicyParameters` | 23.x | Easy | Assert command parameters in policy session | +| `TPM2_SetCapability` | 30.x | Medium | Modify TPM capability settings. Platform auth required | +| `TPM2_NV_DefineSpace2` | 31.x | Medium | Extended NV space definition (larger attribute field). Extends existing NV_DefineSpace | +| `TPM2_NV_ReadPublic2` | 31.x | Easy | Extended NV public read. Extends existing NV_ReadPublic | +| `TPM2_ReadOnlyControl` | 24.x | Easy | Toggle TPM read-only mode. Simple flag | + +#### Conditionally implemented + +`TPM2_PolicyTransportSPDM` has a handler and a dispatch-table entry whenever `WOLFTPM_SPDM` is enabled, and it is removed by `FWTPM_NO_POLICY`. It is not missing. See [SPDM Responder](spdm.md). + +### Coverage Summary + +The eight Version 185 PQC commands (`TPM2_Encapsulate`, `TPM2_Decapsulate`, `TPM2_SignDigest`, `TPM2_VerifyDigestSignature`, `TPM2_SignSequenceStart`, `TPM2_SignSequenceComplete`, `TPM2_VerifySequenceStart`, `TPM2_VerifySequenceComplete`) are implemented under `--enable-pqc`. See [Post-Quantum Support](post-quantum.md) for the PQC-only restriction on these commands. + +| Spec Version | Total Command Codes | Implemented (default build) | Missing | Coverage | +|-------------|---------------------|-----------------------------|---------|----------| +| Revision 1.38 | 112 | 103 | 9 | 92% | +| Revision 1.59 | 117 | 103 | 14 | 88% | +| Version 184 | 126 | 103 | 23 | 82% | +| Version 185 | 134 | 111 | 23 | 83% | + +Implemented counts assume RSA, ECC, AES, and all feature groups, with SPDM, PQC (except in the Version 185 row), and the vendor test command disabled. Enabling `WOLFTPM_SPDM` adds `PolicyTransportSPDM` (one more implemented code). The Version 185 row includes the eight PQC commands. + +Known limitations: `TPM2_SelfTest` is a minimal smoke test and `TPM2_IncrementalSelfTest` is a stub, as noted above, and `SU_STATE` resume is not supported (see the lifecycle section). The command coverage above should not be read as full conformance with the TCG specification. + +## Startup and Shutdown Lifecycle + +1. **First boot:** `FWTPM_NV_Init` finds no NV file, generates random hierarchy seeds, and saves the initial state. +2. **`TPM2_Startup(SU_CLEAR)`:** Flushes transient objects and sessions and resets PCRs. Required before most other TPM commands. `TPM2_GetCapability` is accepted before `Startup`. +3. **Normal operation:** Commands are processed through `FWTPM_ProcessCommand`. +4. **`TPM2_Shutdown`:** Saves NV state but does not clear the "started" flag. The TPM remains logically powered on. +5. **Server restart** (process exit and relaunch) constitutes a power cycle. Only after a power cycle can `TPM2_Startup` be called again. + +Calling `TPM2_Startup` on an already-started TPM returns `TPM_RC_INITIALIZE`. + +Known limitation: `Startup(SU_STATE)` is accepted without checking that a matching `Shutdown(SU_STATE)` came before it, and a process restart zeroes `FWTPM_CTX` and reloads only NV-backed state. Transient objects and sessions are therefore not preserved across a restart, which a conforming TPM Resume requires. This stays a limitation until volatile state serialization and the shutdown and startup sequence checks are implemented. + +## Primary Key Derivation + +Primary keys are deterministically derived from the hierarchy seed from the hierarchy seed using KDFa-based formulas that are specific to this implementation. The same seed, the same public template, and the same `sensitiveCreate.data` always produce the same key. Revision 1.38 discusses primary-object creation in Clause 27. + +- **RSA:** Primes p and q are derived by iterative KDFa with the labels `"RSA p"` and `"RSA q"`, then primality testing, then CRT computation. +- **ECC:** The private scalar d is derived with `KDFa(nameAlg, seed, "ECC", hashUnique, counter)`, and the public point is Q = d*G. +- **KEYEDHASH and SYMCIPHER:** Key bytes are derived with `KDFa(nameAlg, seed, label, hashUnique)`. For KEYEDHASH, nonempty `sensitiveCreate.data` is used directly and is not derived. +- **hashUnique:** `H(sensitiveCreate.data || inPublic.unique)`. Because `sensitiveCreate.data` feeds `hashUnique` and the cache digest, a different value gives a different key. + +A primary key cache (SHA-256 of the template, `FWTPM_MAX_PRIMARY_CACHE` slots) avoids re-deriving expensive RSA keys on repeated `CreatePrimary` calls. + +Hierarchy seeds are managed by `ChangePPS` (platform) and `ChangeEPS` (endorsement). `Clear` regenerates the owner (storage primary) seed and resets endorsement authorization and policy state, but it leaves the endorsement seed and the platform seed unchanged; use `ChangeEPS` to replace the endorsement seed. The null seed is re-randomized on every `Startup(CLEAR)`. For post-quantum primary keys, see [Post-Quantum Support](post-quantum.md). + +## See Also + +- [Building](building.md) +- [Usage](usage.md) +- [HAL and Porting](hal-and-porting.md) +- [Post-Quantum Support](post-quantum.md) +- [SPDM Responder](spdm.md) +- [Post-Quantum (library-wide)](../post-quantum.md) +- [SPDM (library-wide)](../spdm.md) diff --git a/docs/fwtpm/post-quantum.md b/docs/fwtpm/post-quantum.md new file mode 100644 index 00000000..bf875df6 --- /dev/null +++ b/docs/fwtpm/post-quantum.md @@ -0,0 +1,100 @@ +# fwTPM Post-Quantum Support (TPM 2.0 v1.85) + +The fwTPM implements the post-quantum additions from TCG TPM 2.0 Library Specification v1.85, using wolfCrypt's FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA) modules. This brings post-quantum keys, signing, and key encapsulation to platforms that have no TPM silicon. These v1.85 commands raise the implemented count from 103 to 111 commands. For the library-wide post-quantum view, see [Post-Quantum](../post-quantum.md). + +Enable it with `--enable-pqc`, which the fwTPM build promotes to the full `--enable-v185`, at configure time. It is also auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has both ML-DSA and ML-KEM available. Both flags set the internal `WOLFTPM_V185` macro that gates the implementation. Pass `--disable-pqc` to opt out when auto-detect would otherwise enable it. + +## Algorithms + +| Alg | Parameter Sets | Use | +|---|---|---| +| `TPM_ALG_MLKEM` (0x00A0) | ML-KEM-512 / 768 / 1024 | Key encapsulation (decrypt-only keys) | +| `TPM_ALG_MLDSA` (0x00A1) | ML-DSA-44 / 65 / 87 | Pure ML-DSA message signing | +| `TPM_ALG_HASH_MLDSA` (0x00A2) | HashML-DSA-44 / 65 / 87 | Pre-hashed ML-DSA signing | + +## Commands + +The eight v1.85 PQC commands live in `src/fwtpm/fwtpm_command.c`: + +| Command | CC | Purpose | +|---|---|---| +| `TPM2_Encapsulate` | `0x000001A7` | ML-KEM encapsulation, returns sharedSecret and ciphertext | +| `TPM2_Decapsulate` | `0x000001A8` | ML-KEM decapsulation from ciphertext (requires USER auth) | +| `TPM2_SignSequenceStart` | `0x000001AA` | Begin ML-DSA sign sequence | +| `TPM2_SignSequenceComplete` | `0x000001A4` | Finalize sign sequence with message buffer | +| `TPM2_VerifySequenceStart` | `0x000001A9` | Begin ML-DSA verify sequence | +| `TPM2_VerifySequenceComplete` | `0x000001A3` | Finalize verify sequence, returns TPMT_TK_VERIFIED | +| `TPM2_SignDigest` | `0x000001A6` | One-shot digest sign (HashML-DSA or ext-mu ML-DSA) | +| `TPM2_VerifyDigestSignature` | `0x000001A5` | Verify digest signature | + +## Primary Key Derivation + +PQC primary keys follow the same deterministic derivation model as RSA and ECC: hierarchy seed and template, then a KDFa-derived seed, then FIPS 203 or FIPS 204 key expansion. + +- **ML-DSA:** `KDFa(nameAlg, seed, "MLDSA", hashUnique)` gives a 32-byte Xi. `wc_MlDsaKey_MakeKeyFromSeed` turns that into the public key and the expanded private key. The wire format stores only the 32-byte Xi per TCG Part 2 Table 210. +- **HashML-DSA:** the label is `"HASH_MLDSA"`, with the same seed size and expansion. +- **ML-KEM:** `KDFa(nameAlg, seed, "MLKEM", hashUnique)` gives a 64-byte value (d followed by z). `wc_MlKemKey_MakeKeyWithRandom` turns that into the encapsulation and decapsulation keys. The wire format stores only the 64-byte seed per TCG Part 2 Table 206. + +!!! note + These label strings are an interpretation. TCG Part 4 v185, which would specify them normatively, is unpublished. They are subject to change if a later release candidate or Part 4 v185 prescribes different labels. + +## Sign and Verify Sequences + +Pure ML-DSA sequences are streamable on both sign and verify, so `TPM2_SequenceUpdate` is accepted. `TPM_RC_ONE_SHOT_SIGNATURE` applies to multi-pass schemes such as EdDSA, not to pure ML-DSA. A caller can also pass the whole message through the `buffer` parameter of `TPM2_SignSequenceComplete`. Verify sequences accumulate the message through `TPM2_SequenceUpdate`, because `TPM2_VerifySequenceComplete` has no buffer parameter. + +HashML-DSA sequences (both sign and verify) use wolfCrypt's `wc_HashAlg` context to stream the message into the key's hash algorithm. `TPM2_SignSequenceComplete` finalizes the hash and calls `wc_MlDsaKey_SignCtxHash`. + +Signature wire formats differ per spec Part 2 Table 217: + +- **Pure ML-DSA:** `TPM2B_SIGNATURE_MLDSA`, laid out as `sigAlg + size + bytes` +- **HashML-DSA:** `TPMS_SIGNATURE_HASH_MLDSA`, laid out as `sigAlg + hashAlg + size + bytes` + +## Buffer Constants + +Under `WOLFTPM_V185`, buffers are lifted to fit ML-DSA-87 signatures (4627 bytes) and public keys (2592 bytes): + +| Symbol | v1.38 | v1.85 | +|---|---|---| +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 8192 | +| `FWTPM_MAX_PUB_BUF` | 512 | 2720 | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | 4736 | +| `FWTPM_MAX_KEM_CT_BUF` | n/a | 1600 | +| `FWTPM_TIS_FIFO_SIZE` | 4096 | 8192 | +| `FWTPM_NV_PUBAREA_EST` | 600 | 2720 | + +These are the worst-case values. The defaults shrink at compile time to match the parameter sets wolfCrypt was built with. See "v1.85 Embedded RAM Impact" in [Building](building.md) for the per-parameter-set table. + +## Limitations and Scope + +The v1.85 commands are implemented for post-quantum keys only. Non-PQC key types are rejected with `TPM_RC_KEY` or `TPM_RC_SCHEME`, even when the v1.85 spec defines the commands generically: + +- `TPM2_Encapsulate` and `TPM2_Decapsulate`: ML-KEM only. ECC DHKEM (the Table 100 `ecdh` arm with a non-NULL KDF) is not implemented. +- `TPM2_SignSequenceStart`, `TPM2_VerifySequenceStart`, `TPM2_SignSequenceComplete`, and `TPM2_VerifySequenceComplete`: ML-DSA and HashML-DSA only. Classical schemes (RSASSA, RSAPSS, ECDSA, SM2, ECSCHNORR, HMAC) that the spec also permits through these commands are not supported. +- `TPM2_SignDigest` and `TPM2_VerifyDigestSignature`: ML-DSA and HashML-DSA only. Classical digest signing (RSASSA, RSAPSS, ECDSA) over these new commands is not supported. Use the existing `TPM2_Sign` and `TPM2_VerifySignature` commands for those schemes. + +## Deferred and Out of Scope + +Three v1.85 features are deferred, each for a documented reason: + +1. **ML-KEM-salted sessions.** Part 3 Sec.11.1 (`TPM2_StartAuthSession`) does not describe an ML-KEM bullet alongside the RSA-OAEP and ECDH paths, even though Part 2 Sec.11.4.2 Table 222 defines the `mlkem` arm of `TPMU_ENCRYPTED_SECRET`. Part 4 v185, which would specify this normatively, is not yet published. Current behavior: `TPM2_StartAuthSession` returns `TPM_RC_KEY` for an ML-KEM tpmKey. Revisit when Part 4 v185 is published. +2. **External-mu ML-DSA signing.** wolfCrypt has no mu-direct sign API. Part 2 Sec.12.2.3.7 says "512-byte external Mu", but FIPS 204 Algorithm 7 Line 6 produces 64 bytes (SHAKE256 output). This is pending a wolfCrypt API addition and TCG errata confirmation. Current behavior: `TPM_RC_SCHEME` for ext-mu paths, and `TPM_RC_EXT_MU` for Pure ML-DSA keys without `allowExternalMu`. +3. **ECC KEM arm of Encapsulate and Decapsulate.** Part 2 Sec.10.3.13 Table 100 has both `mlkem` and `ecdh` arms, but the table note allows implementations to modify the union based on the algorithms they support. The fwTPM supports the `mlkem` arm only. + +## Test Coverage + +`tests/fwtpm_unit_tests.c` includes ten PQC tests that exercise the full path: + +- CreatePrimary for ML-KEM-768 and ML-DSA-65 +- Full Encapsulate and Decapsulate round-trip (shared secret byte match) +- HashML-DSA SignDigest and VerifyDigestSignature round-trip +- Pure ML-DSA sign sequence and verify sequence round-trip +- Dual-source known-answer tests (NIST ACVP and wolfSSL internal vectors) for ML-DSA-44 verify, ML-DSA-44 keygen determinism, ML-KEM-512 encapsulation with pinned randomness, and ML-KEM-512 keygen determinism +- LoadExternal of a NIST ACVP ML-DSA-44 public key through the fwTPM handler + +## See Also + +- [Overview](overview.md) +- [Building](building.md) +- [Usage](usage.md) +- [SPDM Responder](spdm.md) +- [Post-Quantum (library-wide)](../post-quantum.md) diff --git a/docs/fwtpm/spdm.md b/docs/fwtpm/spdm.md new file mode 100644 index 00000000..7f46df12 --- /dev/null +++ b/docs/fwtpm/spdm.md @@ -0,0 +1,64 @@ +# fwTPM SPDM Responder + +The fwTPM ships an SPDM 1.3 responder, so the full SPDM stack can be exercised against a TPM that has no silicon behind it. It supports both the TCG raw public key handshake (GET_PUBK and GIVE_PUB, no certificates) and the DSP0274 pre-shared key (PSK) handshake. This lets you develop and test SPDM-secured TPM communication in CI or on a workstation before real hardware is available. For the library-wide SPDM view, see [SPDM](../spdm.md). + +## How It Works + +When SPDM is on, the responder sits above the existing transport HAL and dispatches TCG-framed messages into the SPDM state machine. The two message tags are: + +| Tag | Meaning | +|-----|---------| +| `0x8101` | Clear (unsecured) SPDM message | +| `0x8201` | Secured SPDM message | + +Plaintext TPM frames fall through to the regular command dispatcher until the requester issues `SPDMONLY LOCK`. After that, only `TPM2_GetCapability` is allowed through in plaintext, which matches the behavior of Nuvoton and Nations silicon. + +## Building + +Build with `--enable-fwtpm --enable-spdm` plus at least one of `--enable-tcg` or `--enable-psk`: + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-spdm --enable-tcg --enable-psk --enable-nuvoton --enable-nations +make +``` + +## Starting the Responder + +Start the server in one of three modes: + +```sh +SPDM_PSK=dbc2192291d807742441b963f6712841f7697e2e39c45931f3abc53658c8b9338bd3561cab5d90cf9e493295bb5bd6b2c455e0fd19392e0ce4f3433cbcfc7047 +./src/fwtpm/fwtpm_server --spdm-tcg # TCG raw public key handshake +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" # PSK handshake +./src/fwtpm/fwtpm_server --no-spdm # plaintext only (default) +``` + +The responder takes a non-empty PSK of at most 64 bytes (128 hex characters); the exact 64-byte requirement applies to Nations hardware provisioning, not to this responder. The value above is the test value used by `spdm_test.sh`. For a manual PSK test, give the requester the same value, for example `spdm_ctrl --psk "$SPDM_PSK"`. + +## Responder Identity Key + +The responder generates a fresh P-384 identity keypair at startup. It is used to sign `GET_PUBK` and `KEY_EXCHANGE`. The private key never leaves `fwtpm_server` memory, and the stack copy is zeroed with `wc_ForceZero` after it is handed to the responder context. + +In TCG mode, the server prints the public half during startup so the local test harness can pass it to the requester through the responder-key pinning API. + +!!! warning + This printed public key is a test bootstrap channel. It is not a substitute for authenticated device provisioning, and it is not a trust anchor for hardware responders. + +## Testing + +End-to-end coverage uses the same script that drives real silicon: + +```sh +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-tcg +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-psk +``` + +CI exercises 7 build-only configure permutations plus the two end-to-end modes on `ubuntu-latest` through `spdm-test.yml`, against the fwTPM SPDM responder. + +## See Also + +- [Overview](overview.md) +- [Building](building.md) +- [Usage](usage.md) +- [Post-Quantum Support](post-quantum.md) +- [SPDM (library-wide)](../spdm.md) diff --git a/docs/fwtpm/usage.md b/docs/fwtpm/usage.md new file mode 100644 index 00000000..4498d4fb --- /dev/null +++ b/docs/fwtpm/usage.md @@ -0,0 +1,292 @@ +# Using the fwTPM + +This page covers running the fwTPM server, connecting clients, transport modes, NV persistence, testing, the C API, and real-world board examples. To build the server first, see [Building](building.md). + +## Starting the Server + +```sh +./src/fwtpm/fwtpm_server [options] +``` + +**Options:** + +| Option | Description | +|--------|-------------| +| `--help`, `-h` | Show usage information | +| `--version`, `-v` | Print version string | +| `--port ` | Command port (default: 2321) | +| `--platform-port ` | Platform port (default: 2322) | +| `--clear` | Start with cleared NV | +| `--spdm-tcg`, `--spdm-psk`, `--no-spdm` | SPDM responder mode (see [SPDM Responder](spdm.md)) | + +The `--port` and `--platform-port` options are socket-mode only and are not available in TIS builds (`--enable-fwtpm --disable-swtpm`). + +**Example:** + +```sh +# Start with default ports (localhost:2321 command, :2322 platform) +./src/fwtpm/fwtpm_server + +# Start on custom ports +./src/fwtpm/fwtpm_server --port 2331 --platform-port 2332 + +# Start with clear NV +./src/fwtpm/fwtpm_server --clear +``` + +The server prints its configuration on startup: + +``` +wolfTPM fwTPM Server v0.1.0 + Command port: 2321 + Platform port: 2322 + Manufacturer: WOLF + Model: fwTPM +``` + +In `--spdm-tcg` test mode the server also prints its generated responder public key. This is a local test-harness convenience, not a provisioning or trust-anchor channel for hardware responders. + +## Connecting wolfTPM Clients + +Any wolfTPM application built with `--enable-swtpm` connects to the fwTPM server automatically over TCP. The built-in swtpm client speaks the mssim protocol. + +```sh +# In one terminal: start the server +./src/fwtpm/fwtpm_server + +# In another terminal: run wolfTPM examples +./examples/wrap/wrap_test +./examples/wrap/caps +./examples/keygen/keygen keyblob.bin -rsa -t +./examples/attestation/make_credential +``` + +### Using tpm2-tools + +In socket mode (`--enable-swtpm`), the server supports both the mssim (Microsoft TPM simulator) and swtpm (Stefan Berger) TCTI protocols, which it auto-detects on the command port. Either TCTI works: + +```sh +# mssim TCTI (default for wolfTPM test scripts) +export TPM2TOOLS_TCTI="mssim:host=localhost,port=2321" +tpm2_startup -c + +# swtpm TCTI (also works, auto-detected) +export TPM2TOOLS_TCTI="swtpm:host=localhost,port=2321" +tpm2_getrandom 8 +``` + +## NV Persistence + +The server stores persistent state (hierarchy seeds, auth values, PCR state, NV indices) in `fwtpm_nv.bin` (configurable with `FWTPM_NV_FILE`). On first start, seeds are randomly generated and saved. Later starts reload the existing state. + +Embedded targets replace the file backend with a flash, EEPROM, or other NV HAL, including an append-only mode for write-once flash. See [HAL and Porting](hal-and-porting.md). + +## Transport Modes + +### Socket / SWTPM (Default) + +Built with `--enable-fwtpm --enable-swtpm`. The server listens on two TCP ports using the SWTPM wire protocol: + +- **Command port** (default 2321): TPM command and response traffic +- **Platform port** (default 2322): Platform signals (power on and off, NV on, cancel, reset, session end, stop) + +**SWTPM TCP protocol commands** (platform port): + +| Signal | Value | Description | +|--------|-------|-------------| +| `SIGNAL_POWER_ON` | 1 | Power on the TPM | +| `SIGNAL_POWER_OFF` | 2 | Power off the TPM | +| `SIGNAL_PHYS_PRES_ON` | 3 | Assert physical presence | +| `SIGNAL_PHYS_PRES_OFF` | 4 | Deassert physical presence | +| `SIGNAL_HASH_START` | 5 | Start measured boot hash | +| `SIGNAL_HASH_DATA` | 6 | Provide measured boot data | +| `SIGNAL_HASH_END` | 9 | End measured boot hash | +| `SEND_COMMAND` | 8 | Send TPM command (command port) | +| `SIGNAL_NV_ON` | 11 | NV storage available | +| `SIGNAL_CANCEL_ON` | 13 | Cancel current command | +| `SIGNAL_CANCEL_OFF` | 14 | Clear cancel | +| `SIGNAL_RESET` | 17 | Reset TPM | +| `SESSION_END` | 20 | End TCP session | +| `STOP` | 21 | Stop server | + +wolfTPM clients connect through the standard SWTPM interface, which is compatible with `tpm2-tools` and other SWTPM-aware software. + +### TIS / Shared Memory + +Built with `--enable-fwtpm --disable-swtpm`. This mode uses POSIX shared memory and named semaphores to emulate TIS (TPM Interface Specification) register-level access. It simulates an SPI-attached TPM. + +**Shared memory layout** (`FWTPM_TIS_SHM`): + +| Field | Description | +|-------|-------------| +| `magic` / `version` | Validation header (`0x57544953` / "WTIS", protocol version 2) | +| `reg_addr`, `reg_len`, `reg_is_write`, `reg_data` | Register access request | +| TIS register shadow: `access`, `sts`, `int_enable`, `int_status`, `intf_caps`, `did_vid`, `rid` | Emulated TIS registers | +| `cmd_buf[4096]`, `cmd_len`, `fifo_write_pos` | Command FIFO | +| `rsp_buf[4096]`, `rsp_len`, `fifo_read_pos` | Response FIFO | + +**Paths** (compile-time configurable): + +| Define | Default | Description | +|--------|---------|-------------| +| `FWTPM_TIS_SHM_PATH` | `/tmp/fwtpm.shm` | Shared memory file; clients require a regular, single-link, same-UID, exact-size `0600` endpoint | +| `FWTPM_TIS_SEM_CMD` | `/fwtpm_cmd` | Command semaphore name | +| `FWTPM_TIS_SEM_RSP` | `/fwtpm_rsp` | Response semaphore name | + +Clients require an exact protocol version and shared-region-size match, so rebuild the client library and `fwtpm_server` together when changing options that affect `FWTPM_TIS_FIFO_SIZE`. The default paths are global, so run one server per host. + +**Server-side API:** + +- `FWTPM_TIS_Init()`: create shared memory and semaphores +- `FWTPM_TIS_Cleanup()`: remove shared memory and semaphores +- `FWTPM_TIS_ServerLoop()`: process TIS register accesses and dispatch commands + +**Client-side API** (enabled by `WOLFTPM_FWTPM_HAL`): + +- `FWTPM_TIS_ClientConnect()`: attach to existing shared memory +- `FWTPM_TIS_ClientDisconnect()`: detach from shared memory + +## Testing + +```sh +make check # Build + unit.test + run_examples.sh + tpm2-tools +scripts/tpm2_tools_test.sh # tpm2-tools only (311 tests) +``` + +`make check` runs `tests/fwtpm_check.sh`, which starts and stops `fwtpm_server` automatically. Do not start the server manually for it. + +### CI Tests (fwtpm-test.yml) + +All tests below run in GitHub Actions CI. Run them manually before PR submission. ASan, UBSan, and LeakSan coverage lives in `sanitizer.yml`, not this workflow. + +**Runtime tests (build, run_examples.sh, make check):** + +| Name | wolfTPM Config | Extra | Notes | +|------|---------------|-------|-------| +| fwtpm-socket | `--enable-fwtpm --enable-swtpm --enable-debug` | | Primary test | +| fwtpm-tis | `--enable-fwtpm --disable-swtpm --enable-debug` | | TIS/SHM transport | +| fwtpm-v185 | `--enable-fwtpm --enable-v185` | | PQC: wrapper and handler unit tests | +| fwtpm-macos-socket | `--enable-fwtpm --enable-swtpm --enable-debug` | | macOS runner | + +**Runtime tests, gated builds (`fwtpm-gated-runtime` job):** + +These configurations remove commands, so `make check` (which drives the examples and tpm2-tools) does not apply. The job builds and runs only `tests/fwtpm_unit.test`. Its `test_fwtpm_command_gates`, `test_fwtpm_total_commands`, and `test_fwtpm_pcr_bounds` cases assert that a gated command is rejected with `TPM_RC_COMMAND_CODE`, is absent from `TPM_CAP_COMMANDS`, and is not counted in `TPM_PT_TOTAL_COMMANDS`. + +| Name | wolfTPM Config | wolfSSL Config | Extra CFLAGS | +|------|---------------|---------------|-------------| +| all-gates-ecc-only | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | the eleven command-group `-DFWTPM_NO_*` gates together (NV retained) | +| all-gates-mldsa | `--enable-fwtpm --enable-swtpm --enable-v185 --enable-mldsa` | `--enable-dilithium --enable-mlkem` | the same eleven gates; proves SequenceUpdate survives for ML-DSA while SequenceComplete does not | +| reduced-pcr | `--enable-fwtpm --enable-swtpm` | | `-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8` | + +**Build-only tests:** + +| Name | wolfTPM Config | wolfSSL Config | Extra CFLAGS | +|------|---------------|---------------|-------------| +| fwtpm-no-rsa | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | | +| fwtpm-no-ecc | `--enable-fwtpm --enable-swtpm` | `--disable-ecc` | | +| fwtpm-no-sha384 | `--enable-fwtpm --enable-swtpm` | `--disable-sha384` | | +| fwtpm-no-sha1 | `--enable-fwtpm --enable-swtpm` | `--disable-sha` | `-DNO_SHA` | +| fwtpm-v185-build-only | `--enable-fwtpm --enable-v185` | | `-DDEBUG_WOLFTPM` | +| fwtpm-only | `--enable-fwtpm-only --enable-swtpm` | | No client library | +| fwtpm-minimal | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ATTESTATION -DFWTPM_NO_NV -DFWTPM_NO_POLICY -DFWTPM_NO_CREDENTIAL -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC` | +| fwtpm-no-policy | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_POLICY` | +| fwtpm-no-nv | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_NV` | +| fwtpm-no-attestation | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ATTESTATION` | +| fwtpm-no-credential | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CREDENTIAL` | +| fwtpm-no-da | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_DA` | +| fwtpm-no-param-enc | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_PARAM_ENC` | +| fwtpm-no-key-migration | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_KEY_MIGRATION` | +| fwtpm-no-ecdh | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ECDH` | +| fwtpm-no-hash-cmds | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_HASH_CMDS` | +| fwtpm-no-context | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CONTEXT` | +| fwtpm-no-sym-encrypt | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_SYM_ENCRYPT` | +| fwtpm-no-clock | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CLOCK` | +| fwtpm-reduced-pcr | `--enable-fwtpm --enable-swtpm` | | `-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8` | +| fwtpm-no-rsa-no-policy | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | `-DFWTPM_NO_POLICY` | +| fwtpm-no-ecc-no-nv | `--enable-fwtpm --enable-swtpm` | `--disable-ecc` | `-DFWTPM_NO_NV` | +| fwtpm-small-stack | `--enable-fwtpm --enable-swtpm` | | `-DWOLFTPM_SMALL_STACK` | + +**Pedantic builds (build-only, -Werror):** + +| Name | Compiler | Config | +|------|----------|--------| +| fwtpm-pedantic-gcc | gcc | `--enable-fwtpm --enable-swtpm` | +| fwtpm-pedantic-clang | clang | `--enable-fwtpm --enable-swtpm` | +| fwtpm-pedantic-only | gcc | `--enable-fwtpm-only` | + +**Separate job: tpm2-tools (311 tests):** + +```sh +scripts/tpm2_tools_test.sh +``` + +## API Reference + +### Core (`fwtpm.h`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_Init(FWTPM_CTX* ctx)` | Initialize fwTPM context, RNG, load NV state | +| `int FWTPM_Cleanup(FWTPM_CTX* ctx)` | Save NV, free resources, zero sensitive data | +| `const char* FWTPM_GetVersionString(void)` | Return version string (for example `"0.1.0"`) | + +### Command Processor (`fwtpm_command.h`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_ProcessCommand(FWTPM_CTX* ctx, const byte* cmdBuf, int cmdSize, byte* rspBuf, int* rspSize, int locality)` | Process a raw TPM command packet and produce a response. Returns `TPM_RC_SUCCESS` on successful processing; the response buffer may contain a TPM error RC. | + +### IO Transport (`fwtpm_io.h`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_IO_SetHAL(FWTPM_CTX* ctx, FWTPM_IO_HAL* hal)` | Register custom IO transport callbacks | +| `int FWTPM_IO_Init(FWTPM_CTX* ctx)` | Initialize transport (sockets or custom HAL) | +| `void FWTPM_IO_Cleanup(FWTPM_CTX* ctx)` | Close transport and release resources | +| `int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)` | Main server loop; blocks until `ctx->running` is cleared | + +### NV Storage (`fwtpm_nv.h`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_NV_Init(FWTPM_CTX* ctx)` | Load NV state from storage or create new (generates seeds) | +| `int FWTPM_NV_Save(FWTPM_CTX* ctx)` | Save current TPM state to NV storage | +| `int FWTPM_NV_SetHAL(FWTPM_CTX* ctx, FWTPM_NV_HAL* hal)` | Register custom NV storage callbacks | + +### TIS Server (`fwtpm_tis.h`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_TIS_Init(FWTPM_CTX* ctx)` | Create shared memory region and semaphores | +| `void FWTPM_TIS_Cleanup(FWTPM_CTX* ctx)` | Unlink shared memory and semaphores | +| `int FWTPM_TIS_ServerLoop(FWTPM_CTX* ctx)` | Process TIS register accesses (blocks) | + +### TIS Client (`fwtpm_tis.h`, requires `WOLFTPM_FWTPM_HAL`) + +| Function | Description | +|----------|-------------| +| `int FWTPM_TIS_ClientConnect(FWTPM_TIS_CLIENT_CTX* client)` | Attach to fwTPM shared memory | +| `void FWTPM_TIS_ClientDisconnect(FWTPM_TIS_CLIENT_CTX* client)` | Detach from shared memory | + +## Real-world examples + +The [wolftpm-examples](https://github.com/wolfSSL/wolftpm-examples) repository holds complete fwTPM projects for real boards. Each one shows a different isolation or storage choice. + +| Board | Project | What it shows | +|-------|---------|---------------| +| STM32H5 NUCLEO-H563ZI | [STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) | fwTPM in the Cortex-M33 TrustZone secure world, internal-flash NV, UART with the mssim protocol | +| Xilinx ZCU102 (R5, lock-step) | [Xilinx/fwtpm-zcu102-r5](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zcu102-r5) | AMP: fwTPM bare-metal on the Cortex-R5 pair in lock-step, PetaLinux client on the A53 over OpenAMP RPMsg; volatile DDR NV or persistent QSPI | +| Xilinx ZC702 (A9) | [Xilinx/fwtpm-zc702-a9](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zc702-a9) | SRAM-PUF derived device-unique NV key, so no root key is stored in flash | +| SCU35 (MicroBlaze-V soft core) | [Xilinx/fwtpm-scu35-microblazev](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-scu35-microblazev) | ECC-only fwTPM that fits in about 190 KB of block RAM | +| PolarFire SoC MPFS250T | [Microchip/fwtpm-polarfire-miv](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/fwtpm-polarfire-miv) | AMP: fwTPM bare-metal on a U54 hart, isolated from Linux, TIS over shared L2-LIM memory | +| PolarFire MPF300 Splash (soft MIV) | [Microchip/miv-mpf300-splash](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/miv-mpf300-splash) | Soft Mi-V core with persistent on-die sNVM | + +The STM32H5, PolarFire SoC, and ZCU102 projects are also listed as ports in [HAL and Porting](hal-and-porting.md). + +## See Also + +- [Overview](overview.md) +- [Building](building.md) +- [HAL and Porting](hal-and-porting.md) +- [Post-Quantum Support](post-quantum.md) +- [SPDM Responder](spdm.md) diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..814ce639 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,75 @@ +# Getting Started + +wolfTPM is a portable TPM 2.0 library with a native API, a wrapper API, and a set of example applications that come ready to use after a successful build. The examples demonstrate features of a TPM 2.0 module and create RSA and ECC keys in NV storage for testing, using the handles defined in `examples/tpm_test.h`. This page covers the shortest path from a fresh checkout to a first working example. + +## Prerequisites and building wolfSSL + +wolfTPM needs wolfSSL (wolfCrypt) built with the wolfTPM options. Build and install wolfSSL first: + +```bash +git clone https://github.com/wolfSSL/wolfssl.git +cd wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +sudo ldconfig +``` + +`autogen.sh` requires automake and libtool: `sudo apt-get install automake libtool`. + +See [Building wolfTPM](building.md) for using a wolfSSL installed in a different directory. + +## Build wolfTPM + +```bash +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +./autogen.sh +./configure +make +``` + +!!! note + On any non-Windows x86_64/aarch64 host (Linux, macOS, or BSD), a bare `./configure` automatically enables the software TPM backends (swTPM and fwTPM). This lets `make check` run without any TPM hardware attached. Selecting a hardware path turns this default off: any `--enable-`, or `--enable-spi`, `--enable-i2c`, `--enable-mmio`, `--enable-devtpm`, `--enable-autodetect`, `--enable-winapi`, or `--enable-wintbs`. See [System Interfaces](system-interfaces.md). + +For hardware specific build steps, see [Supported Hardware](supported-hardware.md). + +## Run your first example + +A TPM must be reachable before you run any example. With the default build on a non-Windows x86_64/aarch64 host (Linux, macOS, or BSD), the examples talk to a software TPM over a socket, and `make` builds that TPM (`fwtpm_server`) but does not start it. In a separate terminal, start it from the wolfTPM directory: + +```sh +./src/fwtpm/fwtpm_server --clear +``` + +The `--clear` option deletes any saved NV state so you begin with a fresh TPM. Leave the server running. + +!!! note + A software TPM must be running before `caps` or any other example can connect. If you built for hardware instead, connect the TPM module and skip this step. + +The simplest example reads the TPM capabilities and searches for persistent handles: + +```sh +./examples/wrap/caps +TPM2 Get Capabilities +wolfSSL Entering wolfCrypt_Init +Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 +Found 2 persistent handles +``` + +The output shown is illustrative. It reports the manufacturer and firmware details of the TPM you connect to, so it will differ between modules and for the software TPM. + +Other examples go further. `./examples/native/native_test` calls the native `TPM2_*` APIs directly (startup, self test, random numbers, hashing, PCR operations, and more). The PKCS #7 and TLS examples require generating CSRs and signing them with a test script. See `examples/README.md` in the source tree for details. + +To use parameter encryption in the examples, pass `-aes` for AES-CFB mode or `-xor` for XOR mode. Only some TPM commands and responses support parameter encryption. + +!!! note + To run the TLS server and client on the same machine, build with `WOLFTPM_TIS_LOCK` (`--enable-tislock`) to enable concurrent access protection. + +## See Also + +- [Building wolfTPM](building.md) +- [Build Options](build-options.md) +- [Supported Hardware](supported-hardware.md) +- [System Interfaces](system-interfaces.md) diff --git a/docs/hal-io-callback.md b/docs/hal-io-callback.md new file mode 100644 index 00000000..0d1420f4 --- /dev/null +++ b/docs/hal-io-callback.md @@ -0,0 +1,145 @@ +# HAL IO Callback + +A single hardware abstraction layer (HAL) callback must be registered to handle communication to the TPM hardware. This page describes the callback, the example implementations distributed with wolfTPM, and the build options that control them. + +Examples for several platforms are provided to help with initial setup. If you use one of the built-in, system-provided hardware interfaces, `NULL` can be supplied for the HAL IO callback. + +The available system TPM interfaces are: + +* Linux `/dev/tpm0`: enabled with `WOLFTPM_LINUX_DEV` or `--enable-devtpm`. +* Windows TBS: enabled with `WOLFTPM_WINAPI` or `--enable-winapi`. +* Software TPM simulator: enabled with `WOLFTPM_SWTPM` or `--enable-swtpm`. + +If you use a HAL IO callback, it is registered on library initialization with: + +* TPM2 native API: `TPM2_Init` +* wolfTPM wrappers: `wolfTPM2_Init` + +## Example HAL Implementations + +| Platform | Example File | Build Option | +| -------- | ------------ | ------------ | +| Atmel ASF | `tpm_io_atmel.c` | `WOLFSSL_ATMEL` | +| Barebox | `tpm_io_barebox.c` | `__BAREBOX__` | +| Infineon | `tpm_io_infineon.c` | `WOLFTPM_INFINEON_TRICORE` | +| Linux | `tpm_io_linux.c` | `__linux__` | +| Microchip | `tpm_io_microchip.c` | `WOLFTPM_MICROCHIP_HARMONY` | +| QNX | `tpm_io_qnx.c` | `__QNX__` | +| ST Cube HAL | `tpm_io_st.c` | `WOLFSSL_STM32_CUBEMX` | +| wolfHAL | `tpm_io_wolfhal.c` | `WOLFTPM_WOLFHAL` | +| Xilinx | `tpm_io_xilinx.c` | `__XILINX__` | + +## wolfHAL + +Enabled with `WOLFTPM_WOLFHAL` or `--enable-wolfhal`. The wolfHAL headers must be on the include path. + +This HAL is placed last in the platform selection chain, so it is used only when no other platform macro is defined. For example, building for an STM32 target with the CubeMX headers present selects `tpm_io_st.c` instead. + +### Board definitions + +wolfTPM does not ship board definitions. `tpm_io_wolfhal.c` includes `"board.h"`, which the application provides on its include path. A wolfHAL project already has one, so in most cases only the TPM-specific entries below need to be added to it. + +For SPI: + +| Macro | Type | Description | +| ----- | ---- | ----------- | +| `BOARD_SPI_DEV` | `whal_Spi*` | SPI instance the TPM is connected to | +| `BOARD_SPI_COM_CFG` | `whal_Spi_ComCfg*` | SPI session parameters | +| `BOARD_GPIO_DEV` | `whal_Gpio*` | GPIO instance driving chip select | +| `BOARD_CS_PIN` | pin number | Chip select pin, driven active low | + +For I2C (also requires `WOLFTPM_ADV_IO`, which `--enable-i2c` sets): + +| Macro | Type | Description | +| ----- | ---- | ----------- | +| `BOARD_I2C_DEV` | `whal_I2c*` | I2C instance the TPM is connected to | +| `BOARD_I2C_COM_CFG` | `whal_I2c_ComCfg*` | I2C session parameters, including the TPM target address | + +The TPM target address goes in the `addr` field of `BOARD_I2C_COM_CFG`. Most TPM 2.0 I2C parts use `0x2e`. The `TPM2_I2C_ADDR` macro that the other I2C HALs use has no effect here, so defining it is a compile-time error. + +A TPM 2.0 I2C part takes roughly 80 us to wake and NAKs until it is ready, so each transfer is retried up to `TPM_I2C_TRIES` times (default 10). Define `TPM_I2C_TRIES` to override this. + +A missing entry is reported at compile time, naming the macro that is required. Only the macros needed by the selected bus are checked. + +Example additions to an existing wolfHAL `board.h`: + +```c +/* TPM on SPI1, chip select on PA15 */ +extern whal_Spi_ComCfg g_tpmSpiComCfg; +#define BOARD_SPI_COM_CFG (&g_tpmSpiComCfg) +#define BOARD_CS_PIN 15 +``` + +For I2C, where the session config carries the TPM address: + +```c +/* board.c */ +whal_I2c_ComCfg g_tpmI2cComCfg = { + .freq = 400000, /* Hz */ + .addr = 0x2e, /* TPM target address */ + .addrSz = 7, /* bits */ +}; + +/* board.h */ +extern whal_I2c_ComCfg g_tpmI2cComCfg; +#define BOARD_I2C_COM_CFG (&g_tpmI2cComCfg) +``` + +## HAL IO Callback Function + +The prototypes for the HAL callback function: + +```c +#ifdef WOLFTPM_ADV_IO +typedef int (*TPM2HalIoCb)(struct TPM2_CTX*, INT32 isRead, UINT32 addr, + BYTE* xferBuf, UINT16 xferSz, void* userCtx); +#else +typedef int (*TPM2HalIoCb)(struct TPM2_CTX*, const BYTE* txBuf, BYTE* rxBuf, + UINT16 xferSz, void* userCtx); +#endif +``` + +Example function definitions: + +```c +#ifdef WOLFTPM_ADV_IO +int TPM2_IoCb(TPM2_CTX*, int isRead, word32 addr, byte* buf, word16 size, + void* userCtx); +#else +int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, + word16 xferSz, void* userCtx); +#endif +``` + +## Additional Build Options + +* `WOLFTPM_CHECK_WAIT_STATE`: Enables checking of the wait state during a SPI transaction. Most TPM 2.0 chips require this and typically need only 0 to 2 wait cycles depending on the command. Only the Infineon TPMs guarantee no wait states. +* `WOLFTPM_ADV_IO`: Enables advanced IO callback mode, which includes the TIS register and a read/write flag. This is required for I2C, but can be used with SPI also. +* `WOLFTPM_DEBUG_IO`: Enables logging of the IO (if using the example HAL). +* `WOLFTPM_HAL_RESET`: Optional TPM hardware reset (nRST) control in the example HAL (`--enable-hal-reset`). On Linux, `TPM2_IoCb_Reset(&dev->ctx, userCtx)` pulses nRST (active low) through the GPIO char device (raw GPIO v2 uAPI, no libgpiod). + +## TPM Reset (nRST) HAL Macros + +These apply when `WOLFTPM_HAL_RESET` is set. + +* `WOLFTPM_RESET_GPIOCHIP`: GPIO char device. Default: `/dev/gpiochip0`. +* `WOLFTPM_RESET_LINE`: GPIO line wired to nRST. Default: ST33 uses `24` (GPIO24, Pi pin 18), Nuvoton uses `4` (GPIO4). Also settable with `--enable-hal-reset=`. +* `WOLFTPM_RESET_HOLD_US` and `WOLFTPM_RESET_SETTLE_US`: reset hold time and post-reset settle time in microseconds. Defaults: `300000` and `1000000`. + +## Additional Compiler Macros + +* `TPM2_SPI_DEV_PATH`: The device string to be opened by the Linux IO callback. Default: `"/dev/spidev0."`. +* `TPM2_SPI_DEV_CS`: The chip select number string to use. Default: `"0"`. + +These can be set during configure: + +```sh +./configure CPPFLAGS="-DTPM2_SPI_DEV_PATH=\"/dev/spidev0.\" -DTPM2_SPI_DEV_CS=\"0\"" +``` + +Autodetect uses `TPM2_SPI_DEV_PATH[0..4]` for the searched device paths. + +## See Also + +* [Supported Hardware](supported-hardware.md) +* [TPM 2.0 Overview](tpm2-overview.md) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..29ec8a40 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,74 @@ +# wolfTPM + +Portable TPM 2.0 project designed for embedded use. This manual covers building wolfTPM, configuring it for your hardware, using the native and wrapper APIs, and running the firmware TPM (fwTPM) and the post-quantum and SPDM features. + +## Project Features + +* This implementation provides all TPM 2.0 API's in compliance with the specification. +* Wrappers provided to simplify Key Generation/Loading, RSA encrypt/decrypt, ECC sign/verify, ECDH, NV, Hashing/HACM, AES, Sealing/Unsealing, Attestation, PCR Extend/Quote and Secure Root of Trust. +* Any TPM 2.0 compliant module is supported. Tested modules include Infineon SLB9670, SLB9672, SLB9673, STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI, ST33TPHF2XI2C, Microchip ATTPM20, Nations Technologies/NSING Z32H330, NS350, Nuvoton NPCT650, NPCT750, and SealSQ QVault TPM (first TPM with post-quantum ML-DSA/ML-KEM in silicon). +* wolfTPM uses the TPM Interface Specification (TIS) to communicate either over SPI, or using a memory mapped I/O range. +* On Linux, wolfTPM can auto-detect between the kernel TPM driver (`/dev/tpmX`) and direct SPI access at runtime. Enable it with `--enable-autodetect` (a bare `./configure` on a common host defaults to the software TPM instead). +* wolfTPM can also use the Linux TPM kernel interface (`/dev/tpmX`) to talk with any physical TPM on SPI, I2C and even LPC bus. +* Platform support for Raspberry Pi (Linux), MMIO, STM32 with CubeMX, Atmel ASF, Xilinx, QNX, Infineon TriCore, wolfHAL and Barebox. +* The design allows for easy portability to different platforms: + * Native C code designed for embedded use. + * Single IO callback for hardware SPI interface. + * No external dependencies. + * Compact code size and minimal memory use. +* Includes example code for: + * Most TPM2 native API's + * All TPM2 wrapper API's + * PKCS 7 + * Certificate Signing Request (CSR) + * TLS Client + * TLS Server + * Use of the TPM's Non-volatile memory + * Attestation (activate and make credential) + * Benchmarking TPM algorithms and TLS + * Key Generation (primary, RSA/ECC and symmetric), loading and storing to flash (NV memory) + * Sealing and Unsealing data with an RSA key or externally signed policy. + * Time signed or set + * PCR read/reset + * GPIO configure, read and write. + * Endorsement Key/Cert retrieval and validation. +* Parameter encryption support using AES-CFB or XOR. +* Support for salted unbound authenticated sessions. +* Support for HMAC Sessions. +* Support for reading Endorsement certificates (EK Credential Profile). +* Includes a portable firmware TPM 2.0 implementation (fwTPM, also known as fTPM / swtpm) for embedded platforms without a discrete TPM chip. See [fwTPM Overview](fwtpm/overview.md). +* **Post-quantum cryptography support** via TPM 2.0 Library Specification v1.85: ML-DSA (FIPS 204) signing and ML-KEM (FIPS 203) key encapsulation, enabled with `--enable-v185` (full v1.85) or the leaner `--enable-pqc` (ML-DSA / ML-KEM only), with per-operation trimming via `--enable-mldsa`/`--enable-mlkem`. Auto-detected when `--enable-fwtpm` is built against a wolfCrypt that has ML-DSA + ML-KEM. Both the client library and the fwTPM server implement the eight new v1.85 PQC commands. See [Post-Quantum Cryptography](post-quantum.md). +* **SPDM attestation support** (DMTF DSP0274) over the TCG SPDM-over-TPM binding, with a TCG certificate handshake and a DSP0274 pre-shared-key (PSK) handshake, enabled with `--enable-spdm`. The fwTPM server includes an SPDM 1.3 responder so the stack can be exercised end-to-end in CI without discrete silicon. See [SPDM Attestation](spdm.md). + +## Standards and Features + +| Area | Status | Enable flag | Page | +| --- | --- | --- | --- | +| TPM 2.0 specification | Native API for the TPM 2.0 command set, with wrappers for common operations | Always built | [API Reference](api-reference.md) | +| TCG TPM 2.0 Library Specification revision 1.85 | Post-quantum commands implemented in the client library and fwTPM server | `--enable-v185` (full v1.85) | [Build Options](build-options.md) | +| Post-quantum: ML-DSA (FIPS 204) and ML-KEM (FIPS 203) | Client library and fwTPM server; SealSQ QVault in silicon | `--enable-pqc` (ML-DSA / ML-KEM only), `--enable-mldsa`, `--enable-mlkem` | [Post-Quantum Cryptography](post-quantum.md) | +| SPDM attestation (TCG certificate handshake and DSP0274 PSK handshake) | Client library, plus an SPDM 1.3 responder in fwTPM | `--enable-spdm` | [SPDM Attestation](spdm.md) | +| Parameter encryption (AES-CFB or XOR) | Supported, along with salted unbound and HMAC sessions | Set up per session at run time | [API Reference](api-reference.md) | +| EK Credential Profile | Endorsement certificate reading (`examples/endorsement/get_ek_certs`) | Always built | [Getting Started](getting-started.md) | +| Device Identity (IAK / IDevID) | Tested with the ST33KTPM; default keys are ECDSA SECP384R1 with SHA2-384 in NV | `WOLFTPM_MFG_IDENTITY` | [Supported Hardware](supported-hardware.md) | +| Firmware TPM (fwTPM / fTPM / swtpm) | Portable TPM 2.0 server built on wolfCrypt | `--enable-fwtpm` | [fwTPM Overview](fwtpm/overview.md) | + +## Documentation map + +* [Getting Started](getting-started.md): first steps after installing. +* [Building](building.md): build wolfTPM from source. +* [Build Options](build-options.md): configure flags and the defines they set. +* [Supported Hardware](supported-hardware.md): tested TPM modules and platforms. +* [TPM 2.0 Overview](tpm2-overview.md): hierarchies, PCRs and device identification. +* [Project Structure](project-structure.md): source tree layout. +* [Post-Quantum Cryptography](post-quantum.md): ML-DSA and ML-KEM support. +* [SPDM Attestation](spdm.md): SPDM handshakes and the responder. +* [fwTPM Overview](fwtpm/overview.md): the firmware TPM server. +* [API Reference](api-reference.md): native and wrapper APIs. + +## See Also + +* [Getting Started](getting-started.md) +* [Build Options](build-options.md) +* [Supported Hardware](supported-hardware.md) +* [fwTPM Overview](fwtpm/overview.md) diff --git a/docs/ja/api-reference.md b/docs/ja/api-reference.md new file mode 100644 index 00000000..5d18e76a --- /dev/null +++ b/docs/ja/api-reference.md @@ -0,0 +1,31 @@ +# API リファレンス + +wolfTPM は 3 つのレイヤーのヘッダーを公開しています。このページでは、どのヘッダーから使い始めるべきかを説明します。関数単位のリファレンスはヘッダーのコメントから Doxygen で生成され、このセクションの後続ページに掲載されます。 + +## ラッパー API + +ラッパー API は `wolftpm/tpm2_wrap.h` で宣言されています。すべての関数名は `wolfTPM2_*` です。コマンドのシーケンス制御、セッション処理、パラメータ暗号化、キー Blob の管理を少数の呼び出しの背後に隠蔽しており、アプリケーションではこの API から使い始めることを推奨します。鍵の作成、ロード、署名、シーリング、NV ストレージについては [鍵管理](key-management.md) を、クォートと PCR の使い方については [アテステーション](attestation.md) を参照してください。 + +## ネイティブ API + +ネイティブ API は `wolftpm/tpm2.h` で宣言されています。TPM 2.0 のコマンドごとに 1 つの関数として、生の `TPM2_*` コマンドを提供し、TCG 仕様の構造体と定数も併せて定義しています。コマンドパラメータを直接制御したい場合や、ラッパーが対応していないコマンドが必要な場合に使用します。コマンド引数の構築、セッションおよび認可の処理は、すべて自分で行います。 + +## HAL IO + +`hal/tpm_io.h` は、wolfTPM と TPM の間でバイト列をやり取りするためのハードウェア抽象化レイヤーを宣言しています。wolfTPM を新しいボードやバスに移植する際に読むべきヘッダーです。[HAL IO コールバック](hal-io-callback.md) を参照してください。 + +## 生成されるリファレンス + +関数単位の完全なリファレンスはヘッダーの Doxygen コメントから生成され、このセクションの次のページに掲載されます。 + +- TPM2 API +- TPM2 Wrapper API +- TPM2 Header File +- TPM2 Wrapper Header File +- TPM2 HAL IO + +## 関連項目 + +- [鍵管理](key-management.md) +- [アテステーション](attestation.md) +- [HAL IO コールバック](hal-io-callback.md) diff --git a/docs/ja/attestation.md b/docs/ja/attestation.md new file mode 100644 index 00000000..b599c8ad --- /dev/null +++ b/docs/ja/attestation.md @@ -0,0 +1,465 @@ +# アテステーション + +wolfTPM には、ローカルアテステーションとリモートアテステーション、TPM 署名付きタイムスタンプ、エンドースメント鍵証明書、デバイス ID 鍵のサンプルが含まれています。このページでは、リモートアテステーションのチャレンジの流れ、PCR Quote、署名付きタイムスタンプ、EK 証明書の検証、製造元の ID 鍵について説明します。 + +## リモートアテステーションの概要 + +リモートアテステーションとは、クライアントがアテステーションサーバーに証拠を提示し、サーバーがクライアントが既知の状態にあることを確認する仕組みです。これを成立させるには、まずクライアントとサーバーの間で信頼を確立する必要があります。この信頼確立には、標準の TPM 2.0 コマンドである `TPM2_MakeCredential` と `TPM2_ActivateCredential` を使用します。 + +1. クライアントは、TPM 2.0 のプライマリアテステーション鍵 (PAK) と、Quote に署名するアテステーション鍵 (AK) の公開部分をサーバーに送ります。 +2. `MakeCredential` は PAK の公開部分を使ってチャレンジ(シークレット)を暗号化します。通常、チャレンジは AK の公開部分のダイジェストです。PAK と AK の秘密部分をロードできる TPM だけが復号できます。どちらの鍵も `fixedTPM` 属性を持つため、これらをロードできるのは鍵を作成した TPM だけです。 +3. サーバーはチャレンジをクライアントに送ります。 +4. `ActivateCredential` は、ロード済みの PAK と AK を使ってチャレンジを復号し、シークレットを復元します。その後、クライアントはサーバーに応答できます。 + +これにより、クライアントが想定どおりの TPM ID とアテステーション鍵を保持していることをサーバーに証明できます。 + +!!! note + チャレンジとレスポンスの交換に使うトランスポートは実装依存であるため、開発者が選択します。選択肢の一つは、wolfSSL を使った TLS 1.3 のクライアントサーバー接続です。 + +この流れで使用するサンプルは次のとおりです。 + +| プログラム | 役割 | +| --- | --- | +| `./examples/attestation/make_credential` | サーバーがリモートアテステーションのチャレンジを作成するために使用します。 | +| `./examples/attestation/activate_credential` | クライアントがチャレンジを復号して応答するために使用します。 | +| `./examples/attestation/certify` | 指定した名前のオブジェクトが TPM にロードされていることを証明(アテスト)します。 | +| `./examples/keygen/create_primary` | プライマリ鍵 (PK) とアテステーション鍵 (AK) を作成します。 | + +これらのサンプルはすべて `-eh` を受け付けます。これを指定すると、エンドースメント鍵と、エンドースメント階層配下のアテステーション鍵を使用します。EK の秘密部分が TPM の外に出ることはなく、EK は TPM チップごとに固有です。そのため、EK 宛てに暗号化したチャレンジは、その TPM だけが開くことができます。欠点はプライバシーです。EK は TPM を識別するため、アテステーション対象のホストの身元が常に判明します。サンプルは、SRK 配下の AK と EK 配下の AK の両方に対応しており、どちらを使うかは開発者が選択します。 + +## アテステーション用の鍵の作成 + +`keygen` サンプルを使って、TPM 2.0 のアテステーション鍵と、プライマリアテステーション鍵 (PAK) として機能するプライマリストレージ鍵を作成します。 + +```sh +$ ./examples/keygen/keygen -rsa +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: RSA + Template: AIK + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +RSA AIK template +Creating new RSA key... +New key created and loaded (pub 280, priv 222 bytes) +Wrote 508 bytes to keyblob.bin +Wrote 288 bytes to srk.pub +Wrote AK Name digest +``` + +ここで書き出されるファイル(`keyblob.bin`、`srk.pub`、AK の名前ダイジェスト)は、次の 2 つのステップの入力になります。`keygen` の詳細は[鍵管理](key-management.md)を参照してください。 + +## MakeCredential と ActivateCredential + +### Make credential + +アテステーションサーバーは `make_credential` を使ってチャレンジを生成します。シークレットは 32 バイトの乱数で、アテステーション方式によっては対称鍵のシードとして利用できます。 + +```sh +$ ./examples/attestation/make_credential +Using public key from SRK to create the challenge +Demo how to create a credential challenge for remote attestation +Credential will be stored in cred.blob +wolfTPM2_Init: success +Reading 288 bytes from srk.pub +Reading the private part of the key +Public key for encryption loaded +Read AK Name digest success +TPM2_MakeCredential success +Wrote credential blob and secret to cred.blob, 648 bytes +``` + +PAK と AK の公開部分をクライアントとサーバーの間で転送する処理は、このサンプルには含まれません。 + +### Activate credential + +クライアントは `activate_credential` を使ってチャレンジを復号します。シークレットは平文で得られ、アテステーションサーバーに送信できます。 + +```sh +$ ./examples/attestation/activate_credential +Using default values +Demo how to create a credential blob for remote attestation +wolfTPM2_Init: success +Credential will be read from cred.blob +Loading SRK: Storage 0x81000200 (282 bytes) +SRK loaded +Reading 508 bytes from keyblob.bin +Reading the private part of the key +AK loaded at 0x80000001 +Read credential blob and secret from cred.blob, 648 bytes +TPM2_ActivateCredential success +``` + +シークレットを含むレスポンス(平文または対称鍵のシードとして)をサーバーに返送する処理も、このサンプルには含まれません。 + +### Certify + +`certify` サンプルは `TPM2_Certify` を使って、別の鍵に対するアテステーション情報に署名します。これにより、特定の名前を持つオブジェクトが TPM にロードされていることを証明できます。一般的な用途は、制限付き IAK に IDevID のアテステーション情報へ署名させることです。 + +`create_primary` は、RSA または ECC の IDevID 鍵と IAK 鍵を作成できます。これらはエンドースメント階層の配下に作成され、プライマリ鍵のポリシーについては TCG の「TPM 2.0 Keys for Device Identity and Attestation」仕様に従います。IDevID 鍵は、外部向けの制限なし署名に使用します。IAK は内部アテステーションに使用します。ここでは IAK が IDevID を証明します。 + +```sh +% ./examples/keygen/create_primary -rsa -eh -iak -keep +TPM2.0 Primary Key generation example + Algorithm: RSA + Unique: IAK + Store Handle: 0x00000000 + Use Parameter Encryption: NULL +Creating new RSA primary key... +Create Primary Handle: 0x80000000 + +% ./examples/keygen/create_primary -rsa -eh -idevid -keep +TPM2.0 Primary Key generation example + Algorithm: RSA + Unique: IDEVID + Store Handle: 0x00000000 + Use Parameter Encryption: NULL +Creating new RSA primary key... +Create Primary Handle: 0x80000001 + +% ./examples/attestation/certify -rsa -certify=0x80000001 -signer=0x80000000 +Certify 0x80000001 with 0x80000000 to generate TPM-signed attestation info +EK Policy Session: Handle 0x3000000 +TPM2_Certify complete +Certify Info 172 +RSA Signature: 256 + +% ./examples/management/flush 0x80000001 +Preparing to free TPM2.0 Resources +Freeing 80000001 object + +% ./examples/management/flush 0x80000000 +Preparing to free TPM2.0 Resources +Freeing 80000000 object +``` + +ECC の場合は、同じ手順で `-rsa` を `-ecc` に置き換えてください。 + +## Quote と PCR アテステーション + +`examples/pcr/` フォルダには、Platform Configuration Register (PCR) を操作するツールと、TPM 2.0 Quote を生成するツールがあります。より詳細なログを出力するには、`./configure --enable-debug` でビルドしてください。 + +| プログラム | 目的 | +| --- | --- | +| `./examples/pcr/reset` | PCR の内容をクリアします(制約あり、下記参照)。 | +| `./examples/pcr/extend` | extend 操作で PCR の内容を更新します。 | +| `./examples/pcr/quote` | PCR ダイジェストと TPM 署名を含む TPM 2.0 Quote を生成します。 | +| `./examples/pcr/allocate` | TPM が実装し、割り当て済みの PCR バンクを報告し、割り当てを変更します。 | +| `./examples/pcr/demo.sh` | 上記のツールを実演するスクリプトです。 | +| `./examples/pcr/demo-quote-zip.sh` | システムファイルを計測し、その計測結果に対する TPM 署名付きの証明を生成するスクリプトです。 | + +### PCR の基本 + +PCR を変更できるのは extend 操作だけです。電源投入時に、TPM はすべての PCR をデフォルト値(PCR によって全ビット 0 または全ビット 1)にリセットします。同じ PCR 値に到達できるのは、同じダイジェストを同じ順序で extend した場合だけです。A、B、C の順に extend した結果は C、B、A の順とは異なりますが、どちらの順序も再現可能です。 + +`TPM2_Extend` は SHA-1 または SHA-256 のハッシュ演算を使って、現在の PCR 値と新しいダイジェストを結合します。 + +すべての PCR は extend できますが、実行時にリセットできるのは一部だけです。 + +* PCR0 から 15 はブート時にリセットされ、再度クリアできるのは再起動のみです。 +* PCR16 はデバッグ用です。上記のすべてのツールがデフォルトでこれを使用し、テストに安全に使えます。 +* PCR17 から 22 は Dynamic Root of Trust Measurement (DRTM) 用に予約されています。 + +リセットのローカリティは TCG PC Client に従います。PCR16 と 23 はローカリティ 0 から 3、PCR20 から 22 はローカリティ 2 から 4、PCR17 から 19 はローカリティ 4 でリセットされます。ローカリティの選択には `-loc=n` を使用します(`wolfTPM2_SetLocality` を参照)。これは内蔵の TIS/SPI ドライバーと fwTPM に適用されます。 + +### バンクの割り当て + +TPM はハッシュアルゴリズムごとに別々の PCR セットを保持しており、これをバンクと呼びます。どのバンクが存在するかはシリコンで固定されていますが、どのバンクを割り当てるかは `TPM2_PCR_Allocate` でプロビジョニングされ、変更できます。Infineon SLB9672 以降を含む多くのパーツでは、一度に 1 つのバンクしか割り当てられないため、SHA-256 から SHA-384 に移行するには SHA-256 の割り当てを解除する必要があります。SHA-1 は非推奨であり、現行のパーツでは割り当てられません。 + +!!! warning + 指定した選択内容が割り当てを置き換えます。リクエストで指定されなかったバンクは、割り当てが解除されます。このコマンドにはプラットフォーム階層が必要ですが、OS の下ではプラットフォームファームウェアが通常これを無効にしています(指定した認可に関係なく、TPM は `TPM_RC_HIERARCHY` を返します)。プラットフォーム認証が空のパスワードではないセッションを指定して、`wolfTPM2_AllocatePCRBanks_ex` を使用してください。変更は次の TPM リセット時に有効になるため、TPM の電源を入れ直すかシミュレーターを再起動してから、バンクを再度読み取ってください。バンクを変更すると、すべての `PolicyPCR` ダイジェストが無効になり、PCR 値にシーリングされたデータは unseal できなくなります。 + +### Quote + +`TPM2_Quote` は、PCR ダイジェストを TCG 定義の `TPMS_ATTEST` 構造体に格納し、TPM 署名を付与します。署名は TPM だけが使用できるアテステーション ID 鍵 (AIK) で生成されるため、Quote と PCR ダイジェストの出所が保証されます。 + +### ツールの使い方 + +```sh +$ ./examples/pcr/reset -? +Incorrect arguments +Expected usage: +./examples/pcr/reset [pcr] [-loc=n] +* pcr is a PCR index between 0-23 (default 16) +* -loc=n switch to TPM locality n (0-4) before reset + (PCR 17-19 need locality 4; 20-22 need locality 2-4; + enforced by the fwTPM and by discrete TPMs like the ST33) +Demo usage without parameters, resets PCR16. +``` + +```sh +$ ./examples/pcr/extend -? +Incorrect arguments +Expected usage: +./examples/pcr/extend [pcr] [filename] +* pcr is a PCR index between 0-23 (default 16) +* filename points to file(data) to measure + If wolfTPM is built with --disable-wolfcrypt the file + must contain SHA256 digest ready for extend operation. + Otherwise, the extend tool computes the hash using wolfcrypt. +Demo usage without parameters, extends PCR16 with known hash. +``` + +```sh +$ ./examples/pcr/quote -? +Incorrect arguments +Expected usage: +./examples/pcr/quote [pcr] [filename] +* pcr is a PCR index between 0-23 (default 16) +* filename for saving the TPMS_ATTEST structure to a file +Demo usage without parameters, generates quote over PCR16 and +saves the output TPMS_ATTEST structure to "quote.blob" file. +``` + +```sh +$ ./examples/pcr/allocate -? +Expected usage: +./examples/pcr/allocate [-sha1] [-sha256] [-sha384] [-sha512] + [-restore] +* no algorithm flags: report the current allocation and exit +* -shaN: include that bank in the new allocation (repeatable) +* -restore: put the original allocation back before exiting +Demo usage without parameters, reports the PCR banks. + +WARNING: the algorithm flags REPLACE the allocation. Banks not +named are deallocated, every PolicyPCR digest changes, and blobs +sealed to PCR values become unsealable. Many TPMs support only +one active bank at a time. + +The new allocation takes effect at the next TPM reset, so power +cycle the TPM (or restart the simulator) and re-run to confirm. +``` + +フラグを指定しない場合、`allocate` は TPM が持つバンクを報告します。一覧は TPM 自身の `TPM_CAP_PCRS` レスポンスから取得されるため、このビルドで名前を持たないバンクはハッシュアルゴリズム ID として表示され、`pcrSelect` は生のビットマップになります。 + +```sh +$ ./examples/pcr/allocate +PCR banks: + Bank Allocated pcrSelect + SHA-256 yes FFFFFF + SHA-384 yes FFFFFF + SHA-1 no 000000 +``` + +SHA-384 のみの割り当てに移行し、リセット後にそれを確認するには、次のようにします。 + +```sh +$ ./examples/pcr/allocate -sha384 +TPM reported: allocationSuccess YES, maxPCR 24, sizeNeeded 1152, sizeAvailable 4608 +PCR allocation staged. It takes effect at the next TPM reset +(Startup(CLEAR) after a _TPM_Init) - power cycle the TPM, or +restart the simulator process, then re-run to confirm. + +$ ./examples/pcr/allocate +PCR banks: + Bank Allocated pcrSelect + SHA-256 no 000000 + SHA-384 yes FFFFFF + SHA-1 no 000000 +``` + +1 つのバンクしか有効にできない TPM では、2 つを要求すると `TPM_RC_PCR` で拒否されます。コマンドは受け付けるものの空き容量が足りない TPM は `allocationSuccess = NO` を報告し、ラッパーはこれを、`sizeNeeded` が `sizeAvailable` より大きい `BUFFER_E` として返します。どちらのケースも wolfTPM のエラーではありません。 + +スクリプトでは `-restore` を使うと、実行後にバンクを元の状態に戻せます。これは起動時に読み取った選択内容を、ビットマップも含めて正確に再適用するため、一部だけ選択されていたバンクも一部だけ選択された状態で元に戻ります。 + +### 典型的なデモ出力 + +PCR のサンプルはすべて引数なしで実行できます。次は `./examples/pcr/demo.sh` の出力です。 + +```sh +$ ./examples/pcr/reset +Demo how to reset a PCR (clear the PCR value) +wolfTPM2_Init: success +Trying to reset PCR16... +TPM2_PCR_Reset success +PCR16 digest: + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ +``` + +PCR16 はすべて 0 に戻るため、以降の PCR ダイジェストを予測できます。これはブート直後の PCR7 に似ていますが、PCR16 なら再起動せずにテストできます。 + +```sh +$ ./examples/pcr/extend +Demo how to extend data into a PCR (TPM2.0 measurement) +wolfTPM2_Init: success +Hash to be used for measurement: +000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +TPM2_PCR_Extend success +PCR16 digest: + bb 22 75 c4 9f 28 ad 52 ca e6 d5 5e 34 a9 74 a5 | ."u..(.R...^4.t. + 8c 7a 3b a2 6f 97 6e 8e cb be 7a 53 69 18 dc 73 | .z;.o.n...zSi..s +``` + +新しい値は、古い PCR の内容(すべて 0)と、指定した SHA-256 ダイジェストから算出されます。`extend` の前に `reset` を実行すれば、常に同じ値になります。独自のデータを使うには、最初に PCR インデックス(16 を推奨)、2 番目にファイルを渡してください。 + +```sh +$ ./examples/pcr/quote +Demo of generating signed PCR measurement (TPM2.0 Quote) +wolfTPM2_Init: success +TPM2_CreatePrimary: 0x80000000 (314 bytes) +wolfTPM2_CreateEK: Endorsement 0x80000000 (314 bytes) +TPM2_CreatePrimary: 0x80000001 (282 bytes) +wolfTPM2_CreateSRK: Storage 0x80000001 (282 bytes) +TPM2_StartAuthSession: sessionHandle 0x3000000 +TPM2_Create key: pub 280, priv 212 +TPM2_Load Key Handle 0x80000002 +wolfTPM2_CreateAndLoadAIK: AIK 0x80000002 (280 bytes) +TPM2_Quote: success +TPM with signature attests (type 0x8018): + TPM signed 1 count of PCRs + PCR digest: + c7 d4 27 2a 57 97 7f 66 1f bd 79 30 0a 1b bf ff | ..'*W..f..y0.... + 2e 43 57 cc 44 14 7a 82 11 aa 76 3f 9f 1b 3a 6c | .CW.D.z...v?..:l + TPM generated signature: + 28 dc da 76 33 35 a5 85 2a 0c 0b e8 25 d0 f8 8d | (..v35..*...%... + 1f ce c3 3b 71 64 ed 54 e6 4d 82 af f3 83 18 8e | ...;qd.T.M...... + (remaining signature bytes omitted) +``` + +TPM が Quote に署名する前に、サンプルはエンドースメント鍵 (EK) を作成します。EK は他の鍵のプライマリ鍵として機能します。続いてストレージ鍵 (SRK) を作成し、その配下に、Quote 構造体に署名するアテステーション ID 鍵 (AIK) を作成します。 + +### システムファイルの計測(ローカルアテステーション) + +システム管理者が、ユーザーのシステム上の `zip` ツールが本物で改ざんされていないことを確認したいとします。管理者は PCR16 をリセットし、バイナリのハッシュで extend し、後の比較の基準となる Quote を生成します。これが `./examples/pcr/demo-quote-zip.sh` の処理です。 + +```sh +$ ./examples/pcr/reset 16 +... +Trying to reset PCR16... +TPM2_PCR_Reset success +... +``` + +`extend` ツールは `/usr/bin/zip` を wolfCrypt (SHA-256) でハッシュし、wolfTPM が PCR16 に対して `TPM2_PCR_Extend` を発行します。 + +```sh +$ ./examples/pcr/extend 16 /usr/bin/zip +... +TPM2_PCR_Extend success +PCR16 digest: + 2b bd 54 ae 08 5b 59 ef 90 42 d5 ca 5d df b5 b5 | +.T..[Y..B..]... + 74 3a 26 76 d4 39 37 eb b0 53 f5 82 67 6f b4 aa | t:&v.97..S..go.. +``` + +続いて管理者は、PCR16 の計測結果の証明として Quote を作成します。 + +```sh +$ ./examples/pcr/quote 16 zip.quote +... +TPM2_Quote: success +TPM with signature attests (type 0x8018): + TPM signed 1 count of PCRs +... +``` + +Quote はバイナリファイル `zip.quote` に保存されます。`TPMS_ATTEST` 構造体にはクロックと時刻の情報も含まれます。時刻のアテステーションについては次のセクションを参照してください。 + +### 暗号化した qualifying data を使う Quote + +Quote に指定する qualifying data は、パラメータ暗号化で保護できます。[サンプルの概要](examples-overview.md)を参照してください。 + +## 署名付きタイムスタンプ (GetTime) + +`signed_timestamp` サンプルは、アテステーション ID 鍵 (AIK) を作成し、それを使って TPM 署名付きのタイムスタンプを生成します。このタイムスタンプは、現在のシステム稼働時間を保護して報告するために利用できます。 + +```sh +./examples/timestamp/signed_timestamp +``` + +このサンプルは、`authSession`(認可セッション)と `policySession`(ポリシー認可)を使ってエンドースメント階層を有効にします。AIK の作成にはこれが必要です。その後、AIK がネイティブ API 経由で `TPM2_GetTime` コマンドを発行し、TPM が生成して署名したタイムスタンプを返します。 + +`clock_set` サンプルは TPM2 のクロックを進めます。 + +```sh +./examples/timestamp/clock_set [time] +``` + +## エンドースメント鍵証明書 + +TPM の製造元は、TPM 鍵に基づくエンドースメント証明書をプロビジョニングします。TCG EK Credential Profile は、これらを TCG の NV インデックス範囲 (`TPM_20_TCG_NV_SPACE`) に格納する方法を定義しています。`get_ek_certs` サンプルは、そこに格納された EK 証明書を列挙して検証し、署名に使用できるプライマリ EK ハンドルを作成します。`verify_ek_cert` サンプルは、単一の EK 証明書を信頼済み CA のリストに対して検証します。一部のルート CA と中間 CA は `trusted_certs.h` にロードされています。 + +```sh +./examples/endorsement/get_ek_certs +./examples/endorsement/verify_ek_cert +``` + +### サンプルの詳細 + +1. `wolfTPM2_GetHandles` と `TPM_20_TCG_NV_SPACE` で、TCG NV 範囲内のハンドルを取得します。 +2. `wolfTPM2_NVReadPublic` で公開 NV 情報を読み取り、証明書のサイズを取得します。 +3. `wolfTPM2_NVReadAuth` で NV インデックスから NV データ(証明書の DER/ASN.1)を読み取ります。 +4. `wolfTPM2_GetKeyTemplate_EKIndex` または `wolfTPM2_GetKeyTemplate_EK` で、NV インデックスに対応する EK の公開テンプレートを取得します。 +5. `wolfTPM2_CreatePrimaryKey` で、公開テンプレートと `TPM_RH_ENDORSEMENT` 階層を使ってプライマリエンドースメント鍵を作成します。 +6. `wc_ParseCert` で ASN.1/DER 証明書を解析し、発行者、シリアル番号などのフィールドを取得します。 +7. CA 発行者証明書の URI は `extAuthInfoCaIssuer` にあります。 +8. 証明書の公開鍵をインポートし、プライマリ EK の公開 unique 領域と比較します。 +9. wolfSSL Certificate Manager で EK 証明書を検証します。`wolfSSL_CertManagerLoadCABuffer` で信頼済み証明書をロードし、`wolfSSL_CertManagerVerifyBuffer` で検証します。 +10. 必要に応じて、`wc_DerToPem` で PEM に変換してエクスポートします。 + +### 証明書チェーンの例 + +Infineon SLB9672。証明書は次の URL からダウンロードできます(xxx は 3 桁の CA 番号に置き換えてください)。 + +* `https://pki.infineon.com/OptigaRsaMfrCAxxx/OptigaRsaMfrCAxxx.crt` +* `https://pki.infineon.com/OptigaEccMfrCAxxx/OptigaEccMfrCAxxx.crt` + +例: + +* Infineon OPTIGA(TM) RSA Root CA 2、続いて Infineon OPTIGA(TM) TPM 2.0 RSA CA 059 +* Infineon OPTIGA(TM) ECC Root CA 2、続いて Infineon OPTIGA(TM) TPM 2.0 ECC CA 059 + +STMicro ST33KTPM: + +* STSAFE RSA root CA 02 (`http://sw-center.st.com/STSAFE/STSAFERsaRootCA02.crt`)、続いて STSAFE-TPM RSA intermediate CA 10 (`http://sw-center.st.com/STSAFE/stsafetpmrsaint10.crt`) +* STSAFE ECC root CA 02 (`http://sw-center.st.com/STSAFE/STSAFEEccRootCA02.crt`)、続いて STSAFE-TPM ECC intermediate CA 10 (`http://sw-center.st.com/STSAFE/stsafetpmeccint10.crt`) + +ST33KTPM での出力例(証明書の 16 進ダンプは省略しています)。 + +``` +$ ./examples/endorsement/verify_ek_cert +Endorsement Certificate Verify +TPM2: Caps 0x30000415, Did 0x0004, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +TPM2_NV_ReadPublic: Sz 14, Idx 0x1c00002, nameAlg 11, Attr 0x62076801, authPol 0, dataSz 1300, name 34 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 0, Size 768 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 768, Size 532 +EK Data: 1300 + 30 82 05 10 30 82 02 f8 a0 03 02 01 02 02 14 58 | 0...0..........X + ... +wolfTPM2_HashStart: Handle 0x80000002 +wolfTPM2_HashUpdate: Handle 0x80000002, DataSz 764 +wolfTPM2_HashFinish: Handle 0x80000002, DigestSz 48 +Cert Hash: 48 + ... +Issuer Public Exponent 0x10001, Modulus 512 + ... +TPM2_LoadExternal: 0x80000002 +EK Certificate Signature: 512 + ... +TPM2_RSA_Encrypt: 512 +Decrypted Sig: 512 + ... +Expected Hash: 48 + ... +Sig Hash: 48 + ... +Certificate signature is valid +TPM2_FlushContext: Closed handle 0x80000002 +TPM2_FlushContext: Closed handle 0x80000000 +``` + +## デバイス ID + +TCG は、デバイス ID とアテステーション用の鍵を設定するための、TPM 製造元向けガイダンス仕様を公開しています。wolfTPM は `WOLFTPM_MFG_IDENTITY` でこれに対応しており、ST33KTPM でテスト済みです。 + +ST33KTPM のサンプルには、デフォルトのマスターパスワードがプロビジョニングされており、`TEST_SAMPLE` で有効になります。独自のマスターパスワードを使うには、`TPM2_IAK_SAMPLE_MASTER_PASSWORD` を定義してください。マスターパスワードはデバイスのシリアル番号とともにハッシュされ、これらの鍵にアクセスするための認証値が生成されます。 + +デフォルトの鍵は、SHA2-384 を使う ECDSA SECP384R1 です。これらは `TPM2_IAK_KEY_HANDLE`、`TPM2_IAK_CERT_HANDLE`、`TPM2_IDEVID_KEY_HANDLE`、`TPM2_IDEVID_CERT_HANDLE` で定義された NV インデックスに格納されます。 + +## 関連項目 + +* [サンプルの概要](examples-overview.md) +* [鍵管理](key-management.md) +* [シーリングと NVRAM](sealing-and-nvram.md) +* [対応ハードウェア](supported-hardware.md) diff --git a/docs/ja/benchmarks.md b/docs/ja/benchmarks.md new file mode 100644 index 00000000..216bbee6 --- /dev/null +++ b/docs/ja/benchmarks.md @@ -0,0 +1,84 @@ +# ベンチマーク + +このページでは、`examples/bench/bench` プログラムで測定した、対応 TPM 2.0 デバイスにおける一般的な操作の処理速度と、SEALSQ QVault シリコンによる初のポスト量子暗号の測定値を示します。 + +## これらの数値について + +これらは、異なるホストボードとバス速度で実機から取得した代表的な測定結果です。結果は TPM のファームウェアバージョン、バスクロック、ホストプラットフォーム、ビルドオプションによって変動するため、目安として扱い、実際の環境で `./examples/bench/bench` を実行してください。 + +## デバイス別 TPM 2.0 ベンチマーク + +1 操作あたりの平均レイテンシ (ミリ秒、小さいほど良い)。RSA-2048 の鍵生成は、プロビジョニング時に 1 回だけ発生するコストです。 + +| デバイス | バス | RSA-2048 鍵生成 | RSA-2048 秘密鍵演算 | ECDSA P-256 署名 | ECDSA P-256 検証 | +|---|---|---|---|---|---| +| Infineon OPTIGA SLB9670 | SPI, 43 MHz | 2196.2 | 163.2 | 68.9 | 113.5 | +| Infineon OPTIGA SLB9672 | SPI, 43 MHz | 1567.7 | 77.0 | 35.6 | 24.1 | +| Infineon OPTIGA SLB9673 | I2C, 400 kHz | 1910.6 | 168.1 | 72.1 | 57.9 | +| STMicro ST33KTPM2XSPI | SPI, 33 MHz | 1944.1 | 90.8 | 25.3 | 36.5 | +| STMicro ST33TPHF2XSPI | SPI, 33 MHz | 7455.0 | 247.8 | 42.3 | 74.0 | +| Microchip ATTPM20 | SPI, 33 MHz | 5275.9 | 117.7 | 58.7 | 43.0 | +| Nations Z32H330 | SPI, 33 MHz | 2183.8 | 133.2 | 23.4 | 36.8 | +| Nations NS350 | SPI, 33 MHz | 2378.9 | 51.7 | 16.8 | 21.9 | +| Nuvoton NPCT650 | 記載なし | 4479.2 | 540.9 | 190.1 | 265.2 | +| Nuvoton NPCT750 | SPI, 43 MHz | 3408.7 | 70.3 | 56.4 | 39.2 | +| NVIDIA Jetson Orin fTPM (OP-TEE) | `/dev/tpmrm0` | 736.4 | 11.9 | 45.1 | 31.7 | + +README に記載された ST33TPHF2XSPI の RSA 鍵生成の測定は 1 回の操作のみで実行されているため、この値は表の中で最も信頼性が低くなります。 + +Infineon OPTIGA SLB9672 を 43 MHz で動作させた場合の `./examples/bench/bench` の出力例を示します。 + +``` +./examples/bench/bench +TPM2 Benchmark using Wrapper API's + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +RNG 24 KB took 1.070 seconds, 22.429 KB/s +Benchmark symmetric AES-128-CBC-enc not supported! +Benchmark symmetric AES-128-CBC-dec not supported! +Benchmark symmetric AES-256-CBC-enc not supported! +Benchmark symmetric AES-256-CBC-dec not supported! +Benchmark symmetric AES-128-CTR-enc not supported! +Benchmark symmetric AES-128-CTR-dec not supported! +Benchmark symmetric AES-256-CTR-enc not supported! +Benchmark symmetric AES-256-CTR-dec not supported! +AES-128-CFB-enc 86 KB took 1.001 seconds, 85.890 KB/s +AES-128-CFB-dec 88 KB took 1.020 seconds, 86.267 KB/s +AES-256-CFB-enc 86 KB took 1.023 seconds, 84.073 KB/s +AES-256-CFB-dec 86 KB took 1.019 seconds, 84.370 KB/s +SHA1 88 KB took 1.021 seconds, 86.155 KB/s +SHA256 86 KB took 1.015 seconds, 84.717 KB/s +SHA384 90 KB took 1.007 seconds, 89.405 KB/s +RSA 2048 key gen 10 ops took 15.677 sec, avg 1567.678 ms, 0.638 ops/sec +RSA 2048 Public 110 ops took 1.000 sec, avg 9.095 ms, 109.951 ops/sec +RSA 2048 Private 14 ops took 1.078 sec, avg 76.996 ms, 12.988 ops/sec +RSA 2048 Pub OAEP 51 ops took 1.012 sec, avg 19.838 ms, 50.408 ops/sec +RSA 2048 Priv OAEP 12 ops took 1.053 sec, avg 87.738 ms, 11.398 ops/sec +ECC 256 key gen 8 ops took 1.088 sec, avg 135.956 ms, 7.355 ops/sec +ECDSA 256 sign 29 ops took 1.033 sec, avg 35.621 ms, 28.073 ops/sec +ECDSA 256 verify 42 ops took 1.013 sec, avg 24.114 ms, 41.470 ops/sec +ECDHE 256 agree 16 ops took 1.055 sec, avg 65.948 ms, 15.164 ops/sec +``` + +モードに対応していないデバイスでは、そのモードについて "not supported" と出力されます。 + +## ポスト量子暗号 (SEALSQ QVault) + +これらの数値は、SPI 経由で SEALSQ QVault TPM を駆動する Raspberry Pi 5 上で `examples/bench/bench` を使って測定しました。SEALSQ は、この製品をシリコンとして実現された初のポスト量子暗号対応 TPM と位置付けています。 + +| 操作 | 平均レイテンシ | スループット | +|---|---|---| +| ML-DSA-65 鍵生成 | 2044.7 ms | 0.49 ops/s | +| ML-DSA-65 署名 | 581.0 ms | 1.72 ops/s | +| ML-DSA-65 検証 | 163.1 ms | 6.13 ops/s | +| ML-KEM-768 鍵生成 | 800.8 ms | 1.25 ops/s | +| ML-KEM-768 カプセル化 | 211.8 ms | 4.72 ops/s | +| ML-KEM-768 デカプセル化 | 425.5 ms | 2.35 ops/s | + +鍵生成はプロビジョニング時に 1 回だけ発生するコストです。上記の ECDSA の値は、異なる TPM、ホストボード、バス、ファームウェアで取得したものであるため、これらの ML-DSA の値と同一条件での比較にはなりません。ECDSA と PQC のレイテンシを比較するには、同じ TPM、ホスト、バス、ビルドで両方について `./examples/bench/bench` を実行してください。 + +## 関連項目 + +- [テストと CI](testing.md) +- [引用文献](cited-sources.md) +- [リリースノート](release-notes.md) diff --git a/docs/ja/build-options.md b/docs/ja/build-options.md new file mode 100644 index 00000000..22a07099 --- /dev/null +++ b/docs/ja/build-options.md @@ -0,0 +1,165 @@ +# ビルドオプション + +このページは、wolfTPM のビルド方法を制御する Autotools (`./configure`) オプションとプリプロセッサ定義のリファレンスです。各 configure スイッチには、対応するマクロがある場合はそのマクロを記載しています。正式な情報源は wolfTPM ソースツリーの `configure.ac` です。 + +!!! note + このページでは Autotools ビルドについて説明します。CMake ビルドは異なります。fwTPM はデフォルトで無効であり、TPM インターフェースは `--enable-*` フラグではなく `WOLFTPM_INTERFACE` キャッシュ変数 (`auto`、`SWTPM`、`WINAPI`、`DEVTPM`、`SPI`、`I2C`、`MMIO`) で選択します。CMake については [Building wolfTPM](building.md) を参照してください。 + +## 表の読み方 + +- すべての `--enable-X` フラグには `--disable-X` 形式もあります。デフォルト列は、フラグを指定しなかった場合の状態を示します。 +- 一部のマクロはオプトアウト型です。`WOLFTPM2_NO_WRAPPER` は `--disable-wrapper` で定義され、`WOLFTPM2_NO_WOLFCRYPT` は `--disable-wolfcrypt` で定義されます。enable 形式ではこれらは定義されません。 +- 生成される `wolftpm/options.h` には、configure 時に選択されたマクロが記録されます。 + +## 一般およびデバッグ + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-debug[=yes\|no\|verbose\|io]` | no | デバッグコードを追加し、最適化を無効にします。`DEBUG_WOLFTPM` を定義します。`verbose` は `WOLFTPM_DEBUG_VERBOSE` も定義し、`io` は `WOLFTPM_DEBUG_VERBOSE` と `WOLFTPM_DEBUG_IO` の両方を定義します。 | +| `--enable-examples` | enabled | サンプルプログラムをビルドします。 | +| `--enable-wrapper` | enabled | ラッパー API をビルドします。`--disable-wrapper` は `WOLFTPM2_NO_WRAPPER` を定義します。 | +| `--enable-wolfcrypt` | enabled | RNG、認可セッション、パラメータ暗号化に wolfCrypt を使用します。`--disable-wolfcrypt` は `WOLFTPM2_NO_WOLFCRYPT` を定義します。 | +| `--with-wolfcrypt=PATH` | `/usr/local` | wolfSSL のインストール先のパスです。このディレクトリには `lib` と `include` が含まれている必要があります。 | +| `--enable-smallstack` | disabled | スタック使用量を削減するために `WOLFTPM_SMALL_STACK` を定義します。あわせて `MAX_COMMAND_SIZE=1024`、`MAX_RESPONSE_SIZE=1350`、`MAX_DIGEST_BUFFER=896` を設定します。`--disable-wolfcrypt` と併用すると、`MAX_SESSION_NUM=1` も設定します。 | +| `--enable-provisioning` | enabled | Initial Device Identity (IDevID) と Attestation Identity Key のプロビジョニングをサポートします。`WOLFTPM_PROVISIONING` を定義します。 | +| `--enable-firmware` | enabled | Infineon SLB9672/SLB9673 および ST ST33 の TPM ファームウェアアップグレードをサポートします。`WOLFTPM_FIRMWARE_UPGRADE` を定義します。無効にするには `--disable-firmware` を使用します。 | +| `--enable-fuzz` | disabled | ファズターゲットをビルドします。 | + +!!! warning + `WOLFTPM_DEBUG_SECRETS` はどの configure オプションでも設定されず、デフォルトでは無効です。手動で定義すると、認可値、セッションキー、バインドキー、HMAC キー、階層の認可値、暗号化シークレットなどの機密情報が出力されます。開発者のデバッグ用途に限って使用してください。本番ビルドや、標準出力を永続ストレージに記録するデバイスでは、決して有効にしないでください。 + +## I/O レイヤーとバス選択 + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-spi` | not set | SPI ハードウェアビルドの意図を示すシグナルです。`--enable-i2c` が指定されていない場合、SPI がデフォルトのトランスポートになります。マクロは追加しませんが、ハードウェア選択として扱われるため、swTPM と fwTPM の自動デフォルトが無効になります。`--enable-i2c` と併用することはできません。 | +| `--enable-i2c` | disabled | I2C TPM をサポートします。`WOLFTPM_I2C` を定義し、`WOLFTPM_ADV_IO` を自動的に定義します。 | +| `--enable-mmio` | disabled | 組み込みのメモリマップド I/O コールバックを使用します。`WOLFTPM_MMIO` を定義し、`WOLFTPM_ADV_IO` を自動的に定義します。 | +| `--enable-advio` | disabled | 拡張 I/O コールバックのシグネチャを使用します。`WOLFTPM_ADV_IO` を定義します。I2C または MMIO と併用する場合は、別途指定する必要はありません。 | +| `--enable-wolfhal` | disabled | wolfHAL の I/O コールバックを使用します。`WOLFTPM_WOLFHAL` を定義します。wolfHAL のヘッダーと、アプリケーションが提供する `board.h` が必要です。必要な `BOARD_*` 定義については `hal/README.md` を参照してください。 | +| `--enable-hal` | enabled | サンプルの HAL インターフェースをビルドします。`WOLFTPM_EXAMPLE_HAL` を定義します。 | +| `--enable-hal-reset[=LINE]` | disabled | Linux GPIO キャラクタデバイス経由の TPM nRST リセット HAL です。常に `WOLFTPM_HAL_RESET` を定義します。数値の `LINE` を指定すると `WOLFTPM_RESET_LINE` も定義します。ライン未指定の場合のデフォルトは、ST33 では GPIO24、Nuvoton では GPIO4 です。`TPM2_IoCb_Reset()` で駆動します。 | +| `--enable-checkwaitstate` | depends on chip | TIS および SPI のウェイトステート確認をサポートします。`WOLFTPM_CHECK_WAIT_STATE` を定義します。configure は、autodetect の場合と、Infineon 専用ではないすべてのビルドで有効にします。 | +| `--enable-tislock` | disabled | `WOLFTPM_TIS_LOCK` を定義します。名前付きセマフォを使用して、プロセス間で TIS コマンドをシリアライズします。Linux のみ対応です。 | + +`--enable-hal-reset` には SPI または I2C のハードウェア HAL が必要です。configure は、swTPM または `--enable-devtpm` との併用を拒否します。一般的なホストでは swTPM がデフォルトであるため、併用する場合は `--enable-spi` または `--enable-i2c` を指定してください。 + +!!! note + Raspberry Pi で I2C を使用するには、あらかじめ I2C を有効にする必要がある場合があります。 + + 1. 現在の Raspberry Pi OS では `/boot/firmware/config.txt` を編集します (例: `sudo vim /boot/firmware/config.txt`)。古いイメージでは `/boot/config.txt` を使用します。 + 2. `dtparam=i2c_arm=on` のコメントを解除します。 + 3. `sudo reboot` で再起動します。 + +## TPM ベンダーとモジュール + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-infineon[=slb9670\|slb9672\|slb9673]` | disabled | 引数なしの `--enable-infineon` は SLB9672 を選択し、`WOLFTPM_SLB9672` を定義します。`--enable-infineon=slb9670` は `WOLFTPM_SLB9670` を定義します。`--enable-infineon=slb9673` は `WOLFTPM_SLB9673` を定義し、I2C 専用です。`--enable-i2c` を使用し、`--enable-spi` は指定しないでください。 | +| `--enable-st33`, `--enable-st` | disabled | ST ST33 をサポートします。`WOLFTPM_ST33` を定義します。2 つのフラグは同等です。 | +| `--enable-microchip`, `--enable-mchp` | disabled | Microchip ATTPM20 をサポートします。`WOLFTPM_MICROCHIP` を定義します。2 つのフラグは同等です。 | +| `--enable-nuvoton` | disabled | Nuvoton NPCT65x/NPCT75x をサポートします。`WOLFTPM_NUVOTON` を定義します。 | +| `--enable-nations` | disabled | Nations Technology NS350 をサポートします。`WOLFTPM_NATIONS` を定義します。 | +| `--enable-sealsq` | disabled | SealSQ QVault のポスト量子 TPM をサポートします。`WOLFTPM_SEALSQ` を定義します。 | +| `--enable-autodetect` | on when no vendor module is selected | 実行時にモジュールを検出します。`WOLFTPM_AUTODETECT` を定義します。 | + +引数を指定して Infineon デバイスを選択する例を示します。 + +```sh +./configure --enable-infineon=slb9670 +./configure --enable-infineon=slb9673 --enable-i2c +``` + +## オペレーティングシステムのトランスポートとシミュレータ + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-devtpm` | disabled | Linux カーネルドライバー (`/dev/tpmrm0` または `/dev/tpm0`) を使用します。`WOLFTPM_LINUX_DEV` を定義します。swTPM と併用することはできません。 | +| `--enable-swtpm` | see below | swtpm の TCP プロトコルでシミュレータと通信します。`WOLFTPM_SWTPM` と `TPM2_SWTPM_PORT` を定義します。 | +| `--enable-swtpm=uart` | disabled | UART シリアルポート上の swtpm プロトコルです。STM32H5 などの組み込みターゲットでの fwTPM 向けです。`WOLFTPM_SWTPM`、`WOLFTPM_SWTPM_UART`、`TPM2_SWTPM_PORT` を定義し、ポート値はボーレート (デフォルト 115200) になります。 | +| `--with-swtpm-port=PORT` | 2321 | `TPM2_SWTPM_PORT` を設定します。`--enable-swtpm=uart` の場合は、代わりにボーレートを設定します。 | +| `--enable-fwtpm` | see below | ファームウェア TPM (fwTPM) サーバーをビルドします。wolfCrypt が必要です。 | +| `--enable-winapi` (alias `--enable-wintbs`) | disabled | Windows TBS API を使用します。`WOLFTPM_WINAPI` を定義します。swTPM または devtpm と併用することはできません。 | + +### シミュレータのデフォルト動作 + +`--enable-swtpm` と `--enable-fwtpm` は、次のすべてが成り立つ場合にデフォルトで有効になります。 + +- ホスト CPU が x86_64、amd64、または aarch64 である。 +- ホスト OS が Windows (mingw、cygwin、msys、win32) ではない。 +- wolfCrypt が有効である。 +- `--enable-spi`、`--enable-i2c`、`--enable-mmio`、`--enable-devtpm`、`--enable-autodetect`、`--enable-winapi`、`--enable-infineon`、`--enable-st`、`--enable-st33`、`--enable-microchip`、`--enable-nuvoton`、`--enable-nations`、`--enable-sealsq` のいずれでもハードウェアパスが選択されていない。 + +これは Linux だけでなく macOS と BSD にも当てはまります。それ以外の環境では、デフォルトは無効です。 + +!!! warning + これらのホストでオプションなしの `./configure` を実行すると、`WOLFTPM_AUTODETECT` と `WOLFTPM_SWTPM` の両方が定義される場合があります。`WOLFTPM_SWTPM` はカーネルデバイスの検出を抑止するため、そのようなビルドは `/dev/tpmrm0` や `/dev/tpm0` を試行しません。実際の TPM を使用するには、`--enable-autodetect`、`--enable-devtpm`、またはベンダーフラグを明示的に指定してください。`--enable-autodetect` を明示するとシミュレータのデフォルトが無効になり、カーネル優先の動作になります。Linux では実行時に `/dev/tpmrm0` または `/dev/tpm0` を試行し、カーネルドライバーが利用できない場合は SPI にフォールバックします。 + +### fwTPM のマクロ + +| Macro | Where it is set | +| --- | --- | +| `WOLFTPM_FWTPM_BUILD` | あらゆる fwTPM ビルドで、生成される `options.h` に追加されます。テストスクリプトが参照するマーカーです。 | +| `WOLFTPM_FWTPM` | fwTPM サーバーとファズターゲットにのみ設定されます。共有ソース内のサーバー側コードを制御します。 | +| `WOLFTPM_FWTPM_HAL`, `WOLFTPM_ADV_IO` | TIS および共有メモリのビルド、つまり `--enable-swtpm` を伴わない fwTPM で追加されます。Windows ではサポートされません。 | + +### fwTPM 専用モードと NV モード + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-fwtpm-only` | disabled | fwTPM サーバーのみをビルドします。クライアントライブラリ、ラッパー、サンプルをスキップし、`WOLFTPM2_NO_WRAPPER` を定義します。`--enable-fwtpm` を暗黙的に有効にし、wolfCrypt が必要です。`--enable-spdm` とは互換性がありません。 | +| `--enable-fwtpm-nv-appendonly` | disabled | 書き込み一回限りのフラッシュ向け fwTPM ポートのための、追記専用 NV ジャーナルモードです。`WOLFTPM_FWTPM_NV_APPEND_ONLY` を定義します。 | + +## SPDM + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-spdm` | disabled | SPDM をサポートします。`WOLFTPM_SPDM` を定義します。wolfSPDM サブモジュールが必要です。`git submodule update --init lib/wolfSPDM` を実行してください。fwTPM と併用すると `WOLFTPM_SPDM_RESPONDER` も定義します。 | +| `--enable-tcg` | auto under `--enable-spdm` | SPDM TCG バインディングモードです。`WOLFTPM_SPDM_TCG` を定義します。fwTPM、Nuvoton、Nations では自動的に有効になります。 | +| `--enable-psk` | auto with Nations | SPDM PSK モードです。`WOLFTPM_SPDM_PSK` を定義します。`--enable-tcg` が必要です。 | + +configure が強制する関連ルールは次のとおりです。 + +- `--enable-tcg` と `--enable-psk` には `--enable-spdm` が必要です。 +- SPDM を伴う `--enable-nuvoton` には `--enable-tcg` が必要で、`WOLFSPDM_NUVOTON` を定義します。 +- SPDM を伴う `--enable-nations` には `--enable-tcg` と `--enable-psk` の両方が必要で、`WOLFSPDM_NATIONS` を定義します。 +- SPDM を伴う fwTPM には、`--enable-tcg` または `--enable-psk` の少なくとも一方が必要です。 +- `--with-wolfspdm` は廃止されており、指定すると configure が失敗します。`--enable-spdm` を使用してください。 +- SPDM を伴うデバッグビルドは `WOLFSPDM_DEBUG` も定義します。 + +## ポスト量子 (v1.85) + +| Option | Default | Effect and macros | +| --- | --- | --- | +| `--enable-v185` | auto-detect | TPM 2.0 v1.85 の全機能を有効にします。ML-DSA と ML-KEM、署名および検証のシーケンスコマンドとダイジェストコマンド、新しいレスポンスコード、新しいケイパビリティプロパティが含まれます。`WOLFTPM_V185` を定義します。wolfCrypt が ML-DSA と ML-KEM の両方を備えている場合、fwTPM ビルドでは自動的に有効になります。 | +| `--enable-pqc` | auto-detect | ポスト量子の軽量サブセット (ML-DSA と ML-KEM のみ) です。`WOLFTPM_PQC` を定義します。fwTPM ビルドでは完全な v1.85 に昇格します。両方を指定した場合は `--enable-v185` が優先されます。 | +| `--enable-mldsa[=all\|sign-only\|verify-only\|no]` | all | ML-DSA を制限します。`sign-only` は `WOLFTPM_NO_MLDSA_VERIFY` を、`verify-only` は `WOLFTPM_NO_MLDSA_SIGN` を、`no` は `WOLFTPM_NO_MLDSA` を定義します。 | +| `--enable-mlkem[=all\|enc\|dec\|no]` | all | ML-KEM を制限します。`enc` は `WOLFTPM_NO_MLKEM_DECAP` を、`dec` は `WOLFTPM_NO_MLKEM_ENCAP` を、`no` は `WOLFTPM_NO_MLKEM` を定義します。 | +| `--disable-hash-mldsa` | pre-hash enabled | プリハッシュ ML-DSA キーのサポートを除外します。`WOLFTPM_NO_HASH_MLDSA` を定義します。 | + +自動検出を含め、ポスト量子サポートを無効にするには `--disable-v185` または `--disable-pqc` を使用します。`--enable-mldsa=no` と `--enable-mlkem=no` の両方を指定するとエラーになります。wolfCrypt が有効な場合、PQC には ML-DSA (`--enable-mldsa`、または wolfSSL のエイリアス `--enable-dilithium`) と ML-KEM (`--enable-mlkem`) を有効にしてビルドした wolfSSL 5.9.2-stable 以降が必要です。`--disable-wolfcrypt` の場合、PQC はコマンドのマーシャリングのみとなります。 + +## プリプロセッサ定義 + +これらは configure オプションではありません。`CFLAGS` で設定します。例: `./configure CFLAGS="-DWOLFTPM_MAX_RETRIES=3"`。 + +| Macro | Effect | +| --- | --- | +| `WOLFTPM_USE_SYMMETRIC` | TLS サンプル向けに、対称 AES、ハッシュ、HMAC のサポートを有効にします。 | +| `WOLFTPM2_USE_SW_ECDHE` | TLS サンプルが ECC 一時鍵の生成と共有シークレットの導出に TPM を使用しないようにします。 | +| `TLS_BENCH_MODE` | TLS ベンチマークモードを有効にします。 | +| `NO_TPM_BENCH` | TPM ベンチマークサンプルを無効にします。 | +| `WOLFTPM2_ECC_DEFAULT_CURVE` | 曲線を明示しない名前付きラッパーテンプレート (現在は SRK と AIK) が使用する曲線です。デフォルトは `TPM_ECC_NIST_P256`、または `ECC_MIN_KEY_SZ` を満たす有効な最小の曲線です。`-DWOLFTPM2_ECC_DEFAULT_CURVE=TPM_ECC_NIST_P384` のように上書きできます。`wolfTPM2_GetKeyTemplate_ECC` と `_ECC_ex` は曲線を明示的に受け取るため、このマクロによる置き換えは行われません。ただし `NO_ECC256` が設定されている場合は P-256 が代替されます。 | +| `WOLFTPM_MAX_RETRIES` | TPM が `TPM_RC_RETRY` を返した場合 (TPM が一時的にビジー状態の場合。たとえば、`noDA` なしで外部からプロビジョニングされたキーを初めて認可に使用する際に `daUsed` フラグを永続化している間など) に、コマンドを再送信するデフォルトの回数です。デフォルトは 0 で、無効です。実行時に `TPM2_SetCommandRetries()` で、またはビルド時に `-DWOLFTPM_MAX_RETRIES=N` で有効にできます。wolfTPM は作成するすべてのキーに `noDA` を設定するわけではありません。汎用のキーテンプレート API は呼び出し側が渡した属性を使用し、EK テンプレートは `noDA` を省略するため、これらのキーではこの状態が発生し得ます。 | +| `WOLFTPM_NO_RETRY` | `TPM_RC_RETRY` の再送信処理をコンパイルから除外します。`TPM_RC_RETRY` は呼び出し側に返されます。0 より大きい `WOLFTPM_MAX_RETRIES` とは競合します。 | +| `WOLFTPM_LOCALITY_DEFAULT` | 起動時に要求される TIS ロケーリティです (デフォルトは 0)。SPI、メモリマップド、swtpm のトランスポートでは、実行時に `wolfTPM2_SetLocality()` で変更できます。wolfTPM の I2C HAL はロケーリティ選択を実装しておらず、ロケーリティ 0 のみを使用するため、I2C で 0 以外を指定して `wolfTPM2_SetLocality()` を呼び出すと `NOT_COMPILED_IN` が返されます。 | +| `WOLFTPM_TIS_RESET_STALE_LOCALITY` | 起動時に、`WOLFTPM_LOCALITY_DEFAULT` 以外でアクティブなロケーリティを解放し、デフォルトを付与できるようにします。前回のセッションがロケーリティを解放しなかったために停止状態になった TPM を復旧します。デフォルトでは無効です。共有バスでは別のマスターが保持しているロケーリティを解除してしまう可能性があるため、シングルマスターバスでのみ使用してください。代替手段として nRST リセット HAL があります。 | +| `WOLFTPM_LOCALITY_TIMEOUT_TRIES` | 実行時にロケーリティを要求する際のポーリング試行回数です (デフォルトは 1000)。付与できないロケーリティを素早く失敗させるため、小さい値になっています。 | +| `WOLFTPM_RESET_LINE` | リセット HAL 用の nRST GPIO ライン番号です。`--enable-hal-reset=LINE` で設定します。 | + +## 関連項目 + +- [wolfTPM のビルド](building.md) +- [システムインターフェース](system-interfaces.md) +- [サポート対象ハードウェア](supported-hardware.md) +- [はじめに](getting-started.md) diff --git a/docs/ja/building.md b/docs/ja/building.md new file mode 100644 index 00000000..12fa3862 --- /dev/null +++ b/docs/ja/building.md @@ -0,0 +1,426 @@ +# wolfTPM のビルド + +wolfTPM は wolfSSL (wolfCrypt) の上に構築されており、autotools、CMake、または `user_settings.h` ファイルを使用したベアメタルプロジェクトへの直接組み込みでビルドできます。このページでは各ビルド方法を説明します。ベンダーごとのビルド手順は[対応ハードウェア](supported-hardware.md)ページに、configure スイッチの完全な一覧は[ビルドオプション](build-options.md)ページに記載されています。 + +## wolfSSL のビルド + +最初に wolfSSL をビルドしてインストールする必要があります。wolfSSL は[ダウンロードページ](https://wolfssl.com/download/)から入手するか、GitHub からクローンできます。 + +```bash +git clone https://github.com/wolfSSL/wolfssl.git +cd wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +sudo ldconfig +``` + +`autogen.sh` には automake と libtool が必要です: `sudo apt-get install automake libtool`。 + +`--enable-wolftpm` オプションは、次のオプションを指定した場合と同等です。 + +```bash +./configure --enable-certgen --enable-certreq --enable-certext \ + --enable-pkcs7 --enable-cryptocb --enable-aescfb +``` + +## 別の wolfSSL ディレクトリを使用する + +既定以外の場所にインストールした wolfSSL に対して wolfTPM をビルドするには、wolfSSL を任意のプレフィックスにインストールし、`--with-wolfcrypt` で wolfTPM にその場所を指定します。 + +```bash +# cd /your-wolfssl-repo +./autogen.sh # as necessary +./configure --prefix=~/workspace/my_wolfssl_bin --enable-all +make install + +# then for some other library such as wolfTPM: + +# cd /your-wolftpm-repo +./configure --enable-swtpm --with-wolfcrypt=~/workspace/my_wolfssl_bin +``` + +## autotools でのビルド + +wolfSSL をインストールしたら、[ダウンロードページ](https://wolfssl.com/download/)から wolfTPM を入手するか GitHub からクローンして、ビルドします。 + +```bash +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +./autogen.sh +./configure +make +``` + +必要なオプションを `./configure` に追加してください。たとえば、`--enable-devtpm` は Linux カーネルの TPM デバイスを使用し、`--enable-swtpm` は TPM シミュレータを使用します。オプションの一覧は[ビルドオプション](build-options.md)を、各 TPM モジュールに必要なオプションは[対応ハードウェア](supported-hardware.md)を参照してください。 + +Linux の x86_64 と aarch64 では、オプションなしの `./configure` を実行すると、ハードウェアなしで `make check` が動作するように、ソフトウェア TPM バックエンドが自動的に有効になります。[システムインターフェース](system-interfaces.md)を参照してください。 + +## CMake でのビルド + +CMake は、CMake サポートがインストールされている場合の Visual Studio を含め、多くの環境でのコンパイルをサポートします。以下のコマンドは `Developer Command Prompt` で実行できます。 + +```bash +mkdir build +cd build +# to use installed wolfSSL location (library and headers) +cmake .. -DWITH_WOLFSSL=/prefix/to/wolfssl/install/ +# OR to use a wolfSSL source tree +cmake .. -DWITH_WOLFSSL_TREE=/path/to/wolfssl/ +# build +cmake --build . +``` + +wolfSSL がすでにインストールされている (ライブラリとヘッダー) 場合は `-DWITH_WOLFSSL=` を、wolfSSL のソースツリーに対してビルドする場合は `-DWITH_WOLFSSL_TREE=` を使用します。 + +## ベアメタルビルド + +wolfTPM は、オペレーティングシステムが存在しないベアメタルの組み込み環境向けにビルドできます。この方法では、autotools や CMake を使用せず、wolfTPM のソースファイルをプロジェクトに直接コンパイルします。ARM Cortex-M、RISC-V、UltraScale+/Versal、Microblaze などのマイクロコントローラでよく使われます。 + +### 前提条件 + +- wolfCrypt ライブラリのソースコード +- wolfTPM ライブラリのソースコード +- SPI (または I2C) で接続された TPM 2.0 モジュール + +### 手順 1: プリプロセッサマクロを定義する + +次のプリプロセッサマクロを、プロジェクトのビルド設定またはコンパイラのコマンドラインに追加します。 + +``` +WOLFTPM_USER_SETTINGS +WOLFSSL_USER_SETTINGS +``` + +これらのマクロは、autoconf が生成する `options.h` ファイルの代わりに `user_settings.h` ファイルを使用するよう、wolfTPM と wolfSSL に指示します。 + +### 手順 2: user_settings.h ファイルを作成する + +wolfSSL と wolfTPM の両方のビルド設定オプションを記述した `user_settings.h` ファイルをプロジェクトに作成します。参考用の設定ファイルが wolfSSL リポジトリにあります: [examples/configs/user_settings_wolftpm.h](https://github.com/wolfSSL/wolfssl/blob/master/examples/configs/user_settings_wolftpm.h)。 + +wolfTPM 向けの `user_settings.h` の例: + +```c +/* System */ +#define WOLFSSL_GENERAL_ALIGNMENT 4 +#define SINGLE_THREADED +#define WOLFCRYPT_ONLY +#define SIZEOF_LONG_LONG 8 + +/* Platform - bare metal */ +#define NO_FILESYSTEM +#define NO_WRITEV +#define NO_MAIN_DRIVER +#define NO_DEV_RANDOM +#define NO_ERROR_STRINGS +#define NO_SIG_WRAPPER + +/* wolfTPM required features */ +#define WOLF_CRYPTO_CB +#define WOLFSSL_PUBLIC_MP +#define WOLFSSL_AES_CFB +#define HAVE_AES_DECRYPT + +/* ECC options */ +#define HAVE_ECC +#define ECC_TIMING_RESISTANT + +/* RSA options */ +#undef NO_RSA +#define WOLFSSL_KEY_GEN +#define WC_RSA_BLINDING + +/* Big math library */ +#define WOLFSSL_SP_MATH_ALL /* sp_int.c */ +#define WOLFSSL_SP_SMALL +#define SP_INT_BITS 4096 +/* #define SP_WORD_SIZE 32 */ + +/* SHA options: SHA-256 stays enabled, so do not define NO_SHA256 */ +#define WOLFSSL_SHA512 +#define WOLFSSL_SHA384 + +/* Disable unneeded features to reduce footprint */ +#define NO_PKCS8 +#define NO_PKCS12 +#define NO_PWDBASED +#define NO_DSA +#define NO_DES3 +#define NO_RC4 +#define NO_PSK +#define NO_MD4 +#define NO_MD5 +#define WOLFSSL_NO_SHAKE128 +#define WOLFSSL_NO_SHAKE256 +#define NO_DH + +/* Other interesting size reduction options */ +#if 0 + #define RSA_LOW_MEM + #define WOLFSSL_AES_SMALL_TABLES + #define USE_SLOW_SHA + #define USE_SLOW_SHA256 + #define USE_SLOW_SHA512 + #define NO_AES_192 +#endif + +/* Custom random seed source - implement your own */ +#define HAVE_HASHDRBG +#define CUSTOM_RAND_GENERATE_SEED my_rng_seed +``` + +!!! warning + `NO_*` マクロはアルゴリズムを無効にします。wolfTPM のラッパーとセッションには SHA-256 が必要なため、このファイルで `NO_SHA256` を定義してはいけません。 + +`CUSTOM_RAND_GENERATE_SEED` を使用する場合は、独自の RNG シード関数を実装してください。次の例は、パラメータ暗号化を有効にして TPM からシードを取得します。 + +```c +int my_rng_seed(byte* seed, word32 sz) +{ + int rc; + + /* enable parameter encryption for the RNG request */ + rc = wolfTPM2_SetAuthSession(&wolftpm_dev, 0, &wolftpm_session, + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | + TPMA_SESSION_continueSession)); + if (rc == 0) { + rc = wolfTPM2_GetRandom(&wolftpm_dev, seed, sz); + } + wolfTPM2_UnsetAuthSession(&wolftpm_dev, 0, &wolftpm_session); + return rc; +} +``` + +### 手順 3: インクルードパスを設定する + +次のディレクトリをプロジェクトのインクルードパスに追加します。 + +1. wolfSSL のルートディレクトリ (例: `/path/to/wolfssl`) +2. wolfTPM のルートディレクトリ (例: `/path/to/wolftpm`) +3. `user_settings.h` を置いているディレクトリ + +コンパイラフラグの例: + +``` +-I/path/to/wolfssl +-I/path/to/wolftpm +-I/path/to/your/project/include +``` + +### 手順 4: ソースファイルを追加する + +wolfSSL と wolfTPM から必要なソースファイルをプロジェクトに追加します。 + +wolfCrypt のソースファイル (wolfTPM に最低限必要なもの): + +``` +wolfssl/wolfcrypt/src/aes.c +wolfssl/wolfcrypt/src/asn.c +wolfssl/wolfcrypt/src/cryptocb.c +wolfssl/wolfcrypt/src/ecc.c +wolfssl/wolfcrypt/src/hash.c +wolfssl/wolfcrypt/src/hmac.c +wolfssl/wolfcrypt/src/random.c +wolfssl/wolfcrypt/src/rsa.c +wolfssl/wolfcrypt/src/sha.c +wolfssl/wolfcrypt/src/sha256.c +wolfssl/wolfcrypt/src/sha512.c +wolfssl/wolfcrypt/src/sp_int.c +wolfssl/wolfcrypt/src/wc_port.c +wolfssl/wolfcrypt/src/wolfmath.c +``` + +wolfTPM のソースファイル: + +``` +wolftpm/src/tpm2.c +wolftpm/src/tpm2_util.c +wolftpm/src/tpm2_packet.c +wolftpm/src/tpm2_tis.c +wolftpm/src/tpm2_wrap.c +wolftpm/src/tpm2_asn.c +wolftpm/src/tpm2_crypto.c +wolftpm/src/tpm2_param_enc.c +wolftpm/src/tpm2_cryptocb.c +wolftpm/src/tpm2_linux.c +``` + +このリストは `src/include.am` の `src_libwolftpm_la_SOURCES` に対応します。`tpm2_swtpm.c`、`tpm2_winapi.c`、`tpm2_spdm.c` は、それぞれのオプションビルドでのみ必要です。HAL のソース (`hal/tpm_io*.c` のいずれか、後述) は別途追加します。 + +### 手順 5: SPI HAL コールバックを実装する + +wolfTPM が TPM モジュールと通信するには、SPI の送受信コールバックが 1 つ必要です。お使いのハードウェアプラットフォーム向けに実装してください。参考実装は wolfTPM リポジトリの `hal/` ディレクトリにあります。 + +- [hal/tpm_io_xilinx.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_xilinx.c): Xilinx Microblaze 向け +- [hal/tpm_io_st.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_st.c): STM32 向け +- [hal/tpm_io_infineon.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_infineon.c): Infineon Tricore 向け +- [hal/tpm_io_microchip.c](https://github.com/wolfSSL/wolfTPM/blob/master/hal/tpm_io_microchip.c): Microchip 向け + +#### 標準 I/O コールバック + +標準の SPI コールバックのシグネチャは次のとおりです。 + +```c +typedef int (*TPM2HalIoCb)( + TPM2_CTX* ctx, + const byte* txBuf, byte* rxBuf, + word16 xferSz, + void* userCtx +); +``` + +実装例: + +```c +#include +#include + +int TPM2_IoCb(TPM2_CTX* ctx, + const byte* txBuf, byte* rxBuf, word16 xferSz, + void* userCtx) +{ + int ret = TPM_RC_FAILURE; + + /* TODO: Assert SPI chip select */ + spi_cs_assert(); + + /* Perform SPI transfer: send txBuf and receive into rxBuf */ + if (spi_transfer(txBuf, rxBuf, xferSz) == 0) { + ret = TPM_RC_SUCCESS; + } + + /* TODO: De-assert SPI chip select */ + spi_cs_deassert(); + + (void)ctx; + (void)userCtx; + + return ret; +} +``` + +#### 拡張 I/O コールバック + +より細かい制御が必要なプラットフォームでは、`WOLFTPM_ADV_IO` を有効にして拡張コールバックを使用します。 + +```c +typedef int (*TPM2HalIoCb)( + TPM2_CTX* ctx, + INT32 isRead, UINT32 addr, + BYTE* xferBuf, UINT16 xferSz, + void* userCtx +); +``` + +これにより、レジスタアドレスと読み取り/書き込みの方向にアクセスできるため、読み取りと書き込みの操作を分けて扱う必要があるプラットフォームで利用できます。 + +### 手順 6: wolfTPM を初期化して使用する + +セットアップが完了したら、wolfTPM を初期化して TPM との通信を開始します。 + +```c +#include + +int main(void) +{ + int rc; + WOLFTPM2_DEV dev; + + /* Initialize wolfTPM */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + if (rc != TPM_RC_SUCCESS) { + /* Handle error */ + return rc; + } + + /* Get TPM capabilities */ + WOLFTPM2_CAPS caps; + rc = wolfTPM2_GetCapabilities(&dev, &caps); + if (rc == TPM_RC_SUCCESS) { + /* Use TPM ... */ + } + + /* Cleanup */ + wolfTPM2_Cleanup(&dev); + + return 0; +} +``` + +### オプションのビルド構成 + +リソースの限られた環境でメモリフットプリントを削減するには、`user_settings.h` で次のオプションを検討してください。 + +```c +/* Reduce stack usage */ +#define WOLFTPM_SMALL_STACK + +/* Disable wrapper layer if using native API only */ +#define WOLFTPM2_NO_WRAPPER + +/* Use smaller RSA key sizes only */ +#define MAX_RSA_KEY_BITS 2048 +``` + +コンパイル時に TPM モジュールの種類が分かっている場合は、それを選択します。複数ではなく、モジュールのバリアントを 1 つだけ選択してください。 + +```c +/* For Infineon, pick exactly one of these */ +#define WOLFTPM_SLB9670 +/* #define WOLFTPM_SLB9672 */ +/* #define WOLFTPM_SLB9673 */ + +/* For ST ST33 */ +#define WOLFTPM_ST33 + +/* For Nuvoton */ +#define WOLFTPM_NUVOTON + +/* For Microchip ATTPM20 */ +#define WOLFTPM_MICROCHIP +``` + +モジュールを指定しない場合、wolfTPM は `WOLFTPM_AUTODETECT` (既定) を使用して、実行時に自動検出を試みます。 + +SPI ではなく I2C で接続された TPM モジュールの場合: + +```c +#define WOLFTPM_I2C +#define WOLFTPM_ADV_IO +``` + +I2C 通信には、拡張 I/O コールバックを実装する必要があります。 + +### 暗号鍵の保管 + +ベアメタル環境では、TPM がメインプロセッサのメモリから分離された、暗号鍵のためのセキュアな保管場所を提供します。鍵素材が平文の形で TPM の外に出ることはありません。 + +- `TPM2_CreatePrimary` で作成した鍵は TPM 内に存在し、ハンドルが返されます。 +- `TPM2_Create` で作成した鍵は暗号化されたブロブとして返され、不揮発性メモリに保存して `TPM2_Load` で再ロードできます。 +- `TPM2_EvictControl` を使用すると、鍵を TPM の NVRAM に永続的に保存できます。 + +これにより、メインプロセッサのメモリが侵害された場合でも、暗号鍵は保護されたままになります。 + +### トラブルシューティング + +SPI 通信の問題: + +1. SPI のクロック極性と位相を確認します (TPM では通常 CPOL=0、CPHA=0)。 +2. SPI クロック速度を確認します。低速 (1 ~ 10 MHz) から始めて、徐々に上げてください。 +3. 送受信の全期間にわたって、チップセレクトがローにアサートされていることを確認します。 +4. 一部の TPM では、SPI 操作中にウェイトステートが必要です。これは、レスポンスの準備完了を示す MSB が立つまで追加のバイトを読み取ることを意味します (`WOLFTPM_CHECK_WAIT_STATE` で有効化)。 +5. デバッグ出力は、`DEBUG_WOLFTPM` (一般)、`WOLFTPM_DEBUG_VERBOSE` (詳細)、`WOLFTPM_DEBUG_IO` (SPI と I2C のトランザクション) で有効にできます。 + +ビルドエラー: + +1. `WOLFSSL_USER_SETTINGS` と `WOLFTPM_USER_SETTINGS` が定義されていることを確認します。 +2. インクルードパスが正しいことを確認します。 +3. 必要なソースファイルがすべてビルドに含まれていることを確認します。 + +## 関連項目 + +- [はじめに](getting-started.md) +- [ビルドオプション](build-options.md) +- [対応ハードウェア](supported-hardware.md) +- [システムインターフェース](system-interfaces.md) diff --git a/docs/ja/cited-sources.md b/docs/ja/cited-sources.md new file mode 100644 index 00000000..62db1c94 --- /dev/null +++ b/docs/ja/cited-sources.md @@ -0,0 +1,23 @@ +# 引用文献 + +このページでは、本マニュアルの執筆に使用した参考文献を示します。元の序文で引用された 2 つの文献と、マニュアルが参照する仕様書の順に記載しています。 + +## 参考文献 + +1. Wikipedia contributors. (2018, May 30). Trusted Platform Module. In _Wikipedia, The Free Encyclopedia_. Retrieved 22:46, June 20, 2018. +2. Arthur W., Challener D., Goldman K. (2015). Platform Configuration Registers. In: _A Practical Guide to TPM 2.0_. Apress, Berkeley, CA. + +## 仕様書 + +| 仕様書 | 発行団体 | 適用箇所 | +|---|---|---| +| TPM 2.0 Library Specification, versions 1.38, 1.59, 1.84 and 1.85 | Trusted Computing Group (TCG) | wolfTPM と fwTPM が実装する TPM 2.0 のコマンドセット、構造体、動作。バージョン 1.85 でポスト量子暗号コマンドが追加されました。 | +| FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard (ML-KEM) | NIST | ポスト量子暗号の鍵カプセル化 (ML-KEM-768)。 | +| FIPS 204, Module-Lattice-Based Digital Signature Standard (ML-DSA) | NIST | ポスト量子暗号の署名 (ML-DSA-65)。 | +| DSP0274, Security Protocol and Data Model (SPDM) Specification | DMTF | 対応する TPM モジュールおよび fwTPM で使用される SPDM セキュアトランスポート。 | + +## 関連項目 + +- [ベンチマーク](benchmarks.md) +- [リリースノート](release-notes.md) +- [API リファレンス](api-reference.md) diff --git a/docs/ja/csharp-wrapper.md b/docs/ja/csharp-wrapper.md new file mode 100644 index 00000000..f56091e8 --- /dev/null +++ b/docs/ja/csharp-wrapper.md @@ -0,0 +1,183 @@ +# C# ラッパー + +`wrapper/CSharp` ディレクトリには、wolfTPM の TPM 2.0 API 向け C# ラッパーが含まれています。P/Invoke を通じてネイティブの `wolftpm` ライブラリにバインドするため、先にネイティブライブラリをビルドしておく必要があります。テストは NUnit を使用し、.NET (Windows) または Mono (Linux) 上で実行されます。 + +wolfTPM の `README.md` の説明に従って wolfSSL をビルドし、その後、お使いのプラットフォームに応じて以下の説明に従い wolfTPM をビルドしてください。Linux では、テストに swtpm TCP シミュレータを使用します。 + +## Windows + +ラッパーをビルドするための Visual Studio ソリューションが用意されています。テストを実行するには、`.runsettings` ファイルを更新して `wolftpm.dll` の場所を追加します。このファイルには vcpkg ビルド用のプレースホルダーがありますが、Visual Studio で wolfTPM をビルドする際に CMake を使用することもできます。 + +Windows で wolfTPM をビルドするための CMake 設定の例: + +``` +"WOLFTPM_INTERFACE": "WINAPI", +"WOLFTPM_EXAMPLES": "no", +"WOLFTPM_DEBUG": "yes", +"WITH_WOLFSSL": "C:/Users/[username]/wolfssl/out/install/windows-default" +``` + +## Linux + +このラッパーは、シミュレータ用の swtpm TCP プロトコルで動作確認されています。シミュレータのビルドと実行については [SWTPM](system-interfaces.md) を参照してください。 + +wolfTPM をビルドします。 + +```sh +./autogen.sh +./configure --enable-swtpm +make all +make check +``` + +Mono と NUnit の前提パッケージをインストールします。 + +```sh +apt install mono-tools-devel nunit nunit-console +``` + +続いて、ラッパーとそのテストをビルドして実行します。 + +```sh +cd wrapper/CSharp +mcs wolfTPM.cs wolfTPM-tests.cs -r:/usr/lib/cli/nunit.framework-2.6.3/nunit.framework.dll -t:library + +# run the selftest case +LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll -run=tpm_csharp_test.WolfTPMTest.TrySelfTest + +# run all tests +LD_LIBRARY_PATH=../../src/.libs/ nunit-console wolfTPM.dll +``` + +セルフテストを実行すると、次のような出力が表示されます。 + +``` +Selected test(s): tpm_csharp_test.WolfTPMTest.TrySelfTest + +wolfSSL Entering wolfCrypt_Init +. +Tests run: 1, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0.1530346 seconds + + Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0 + +wolfSSL Entering wolfCrypt_Cleanup +``` + +## API の概要 + +すべてのラッパー型は `wrapper/CSharp/wolfTPM.cs` の `wolfTPM` 名前空間にあります。各クラスはネイティブの wolfTPM オブジェクトを包む薄いクラスで、`wolftpm` ライブラリへの P/Invoke 呼び出しによって確保と解放が行われます。 + +| 型 | 用途 | +| --- | --- | +| `Device` | TPM への接続。ネイティブの `WOLFTPM2_DEV` を保持し、すべての TPM 操作を提供します。 | +| `Key` | ロード済みの TPM 鍵 (ストレージルート鍵 (SRK) やプライマリ鍵など)。 | +| `KeyBlob` | 作成した鍵 (公開部と秘密部)。ロード、使用、バイト配列への保存ができます。 | +| `Template` | 新しい鍵の種類と属性を記述する TPM 公開テンプレート。 | +| `Session` | TPM 認可セッション。パラメータ暗号化付きの HMAC セッションに使用します。 | +| `Csr` | サブジェクト、鍵用途、カスタム拡張を保持する証明書署名要求 (CSR) ヘルパー。 | +| `WolfTpm2Exception` | ネイティブ呼び出しが失敗したときにスローされる例外。 | +| `Status` | 主な戻りコードの列挙型: `TPM_RC_SUCCESS`、`TPM_RC_HANDLE`、`TPM_RC_NV_UNAVAILABLE`、`TPM_RC_SIGNATURE`、`BAD_FUNC_ARG`、`NOT_COMPILED_IN`。 | + +このファイルには、ネイティブの値に対応する列挙型も定義されています。`TPM2_Object` (`sensitiveDataOrigin`、`userWithAuth`、`decrypt`、`sign`、`noDA` などのオブジェクト属性ビット)、`TPM2_Alg` (`RSA`、`ECC`、`SHA256`、`RSASSA`、`CFB`、`XOR`、`NULL` など)、`TPM2_ECC` (曲線)、`SE` (セッションタイプ)、`SESSION_mask`、`TPM_RH` (`OWNER`、`ENDORSEMENT`、`PLATFORM` などの階層)、`X509_Format` (`PEM` または `DER`) です。 + +### Device の存続期間 + +`Device` は `IDisposable` を実装しています。コンストラクタはネイティブの `wolfTPM2_New()` を呼び出し、これは TPM の初期化も行うため、新しい `Device` はそのまま使用できます。`Dispose()` は `wolfTPM2_Free()` を呼び出してポインタをクリアします。呼び忘れた場合はファイナライザが同じ後処理を行いますが、デバイスは `using` ステートメントで囲むか、自分で `Dispose()` を呼び出してください。 + +`Key`、`KeyBlob`、`Template`、`Session`、`Csr` も同じパターンです。コンストラクタがネイティブオブジェクトを確保し、`Dispose()` が解放します。解放呼び出しのネイティブ戻り値は無視されます。 + +`Device.Ref` はネイティブのデバイスポインタを返します。`Device` には次の定数もあります: `MAX_KEYBLOB_BYTES` (2048)、`MAX_TPM_BUFFER` (2048)、`INVALID_DEVID` (-2)。最初の 2 つはテストで使用するバッファサイズであり、プラットフォームによってはより大きな値が必要になる場合があります。 + +### エラーと戻り値 + +ほとんどのメソッドは `int` を返し、失敗時には `WolfTpm2Exception` をスローします。通常のケースでは戻り値を確認する必要はありません。例外には、ネイティブの戻りコードを持つ `ErrorCode` プロパティがあります。`Message` には、ネイティブ関数名、16 進数のコード、`TPM2_GetRCString` が返すテキストが含まれます。`Device.GetErrorString(int)` と `Device.GetErrorString(Status)` は、任意のコードに対して同じテキストを返します。 + +一部のメソッドは、特定のコードを致命的ではないものとして扱い、スローせずに返します。 + +- `ReadPublicKey` は、ハンドルにオブジェクトが存在しない場合に `TPM_RC_HANDLE` を返します。 +- `StoreKey` は `TPM_RC_NV_UNAVAILABLE` を返します。 +- `VerifyHashScheme` は、署名が一致しない場合に `TPM_RC_SIGNATURE` を返します。 +- `Csr.SetCustomExtension` は、ネイティブライブラリが対応なしでビルドされている場合に `NOT_COMPILED_IN` を返します。 + +データを生成するメソッドは、成功時に正のサイズを返します: `KeyBlob.GetKeyBlobAsBuffer`、`Device.RsaEncrypt`、`Device.RsaDecrypt`、`Device.SignHashScheme`、`Device.GenerateCSR`、`Csr.MakeAndSign`。`UnloadHandle` はネイティブ関数を直接呼び出し、スローせずにそのコードを返します。 + +### 鍵、キーブロブ、セッション + +- `Key` は、`CreateSRK`、`CreatePrimaryKey`、`ReadPublicKey`、`LoadRsaPublicKey`、`LoadRsaPrivateKey`、`ImportRsaPrivateKey` のいずれかで設定されます。`GetHandle()` はネイティブのハンドルポインタを返し、`SetKeyAuthPassword` は鍵のパスワードを設定します。 +- `KeyBlob` は、親の `Key` と `Template` を指定した `CreateKey` で設定し、`LoadKey` でロードします。`GetKeyBlobAsBuffer` でエクスポートするとディスクに保存でき、別のプロセスで `SetKeyBlobFromBuffer` により復元できます。復元後は、再度 `LoadKey` でロードし、使用前に `SetKeyAuthPassword` を呼び出してください。 +- `Device.StoreKey` と `Device.DeleteKey` は、`TPM_RH.OWNER` などの階層のもとで、鍵またはキーブロブを永続ストレージ (NV) に移したり削除したりします。 +- ロードされた TPM オブジェクトは、解放するまで TPM 内にロードされたままです。使い終わったら、`Key`、`KeyBlob`、`Session` を指定して `Device.UnloadHandle` を呼び出してください。`Dispose()` が解放するのは、マネージドのラッパーとそのネイティブメモリだけです。 +- `Session` は `StartAuth(device, parentKey, encDecAlg)` で開始します。`encDecAlg` は `TPM2_Alg.NULL`、`CFB`、`XOR` のいずれかです。HMAC セッションを開始し、認可スロット 1 (または `Session(int index)` で指定したインデックス) に割り当て、パラメータ暗号化を有効にします。終了するには `StopAuth(device)` を呼び出します。`Device.StartSession`、`SetAuthSession`、`ClearAuthSession` は、その内部で使われる低レベルの呼び出しです。 + +### Template と Csr + +`Template` はネイティブの鍵テンプレートを設定します。`GetKeyTemplate_RSA`、`GetKeyTemplate_ECC`、`GetKeyTemplate_Symmetric`、EK、SRK、AIK 用のバリアント (`GetKeyTemplate_RSA_EK`、`GetKeyTemplate_ECC_EK`、`GetKeyTemplate_RSA_SRK`、`GetKeyTemplate_ECC_SRK`、`GetKeyTemplate_RSA_AIK`、`GetKeyTemplate_ECC_AIK`)、`SetKeyTemplate_Unique` があります。 + +証明書要求を 1 回の呼び出しで作成するには、サブジェクト文字列、鍵用途文字列、`X509_Format` を指定して `Device.GenerateCSR` を使用します。より細かく制御するには、`SetSubject`、`SetKeyUsage`、`SetCustomExtension` で `Csr` を構築し、`MakeAndSign` を呼び出します。拡張版のオーバーロードで `selfSign` 引数に 0 以外を指定すると、要求ではなく自己署名証明書が得られます。 + +### その他の Device メソッド + +`SelfTest`、`GetRandom`、`RsaEncrypt`、`RsaDecrypt`、`SignHashScheme`、`VerifyHashScheme`、`GetHandleValue` も `Device` にあります。各パラメータについては `wolfTPM.cs` の XML コメントを参照してください。 + +### 使用例 + +この例では、ストレージルート鍵を作成し、その配下に RSA 鍵を作成してロードし、ダイジェストに署名して署名を検証します。`wolfTPM-tests.cs` で使われているパターンに従っています。 + +```csharp +using System; +using wolfTPM; + +class Example +{ + static void Main() + { + using (Device device = new Device()) + using (Key srk = new Key()) + using (KeyBlob blob = new KeyBlob()) + using (Template template = new Template()) + { + try + { + device.SelfTest(); + device.CreateSRK(srk, TPM2_Alg.RSA, "StorageKeyAuth"); + + template.GetKeyTemplate_RSA((ulong)( + TPM2_Object.sensitiveDataOrigin | + TPM2_Object.userWithAuth | + TPM2_Object.decrypt | + TPM2_Object.sign | + TPM2_Object.noDA)); + + device.CreateKey(blob, srk, template, "MyKeyAuth"); + device.LoadKey(blob, srk); + + byte[] digest = new byte[32]; + device.GetRandom(digest); + + byte[] sig = new byte[256]; + int sigSz = device.SignHashScheme(blob, digest, sig, + TPM2_Alg.RSASSA, TPM2_Alg.SHA256); + Console.WriteLine("Signature is {0} bytes", sigSz); + + int rc = device.VerifyHashScheme(blob, sig, digest, + TPM2_Alg.RSASSA, TPM2_Alg.SHA256); + Console.WriteLine(rc == (int)Status.TPM_RC_SUCCESS ? + "Signature verified" : "Signature invalid"); + + device.UnloadHandle(blob); + device.UnloadHandle(srk); + } + catch (WolfTpm2Exception e) + { + Console.WriteLine("TPM error: " + e.Message); + } + } + } +} +``` + +## 関連項目 + +- [SWTPM](system-interfaces.md) +- [Build Options](build-options.md) +- [Rust Wrapper](rust-wrapper.md) diff --git a/docs/ja/embedded-integrations.md b/docs/ja/embedded-integrations.md new file mode 100644 index 00000000..972d9010 --- /dev/null +++ b/docs/ja/embedded-integrations.md @@ -0,0 +1,522 @@ +# 組み込み向け統合 + +このページでは、wolfTPM に同梱されているプラットフォームおよび IDE 向けの統合をまとめています。対象は Espressif ESP-IDF、Zephyr、QNX、IAR Embedded Workbench、Visual Studio、Das U-Boot です。STM32 Cube Pack については [STM32CubeIDE](stm32cube.md) を参照してください。 + +## Espressif ESP-IDF + +Espressif 向けプロジェクトは `IDE/Espressif` にあります。wolfTPM 向けの Wolf 固有の設定は、通常 `[project]/components/wolfssl/include` にある wolfSSL の `user_settings.h` ファイルに記述されています。 + +ESP-IDF が利用可能なシェルからビルドします (ここでは VisualGDB で v5.2 を使用する例を示します)。 + +```sh +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM/IDE/Espressif + +# set your path to ESP-IDF +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.2 + +. ${WRK_IDF_PATH}/export.sh +idf.py build +``` + +### メモリ + +当初の最小メモリ要件は 35KB のスタックです。`sdkconfig.defaults` を参照してください。現在割り当てられているメモリは 50960 です。 + +### ピン割り当て (I2C) + +既定では次のピン割り当てが使用されます。`menuconfig` で変更できます。 + +| | SDA | SCL | +| --- | --- | --- | +| ESP I2C Master | I2C_MASTER_SDA | I2C_MASTER_SCL | +| TPM2 Device | SDA | SCL | + +`I2C_MASTER_SDA` と `I2C_MASTER_SCL` の既定値については、`menuconfig` の `Example Configuration` を参照してください。ドライバーが内部プルアップを有効にするため、SDA と SCL に外付けのプルアップ抵抗は不要です。 + +### I2C のトラブルシューティング + +- I2C トランザクション中に UART へ出力すると、タイミングに影響してエラーが発生することがあります。 +- フラッシュ更新後に TPM モジュールがリセットされていることを確認してください。 +- 配線を確認してください。`SCL` は `SCL` に、`SDA` は `SDA` に接続します。GND も接続してください。Vcc は 3.3V のみです。 +- ESP32 側で正しいピンが接続されていることを確認してください。既定の SCL は `GPIO 19`、既定の SDA は `GPIO 18` です。 +- 他の I2C ボードと併用する前に、I2C デバイス 1 台だけでテストしてください。 +- 複数の I2C ボードを使用する場合は、適切なプルアップがあるか確認してください。データシートを参照してください。 +- TPM デバイスをもう一度リセットしてください。TPM SLB9673 評価ボードのボタンを押すか、必要に応じて TPM のピン 17 を設定します。 + +## Zephyr + +Zephyr ポートは wolfTPM のソースツリーの `zephyr` ディレクトリにあります。[Zephyr Project](https://www.zephyrproject.org/) を対象とし、次を提供します。 + +| パス | 内容 | +| --- | --- | +| `modules/lib/wolftpm` | wolfTPM ライブラリのコード | +| `modules/lib/wolftpm/zephyr/` | wolfTPM を Zephyr モジュールとして使うための設定ファイルと CMake ファイル | +| `modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_caps` | wolfTPM ケイパビリティのサンプルアプリケーション | +| `modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test` | wolfTPM ラッパーテストアプリケーション | + +### Zephyr モジュールとしてセットアップする + +[Zephyr getting started guide](https://docs.zephyrproject.org/latest/develop/getting_started/index.html) に従って Zephyr プロジェクトをセットアップします。その後、`west.yml` に wolfTPM をプロジェクトとして追加します。 + +```yaml +manifest: + remotes: + # + - name: wolftpm + url-base: https://github.com/wolfssl + + projects: + # + - name: wolftpm + path: modules/lib/wolftpm + revision: master + remote: wolftpm +``` + +!!! note + wolfTPM は wolfSSL に依存するため、同じ方法で `west.yml` に wolfSSL も追加してください。 + +west のモジュールを更新します。 + +```sh +west update +``` + +これで west は wolftpm をモジュールとして認識し、その Kconfig と `CMakeLists.txt` をビルドシステムに取り込みます。 + +### ラッパーテストをビルドして実行する + +`west zephyr-export` を実行せずにアプリをビルドするには、`CMAKE_PREFIX_PATH` を Zephyr SDK の場所に設定し、`zephyr` ディレクトリからビルドします。例: + +```sh +CMAKE_PREFIX_PATH=/path/to/zephyr-sdk- west build -p always -b qemu_x86 ../modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test/ +``` + +`wolftpm_wrap_test` をビルドして実行します。 + +```sh +cd [zephyrproject] +west build -p auto -b qemu_x86 modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_test +west build -t run +``` + +### ケイパビリティサンプルをビルドして実行する + +`wolftpm_wrap_caps` をビルドして実行します。 + +```sh +cd [zephyrproject] +west build -p auto -b qemu_x86 modules/lib/wolftpm/zephyr/samples/wolftpm_wrap_caps +west build -t run +``` + +## QNX + +以下の手順では、QNX SPI ドライバー経由で wolfTPM を使用する QNX Momentics プロジェクトを作成します。ファイルは `IDE/QNX` にあります。 + +### QNX アプリケーションを作成する + +1. ライブラリ用 (`lib`) とインクルード用 (`inc`) のフォルダーを作成します。 +2. ライブラリのソースを `wolfssl` と `wolftpm` として `lib` ディレクトリに追加します。 +3. ソースとインクルードディレクトリをビルドするように Makefile を編集します。 + +``` +# wolfSSL and wolfTPM library includes/sources +INCLUDES += -I./inc -I./lib/wolftpm -I./lib/wolfssl +CCFLAGS_all += -DWOLFSSL_USER_SETTINGS -DWOLFTPM_USER_SETTINGS + +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/*.c) +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/port/arm/*.c) +SRCS += $(call wildcard, lib/wolfssl/wolfcrypt/src/port/xilinx/*.c) +SRCS += $(call wildcard, lib/wolftpm/src/*.c) + +# The QNX SPI Driver +LIBS += -lspi-master +``` + +4. すべての Wolf 固有の設定を記述する `inc/user_settings.h` を作成します。テンプレートは次のとおりです。 + +```c +#ifndef WOLF_USER_SETTINGS_H +#define WOLF_USER_SETTINGS_H + +/* TPM */ +#define WOLFTPM_AUTODETECT +#define WOLFTPM_CHECK_WAIT_STATE +#define WOLFTPM_ADV_IO /* use advanced IO HAL callback */ +#define TPM_TIMEOUT_TRIES 100000 + +/* always perform self-test (some chips require) */ +#define WOLFTPM_PERFORM_SELFTEST + +/* Reduce stack use */ +#define MAX_COMMAND_SIZE 1024 +#define MAX_RESPONSE_SIZE 1350 +#define MAX_DIGEST_BUFFER 896 + +/* Debugging */ +#if 1 + #define DEBUG_WOLFTPM + //#define WOLFTPM_DEBUG_VERBOSE + //#define WOLFTPM_DEBUG_IO + //#define WOLFTPM_DEBUG_TIMEOUT +#endif + +/* Platform */ +#define WOLFCRYPT_ONLY +#define SINGLE_THREADED +#define NO_FILESYSTEM +#define WOLFSSL_IGNORE_FILE_WARN +#define WOLFSSL_HAVE_MIN +#define WOLFSSL_HAVE_MAX + +/* Math */ +#define ECC_TIMING_RESISTANT +#define TFM_TIMING_RESISTANT +#define USE_FAST_MATH +#define FP_MAX_BITS (2 * 4096) +#define WOLFSSL_NO_HASH_RAW +#define ALT_ECC_SIZE + +/* Enables */ +#define HAVE_ECC +#define ECC_SHAMIR +#define HAVE_AESGCM +#define GCM_TABLE_4BIT + +/* Disables */ +#define NO_MAIN_DRIVER +#define NO_WOLFSSL_MEMORY +#define NO_ASN +#define NO_ASN_TIME +#define NO_CODING +#define NO_CERTS +#define NO_PSK + +#define NO_PWDBASED +#define NO_DSA +#define NO_RC4 +#define NO_MD4 +#define NO_MD5 +#define NO_SHA +#define NO_HC128 +#define NO_RABBIT +#define NO_DES3 + +#endif /* !WOLF_USER_SETTINGS_H */ +``` + +5. wolfTPM の HAL には、`tpm_io.c` をそのまま使用するか、必要な HAL インターフェースを自身の `.c` ファイルにコピーします。[HAL I/O Callback](hal-io-callback.md) を参照してください。 +6. wolfTPM のサンプルコードを自身の `.c` ファイルに追加します。 +7. 以下の QNX BSP SPI マスターパッチの適用を検討してください。これにより、チップセレクトをアサートしたまま複数の呼び出しを実行できるようになります。これは SPI のウェイトステートに必要です。 + +### 手動チップセレクト用の QNX SPI マスターパッチ + +次の QNX BSP ファイルを編集します。 + +1. `bsp/src/hardware/spi/xzynq/aarch64/dll.le.zcu102/xzynq_spi.c`: + +```diff +@@ -442,7 +442,7 @@ static void xzynq_setup(xzynq_spi_t *dev, uint32_t device) + spi_debug1("%s: CONFIG_SPI_REG = 0x%x", __func__, dev->ctrl[id]); + #endif + +- if(dev->fcs) { ++ if(dev->fcs || (devlist[id].cfg.mode & SPI_MODE_MAN_CS)) { + out32(base + XZYNQ_SPI_CR_OFFSET, dev->ctrl[id] | XZYNQ_SPI_CR_MAN_CS); + } else { + out32(base + XZYNQ_SPI_CR_OFFSET, dev->ctrl[id]); +@@ -621,7 +621,7 @@ void *xzynq_xfer(void *hdl, uint32_t device, uint8_t *buf, int *len) + reset = 1; + } + +- if(!dev->fcs) { ++ if(!dev->fcs && !(devlist[id].cfg.mode & SPI_MODE_MAN_CS)) { + xzynq_spi_slave_select(dev, id, 0); + } +``` + +2. `bsp/src/hardware/spi/xzynq/config.c`: + +```diff +@@ -72,6 +73,16 @@ int xzynq_cfg(void *hdl, spi_cfg_t *cfg, int cs) + /* Enable ModeFail generation */ + ctrl |= XZYNQ_SPI_CR_MFAIL_EN; + ++ if (cfg->mode & SPI_MODE_MAN_CS) ++ ctrl |= XZYNQ_SPI_CR_MAN_CS; /* enable manual CS mode */ ++ ++ if (cfg->mode & SPI_MODE_CLEAR_CS) { ++ /* make sure all chip selects are de-asserted */ ++ /* set all CS bits high to de-assert */ ++ out32(base + XZYNQ_SPI_CR_OFFSET, ++ in32(base + XZYNQ_SPI_CR_OFFSET) | XZYNQ_SPI_CR_CS); ++ } ++ +``` + +3. `target/qnx7/usr/include/hw/spi-master.h`: + +```diff +@@ -71,6 +71,8 @@ typedef struct { + #define SPI_MODE_RDY_LEVEL (2 << 14) /* Low level signal */ + #define SPI_MODE_IDLE_INSERT (1 << 16) ++#define SPI_MODE_MAN_CS (1 << 17) /* Manual Chip select */ ++#define SPI_MODE_CLEAR_CS (1 << 18) /* Clear all chip selects (used with SPI_MODE_MAN_CS) */ + + #define SPI_MODE_LOCKED (1 << 31) /* The device is locked by another client */ +``` + +ご質問は support@wolfssl.com までメールでお問い合わせください。 + +## IAR-EWARM + +`IDE/IAR-EWARM` ディレクトリには、TPM 2.0 ラッパー API 向けの IAR Embedded Workbench for ARM プロジェクトが含まれています。README がないため、以下の内容はプロジェクトファイルから確認したものです。 + +| パス | 内容 | +| --- | --- | +| `ewarm-tpm2.eww` | IAR ワークスペース | +| `ewarm-tpm2.ewp` | IAR プロジェクト | +| `source/main.c` | アプリケーションのエントリポイント | +| `source/tpm_main.c` | `wolftpm/tpm2.h` と `wolftpm/tpm2_wrap.h` を使用する TPM サンプルコード | +| `header/tpm_main.h` | サンプルコード用のヘッダー | + +ビルドするには、IAR Embedded Workbench で `ewarm-tpm2.eww` を開きます。このサンプルは、ストレージ鍵 (`0x81000000`)、RSA 鍵 (`0x81000010`)、RSA 公開鍵 (`0x81000011`)、および NV 証明書インデックス (`0x01800000`) に固定のハンドルを使用します。 + +### IAR のプロジェクト設定 + +以下の設定は `ewarm-tpm2.ewp` から確認したものです。プロジェクトは ARM ツールチェーンを使用し、Debug と Release の構成があります。 + +| 設定 | 値 | +| --- | --- | +| インクルードパス | `$PROJ_DIR$\..\..` (wolfTPM のルート。`#include ` を解決するため) と `$PROJ_DIR$\header` | +| Debug のプリプロセッサ定義 | `WOLFTPM2_NO_WOLFCRYPT` | +| Release のプリプロセッサ定義 | `NDEBUG` | +| `lib/wolftpm` グループの wolfTPM ソース | `src/tpm2.c`、`src/tpm2_packet.c`、`src/tpm2_tis.c`、`src/tpm2_wrap.c` | +| アプリケーションのソース | `source/main.c`、`source/tpm_main.c` | + +このプロジェクトは wolfSSL のソースやインクルードパスを追加せず、`WOLFTPM_USER_SETTINGS` も定義しません。Debug 構成では `WOLFTPM2_NO_WOLFCRYPT` により wolfCrypt なしで wolfTPM をビルドします。Release 構成ではこれが定義されないため、Release ビルドでは wolfSSL のヘッダーとソースをプロジェクトに追加する必要があります。お使いのターゲット向けの wolfSSL のビルド方法に合わせて、インクルードパスと定義を調整してください。 + +!!! note + プロジェクトファイルにはデバイスやコアが設定されていません。ビルドの前に、Options、General Options、Target でターゲットデバイスを選択してください。このプロジェクトファイルは IAR EWARM 8.30.1 (ビルド 17146) で最後に保存されたものです。他の IAR バージョンはリポジトリに記録されていないため、動作確認済みのバージョンとしては記載していません。 + +### IAR の HAL + +このプロジェクトは `src/tpm2_tis.c` をコンパイルするため、標準の TPM TIS レイヤーと IO コールバック HAL を使用します ([HAL I/O Callback](hal-io-callback.md) を参照)。すぐに使える SPI ドライバーは含まれていません。`source/tpm_main.c` はスタブのコールバック `TPM2_IoCb` を定義しており、`TODO` の行を独自の SPI 転送ルーチンの呼び出しに置き換えるまで `TPM_RC_FAILURE` を返します。このコールバックは `TPM2_Cust_Example` 内で `wolfTPM2_Init` に渡されます。 + +サンプルは続いて、永続ストレージ鍵 `0x81000000` を読み取ります。存在しない場合は、RSA プライマリストレージ鍵を作成して永続化し、`0x81000010` の RSA 鍵についても同様に処理します。パスワードには `ThisIsMyStorageKeyAuth` と `ThisIsMyKeyAuth` を使用し、終了前に両方のハンドルをアンロードして `wolfTPM2_Cleanup` を呼び出します。 + +## Visual Studio + +`IDE/VisualStudio` ディレクトリには、wolfSSL、wolfTPM、およびいくつかのサンプルをビルドするプロジェクトを含む Visual Studio ソリューション `wolftpm.sln` があります。プロジェクトは `wolfssl.vcxproj`、`wolftpm.vcxproj`、`wrap_test.vcxproj`、`wolfcrypt_test.vcxproj`、`tls_server.vcxproj` です。ソリューションとプロジェクトは Visual Studio 2015 をベースにしており、開く際に新しいバージョンへ再ターゲットできます。 + +すべてのビルド設定は `IDE/VisualStudio/user_settings.h` にあります。プロジェクトは、`wolftpm` と `wolfssl` の各ディレクトリが隣り合って配置されていることを前提としています。 + +このソリューションは、wolfSSL の Web サイトから入手できる FIPS Ready バンドルに対応しています。使用するには、`user_settings.h` の `#if 0` となっている FIPS セクションを有効にします。実行時に `fips_test.c` で FIPS の整合性チェックを設定する方法については、wolfSSL ソース内の `wolfssl/IDE/WIN10/README.txt` を参照してください。 + +### ビルド手順 + +1. `wolftpm` と `wolfssl` のソースディレクトリを隣り合わせに配置します。プロジェクトは `../../` や `../../../wolfssl/` といったインクルードパスを使用します。 +2. `IDE/VisualStudio/wolftpm.sln` を開きます。プロジェクトはプラットフォームツールセット `v110` を指定しているため、Visual Studio は、インストール済みのツールセットへの再ターゲットを求めます。 +3. 構成 (`Debug`、`Release`、`DLL Debug`、`DLL Release`) とプラットフォーム (`Win32` または `x64`) を選択します。 +4. ソリューションをビルドします。`wolftpm` は `wolfssl` プロジェクトを参照しているため、wolfSSL が先にビルドされます。 + +wolfTPM の CI ワークフローは、`v142` ツールセットを指定した MSBuild でコマンドラインからソリューションをビルドします。`x64` の `Debug` 構成を使用しています。 + +```sh +msbuild /m /p:PlatformToolset=v142 /p:Platform=x64 /p:Configuration=Debug wolftpm\IDE\VisualStudio\wolftpm.sln +``` + +ソリューションには 5 つのプロジェクトがあります: `wolfssl`、`wolftpm`、`wolfcrypt_test`、`wrap_test` (`examples/wrap/wrap_test.c` からビルド)、`tls_server` です。 + +### user_settings.h の役割 + +`wolftpm` プロジェクトは `WOLFSSL_USER_SETTINGS` と `WOLFTPM_USER_SETTINGS` を定義するため、両方のライブラリは生成された `options.h` の代わりに `IDE/VisualStudio/user_settings.h` を読み込みます。このファイルは、TLS 1.2 と 1.3 を使用する wolfTPM のテンプレートです。wolfTPM に関わる主な設定は次のとおりです。 + +| 定義 | 目的 | +| --- | --- | +| `WOLFTPM_WINAPI` | `_WIN32` が定義されている場合に設定されます。Windows TBS トランスポートを選択します。 | +| `WOLFSSL_AES_CFB` | TPM のパラメータ暗号化に必要です。 | +| `WOLFSSL_PUBLIC_MP` | `mp_` 数学関数を公開します。TPM の ECC シークレット暗号化に必要です。 | +| `WOLFTPM_AUTODETECT` | 安全なデフォルト設定で、あらゆる TPM モデルに対応します。 | +| `WOLF_CRYPTO_CB` と `HAVE_PK_CALLBACKS` | TPM 上で暗号処理を実行するためのコールバックです。 | +| `WOLFSSL_CERT_GEN`、`WOLFSSL_CERT_REQ`、`WOLFSSL_CERT_EXT` | 証明書と CSR の生成に使用します。 | + +このファイルには、無効化された `#if 0` の FIPS セクション、数学オプション (FIPS なしの場合は `WOLFSSL_SP_MATH_ALL`)、`DEBUG_WOLFSSL` が有効なデバッグセクションもあります。 + +### Windows の TPM トランスポート + +Visual Studio のプロジェクトは、SPI やシミュレータではなく、Windows TBS (TPM Base Services) インターフェースを使用します。Windows では `user_settings.h` が `WOLFTPM_WINAPI` を定義し、`wolftpm.vcxproj` は `src/tpm2_winapi.c` をコンパイルし、サンプルプロジェクト (`wrap_test`、`tls_server`) と `wolftpm` の DLL 構成は `tbs.lib` をリンクします。このモードでは、wolfTPM は `tbs.h` の TBS API を呼び出します。IO コールバックやユーザーコンテキストは受け付けないため、`wolfTPM2_Init` にはどちらも `NULL` を渡してください。NV アクセスの制限とサンプルの実行方法については、[Windows TBS](system-interfaces.md) を参照してください。 + +## U-Boot + +wolfTPM は Das U-Boot を実験的にサポートしており、次の機能があります。 + +- TPM との通信に U-Boot のソフトウェア SPI ドライバーを使用します。 +- 内部の TIS レイヤーを通じて TPM 2.0 ドライバーの機能を実装します。 +- すべての TPM 2.0 コマンドへのネイティブ API アクセスを提供します。 +- 一般的な TPM 2.0 操作向けのラッパー API を含みます。 +- 2 つの統合パスをサポートします。 + - `__linux__`: `tpm2_linux.c` を通じて既存の tpm インターフェースを使用します。 + - `__UBOOT__`: `tpm_io_uboot.c` を通じた直接の SPI 通信を行います。 + +サンプルファイルは `examples/u-boot` にあります。 + +### U-Boot コマンド + +これらのコマンドは `wolftpm` インターフェースから利用できます。 + +基本コマンド: + +| コマンド | 説明 | +| --- | --- | +| `help` | ヘルプテキストを表示します。 | +| `device [num device]` | すべてのデバイスを表示するか、指定したデバイスを設定します。 | +| `info` | TPM に関する情報を表示します。 | +| `state` | 利用可能な場合に、TPM の内部状態を表示します。 | +| `autostart` | TPM を初期化し、Startup(clear) を実行し、完全なセルフテストシーケンスを実行します。 | +| `init` | ソフトウェアスタックを初期化します。最初のコマンドでなければなりません。 | +| `startup []` | TPM2_Startup コマンドを発行します。`` は `TPM2_SU_CLEAR` (状態をリセット) または `TPM2_SU_STATE` (状態を保持) です。`[]` は "off" を指定するオプションのシャットダウンです。 | +| `self_test ` | TPM の機能をテストします。`` は "full" (すべてのテスト) または "continue" (未テストのテストのみ) です。 | + +PCR 操作: + +| コマンド | 説明 | +| --- | --- | +| `pcr_extend []` | ダイジェストで PCR を拡張します。 | +| `pcr_read []` | PCR をメモリに読み出します。 | +| `pcr_allocate []` | PCR バンクのアルゴリズムを再構成します。 | +| `pcr_setauthpolicy` or `pcr_setauthvalue []` | PCR アクセスキーを変更します。 | +| `pcr_print` | 現在の PCR の状態を表示します。 | + +セキュリティ管理: + +| コマンド | 説明 | +| --- | --- | +| `clear ` | TPM2_Clear を発行します。`` は `TPM2_RH_LOCKOUT` または `TPM2_RH_PLATFORM` です。 | +| `change_auth []` | 階層のパスワードを変更します。`` は `TPM2_RH_LOCKOUT`、`TPM2_RH_ENDORSEMENT`、`TPM2_RH_OWNER`、または `TPM2_RH_PLATFORM` です。 | +| `dam_reset []` | 内部エラーカウンターをリセットします。 | +| `dam_parameters []` | ディクショナリアタック軽減 (DAM) のパラメータを設定します。 | +| `caps` | TPM のケイパビリティと情報を表示します。 | + +ファームウェア管理: + +| コマンド | 説明 | +| --- | --- | +| `firmware_update ` | TPM ファームウェアを更新します。 | +| `firmware_cancel` | TPM ファームウェアの更新をキャンセルします。 | + +### U-Boot で wolfTPM を有効にする + +ボードの defconfig に次のオプションを追加します。 + +``` +CONFIG_TPM=y +CONFIG_TPM_V2=y +CONFIG_TPM_WOLF=y +CONFIG_CMD_WOLFTPM=y +``` + +あるいは、`make menuconfig` を使用して次を有効にします。 + +- Device Drivers, TPM, TPM 2.0 Support +- Device Drivers, TPM, wolfTPM Support +- Command line interface, Security commands, Enable wolfTPM commands + +### QEMU でビルドして実行する + +この手順では、TPM シミュレータを使用して、QEMU 上で wolfTPM 付きの U-Boot を実行します。 + +1. swtpm をインストールします。 + +```sh +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +./autogen.sh +make +``` + +2. U-Boot をビルドします。 + +```sh +make distclean +export CROSS_COMPILE=aarch64-linux-gnu- +export ARCH=aarch64 +make qemu_arm64_defconfig +make -j4 +``` + +3. TPM の状態ディレクトリを作成します。 + +```sh +mkdir -p /tmp/mytpm1 +``` + +4. 1 つ目のターミナルで swtpm を起動します。 + +```sh +swtpm socket --tpm2 --tpmstate dir=/tmp/mytpm1 --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --log level=20 +``` + +5. 2 つ目のターミナルで QEMU を起動します。 + +```sh +qemu-system-aarch64 -machine virt -nographic -cpu cortex-a57 -bios u-boot.bin -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis-device,tpmdev=tpm0 +``` + +6. ブート出力の例: + +``` +U-Boot 2025.07-rc1-ge15cbf232ddf-dirty (May 06 2025 - 16:25:56 -0700) + +DRAM: 128 MiB +using memory 0x46658000-0x47698000 for malloc() +Core: 52 devices, 15 uclasses, devicetree: board +Flash: 64 MiB +Loading Environment from Flash... *** Warning - bad CRC, using default environment + +In: serial,usbkbd +Out: serial,vidconsole +Err: serial,vidconsole +No USB controllers found +Net: eth0: virtio-net#32 + +Hit any key to stop autoboot: 0 +=> tpm2 help +tpm2 - Issue a TPMv2.x command + +Usage: +tpm2 [] + +device [num device] + Show all devices or set the specified device +info + Show information about the TPM. +``` + +7. コマンドの例: + +``` +=> tpm2 info +tpm_tis@0 v2.0: VendorID 0x1014, DeviceID 0x0001, RevisionID 0x01 [open] +=> tpm2 startup TPM2_SU_CLEAR +=> tpm2 get_capability 0x6 0x20e 0x200 1 +Capabilities read from TPM: +Property 0x6a2e45a9: 0x6c3646a9 +=> tpm2 pcr_read 10 0x100000 +PCR #10 sha256 32 byte content (20 known updates): + 20 25 73 0a 00 56 61 6c 75 65 3a 0a 00 23 23 20 + 4f 75 74 20 6f 66 20 6d 65 6d 6f 72 79 0a 00 23 +``` + +8. QEMU を終了するには、Ctrl-A に続けて X を押します。 + +## 関連項目 + +- [STM32CubeIDE](stm32cube.md) +- [Building](building.md) +- [System Interfaces](system-interfaces.md) +- [HAL I/O Callback](hal-io-callback.md) +- [Supported Hardware](supported-hardware.md) +- [Windows TBS](system-interfaces.md) diff --git a/docs/ja/examples-overview.md b/docs/ja/examples-overview.md new file mode 100644 index 00000000..c5b7d003 --- /dev/null +++ b/docs/ja/examples-overview.md @@ -0,0 +1,104 @@ +# サンプルの概要 + +wolfTPM のサンプルは、ネイティブの `TPM2_*` API と `wolfTPM2_*` ラッパー API の両方を使って TPM 2.0 モジュールを利用する方法を示します。サンプルはライブラリと一緒にビルドされ、インストールが成功すればそのまま実行できます。サンプルをお使いのハードウェアプラットフォームに接続するには、`tpm_io.c` の `TPM2_IoCb` 関数と [HAL I/O コールバックガイド](hal-io-callback.md)を参照してください。 + +サンプルは、テスト用に NV 上へ RSA 鍵と ECC 鍵を作成します。このとき `./examples/tpm_test.h` で定義されたハンドルを使用します(実行フラグとテスト用ハンドルを参照)。PKCS #7 と TLS のサンプルでは、テストスクリプトで生成して署名した CSR が必要です。手順は `examples/README.md` の CSR と証明書署名のセクションを参照してください。 + +一部のサンプルはベンダー固有です。たとえば ST33 や NPCT75x TPM 向けの追加 GPIO サンプルがあり、これらは該当のハードウェアでのみ動作します。 + +## ネイティブ API テスト + +ネイティブの `TPM2_*` API の呼び出し方を示します。 + +```sh +./examples/native/native_test +``` + +## ラッパー API テスト + +`wolfTPM2_*` ラッパー API の呼び出し方を示します。 + +```sh +./examples/wrap/wrap_test +``` + +## 暗号プリミティブのサンプル + +一般的な TPM 暗号操作を扱う、小さく焦点を絞ったサンプルです。 + +```sh +./examples/wrap/getrandom [bytes] +./examples/wrap/hash [-sha384|-sha512] +./examples/wrap/encrypt_decrypt [-aescfb|-aesctr|-aescbc] +./examples/keygen/ecdh +``` + +| コマンド | 内容 | +| --- | --- | +| `getrandom [bytes]` | TPM の RNG から乱数バイトを取得します(デフォルトは 32)。 | +| `hash` | TPM のハッシュシーケンスでメッセージをハッシュします。デフォルトは SHA-256 で、`-sha384` または `-sha512` で変更できます。 | +| `encrypt_decrypt` | 対称鍵による暗号化と復号の往復テストです。デフォルトは AES-CFB です。 | +| `ecdh` | ECDH (P-256) 鍵共有を行い、共有秘密を生成します。 | + +!!! note + 多くの TPM は、輸出規制のため `TPM2_EncryptDecrypt` を完全に無効にしています。`encrypt_decrypt` サンプルは、このコマンドが利用できない場合は正常にスキップします。 + +## パラメータ暗号化 + +サンプルでパラメータ暗号化を有効にするには、AES-CFB モードなら `-aes`、XOR モードなら `-xor` を使用します。パラメータ暗号化に対応しているのは一部の TPM コマンドとレスポンスのみです。`TPM2_` API のエントリでフラグに `CMD_FLAG_ENC2` または `CMD_FLAG_DEC2` が設定されている場合、そのコマンドはパラメータ暗号化または復号を使用します。 + +暗号化できるのは TPM コマンドの最初のパラメータだけで、その型は `TPM2B_DATA` である必要があります。たとえば TPM 鍵のパスワード認証や、TPM2.0 Quote の qualifying data が該当します。リクエストとレスポンスは、同時にも別々にも暗号化できます。これは `sessionAttributes` で制御します。 + +* `TPMA_SESSION_decrypt`: コマンドのリクエスト用 +* `TPMA_SESSION_encrypt`: コマンドのレスポンス用 + +どちらか一方だけ、または同じ認可セッションで両方を設定できます。どれを使うかは開発者が決めます。 + +パラメータ暗号化を使用するサンプルは次のとおりです。 + +* 暗号化した認可値を使う鍵生成。[鍵管理](key-management.md)を参照してください。 +* 暗号化した NV 認可を使う、鍵用のセキュアボールト。[シーリングと NVRAM](sealing-and-nvram.md)を参照してください。 +* 暗号化したユーザーデータを使う TPM2.0 Quote。Quote に指定する qualifying data は、署名される Quote 構造体に含まれる任意のデータです。パラメータ暗号化を使うと、ホストはこのデータを暗号化した状態で TPM に送るため、中間者攻撃から保護されます。[アテステーション](attestation.md)を参照してください。 + +### ポスト量子セッション鍵 (v1.85) + +v1.85 の PQC 対応 TPM では、パラメータ暗号化セッションの鍵として、RSA や ECC のストレージ鍵の代わりにポスト量子プライマリ鍵を使用できます。ML-KEM は復号に対応しており、セッションの salt 鍵として使用します。ML-DSA は署名専用で、セッションの bind 鍵として使用します。RSA や ECC のストレージ鍵が必要な場合(たとえば作成する子鍵の親として)は、従来どおりです。 + +ML-KEM 鍵でセッションを salt するには `-mlkem[=512|768|1024]` を、ML-DSA 鍵にバインドするには `-mldsa[=44|65|87]` を指定します。これらのフラグは `wrap_test`、`pcr/quote`、`nvram/store`、`nvram/counter` で受け付けられます。`keygen` サンプルでは、`-mlkem` と `-mldsa` が子鍵の種類の選択に使われるため、代わりに `-paramkey=mlkem[=...]` と `-paramkey=mldsa[=...]` を使用します。 + +```sh +./examples/wrap/wrap_test -aes -mlkem=768 +./examples/pcr/quote 16 quote.blob -ecc -xor -mldsa=65 +./examples/nvram/counter -aes -mldsa=65 +./examples/keygen/keygen keyblob.bin -ecc -aes -paramkey=mlkem=768 +``` + +## 実行フラグとテスト用ハンドル + +サンプルで使用するハンドルは `./examples/tpm_test.h` で定義されています。 + +| 定義 | 値 | 用途 | +| --- | --- | --- | +| `TPM2_DEMO_STORAGE_KEY_HANDLE` | `0x81000200` | 永続ストレージ鍵 (RSA) | +| `TPM2_DEMO_STORAGE_EC_KEY_HANDLE` | `0x81000201` | 永続ストレージ鍵 (ECC) | +| `TPM2_DEMO_PERSISTENT_KEY_HANDLE` | `0x81000202` | 汎用の永続鍵 | +| `TPM2_DEMO_HMAC_KEY_HANDLE` | `0x81000210` | 永続 HMAC 鍵 | + +RSA と ECC のテスト用の鍵と証明書は、ベースアドレスにインデックスオフセットを加えた値を使用します。 + +| 定義 | インデックス | ハンドル | 種類 | +|----------------------------------------|----------|----------------------------|----------------------| +| `TPM2_DEMO_RSA_KEY_HANDLE` | `0x20` | `0x81000000 + 0x20` | 永続鍵 | +| `TPM2_DEMO_RSA_CERT_HANDLE` | `0x20` | `0x01800000 + 0x20` | NV インデックス | +| `TPM2_DEMO_ECC_KEY_HANDLE` | `0x21` | `0x81000000 + 0x21` | 永続鍵 | +| `TPM2_DEMO_ECC_CERT_HANDLE` | `0x21` | `0x01800000 + 0x21` | NV インデックス | + +!!! warning + TLS のサーバーとクライアントのサンプルを同一マシンで実行するには、`WOLFTPM_TIS_LOCK` を有効にして wolfTPM をビルドしてください(`./configure --enable-tislock`)。これにより名前付きセマフォが追加され、プロセス間での SPI デバイスへの同時アクセスが保護されます。 + +## 関連項目 + +* [鍵管理](key-management.md) +* [アテステーション](attestation.md) +* [シーリングと NVRAM](sealing-and-nvram.md) +* [HAL I/O コールバックガイド](hal-io-callback.md) diff --git a/docs/ja/firmware-update.md b/docs/ja/firmware-update.md new file mode 100644 index 00000000..43ff5dcb --- /dev/null +++ b/docs/ja/firmware-update.md @@ -0,0 +1,368 @@ +# ファームウェアアップデート + +wolfTPM は、一部の TPM 2.0 モジュールのファームウェアを更新できます。`--enable-firmware` を指定して configure すると、サンプルとライブラリのサポートが有効になります。サポート対象は次のとおりです。 + +- Infineon SLB9672 (SPI) および SLB9673 (I2C) TPM 2.0 モジュール。Infineon はファームウェアアップデートをオープンソース化しています。 +- STMicroelectronics ST33KTPM TPM 2.0 モジュール。第 1 世代ファームウェア (RSA 署名付きマニフェスト)、512 未満の第 9 世代ファームウェア (ECDSA 署名付きマニフェスト)、512 以上の第 9 世代ファームウェア (LMS 署名が必須) をサポートします。 + +ファームウェアアップデート用のプログラムは `examples/firmware/` にあります: `ifx_fw_extract.c`、`ifx_fw_update.c`、`st33_fw_update.c`、およびポリシーヘルパーの `firmware_policy.c` です。 + +## Infineon ファームウェア (抽出とアップデート) + +### ファームウェアの抽出 + +Infineon はファームウェアを .bin ファイル (例: `TPM20_15.23.17664.0_R1.BIN`) としてリリースします。この .bin には、16 バイトの GUID ヘッダー、キーグループごとの 1 つ以上のマニフェスト、およびファームウェアが含まれます。一般的なマニフェストは 3KB、ファームウェアは 920KB です。 + +ホスト側ツール `ifx_fw_extract` は、TPM のアップグレードに必要なマニフェストとファームウェアのデータファイルを抽出します。 + +```sh +# Build host tool +make + +# Help +./ifx_fw_extract --help +Usage: + ifx_fw_extract + ifx_fw_extract + +# Find key groups in .bin +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 + +# Extract manifest and firmware data files for key group +./ifx_fw_extract TPM20_26.13.17770.0_R1.BIN 7 TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Reading TPM20_26.13.17770.0_R1.BIN +Found group 00000007 +Chosen group found: 00000007 +Manifest size is 3224 +Data size is 934693 +Writing TPM20_26.13.17770.0_R1.MANIFEST +Writing TPM20_26.13.17770.0_R1.DATA +``` + +### ファームウェアのアップデート + +`ifx_fw_update` ツールは、マニフェスト (ヘッダー) とファームウェアデータファイルを使用します。 + +TPM にはキーグループ ID を取得するためのベンダー機能があります。この値は `wolfTPM2_GetCapabilities` を呼び出すと `WOLFTPM2_CAPS.keyGroupId` に格納されます。この値は、抽出ツールに指定した `keygroup_id` と一致する必要があります。 + +```sh +# Help +./ifx_fw_update --help +Infineon Firmware Update Usage: + ./ifx_fw_update (get info) + ./ifx_fw_update --abandon (cancel) + ./ifx_fw_update --policytest (safe policy auth self-test) + ./ifx_fw_update [policy opts] + ./ifx_fw_update (default auth) +Policy options (caller-supplied authorization): + --policy provision+satisfy a PolicyCommandCode + --policyor provision+satisfy a PolicyOR (multi-branch) + --sha256|--sha384|--sha512 policy hash (default SHA-256) + +# Run without arguments to display the current firmware information, +# including key group id and operational mode +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) + +# Run with manifest and firmware files +./ifx_fw_update TPM20_26.13.17770.0_R1.MANIFEST TPM20_26.13.17770.0_R1.DATA +Infineon Firmware Update Tool + Manifest File: TPM20_26.13.17770.0_R1.MANIFEST + Firmware File: TPM20_26.13.17770.0_R1.DATA +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1254 (255 same) +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +TPM2_FlushContext: Closed handle 0x3000000 +TPM2_StartAuthSession: handle 0x3000000, algorithm NULL +Firmware manifest chunk 1024 offset (0 / 3224), state 1 +Firmware manifest chunk 1024 offset (1024 / 3224), state 2 +Firmware manifest chunk 1024 offset (2048 / 3224), state 2 +Firmware manifest chunk 152 offset (3072 / 3224), state 0 +Firmware data chunk offset 0 +Firmware data chunk offset 1024 +Firmware data chunk offset 2048 +Firmware data chunk offset 3072 +... +Firmware data chunk offset 932864 +Firmware data chunk offset 933888 +Firmware data done +Mfg IFX (1), Vendor , Fw 0.0 (0x0) +Operational mode: After finalize or abandon, reboot required (0x4) +KeyGroupId 0x7, FwCounter 1253 (254 same) +TPM2_Shutdown failed 304: Unknown + +# Reset or power cycle TPM +./ifx_fw_update +Infineon Firmware Update Tool +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +TPM2_Startup pass +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a) +Operational mode: Normal TPM operational mode (0x0) +KeyGroupId 0x7, FwCounter 1253 (254 same) +``` + +## ST33 ファームウェアアップデート + +このサンプルを有効にするには、`--enable-st33 --enable-firmware` を指定してビルドします。 + +### ファームウェア形式の自動検出 + +ST33KTPM のファームウェアアップデートは、TPM のファームウェアバージョンから必要な形式を検出します。マニフェスト (blob0) は 33 バイトの固定ヘッダーに、ファームウェアダイジェストとそれに対する署名が続く構造のため、そのサイズは各世代が署名に使用するアルゴリズムによって決まります。 + +- 第 1 世代 (メジャーバージョン 1、例: 1.257 や 1.771): 非 LMS 形式。 + - マニフェストサイズ: 321 バイト (SHA-256 ダイジェスト、RSAPSS-2048 署名)。 + - マイナーバージョンがいくら大きくなっても、常に非 LMS です。 +- 512 未満の第 9 世代 (例: 9.257): 非 LMS 形式。 + - マニフェストサイズ: 177 バイト (SHA-384 ダイジェスト、ECDSA P-384 署名)。 +- 512 以上の第 9 世代 (例: 9.512): LMS (Leighton-Micali Signature) 形式。 + - マニフェストサイズ: 2697 バイト (埋め込みの LMS 署名を含む)。 + +LMS の要件は第 9 世代のルールであるため、TPM の capabilities から `fwVerMajor` と `fwVerMinor` の両方を参照します。このサンプルは、判定結果をファイル自体でも確認します。blob0 以降はすべて `[type][length]` レコードの連鎖で、ファイルの終端でちょうど終わります。そして、正しいマニフェストサイズだけが最終バイトに一致します。形式を手動で選択する必要はありません。 + +### パーツの識別 + +ST33TPHF2X で `TPM_PT_VENDOR_STRING_1..4` が何を返すかは、ファームウェアによって異なります。初期の 1.x ファームウェアはテキストではなくバイナリを返すため、`Vendor` フィールドは空で表示されます。後期の 1.x ファームウェアは ASCII (例: `ST33TPHF2XSPI`) を返します。この変更はファームウェア 1.771 では存在し、1.258 では存在しません。どのファームウェアで導入されたかは不明です。いずれの場合も、ファームウェアのメジャーバージョンが信頼できる識別子であり、パーツとインターフェースのラインに対応します。 + +| `fwVerMajor` | パーツライン | ファームウェアイメージの例 | +| --- | --- | --- | +| 1 | ST33TPHF2X、SPI ファームウェアライン | `TPM_ST33TPHF2XSPI_00010301.fi` | +| 2 | ST33TPHF2X、I2C ファームウェアライン | `TPM_ST33TPHF2XI2C_00020200.fi` | +| 9 | ST33KTPM2X | `TPM_ST33KTPM2X_00090200_V1.fi` | +| 10 (`0x000a`) | ST33KTPM2A | `TPM_ST33KTPM2A_000a0200.fi` | +| 11 (`0x000b`) | ST33KTPMQ | (手元になし) | + +マニフェストヘッダーにも同じバージョンが含まれます。ゼロバイトに続いて、イメージがアップグレード先とするファームウェアバージョンが `TPM_PT_FIRMWARE_VERSION_1` のレイアウトで格納されています (`00 | 00 02 02 00` は 2.512 を表します)。`st33_fw_update` は両方を表示し、メジャーバージョンが実行中のパーツと一致しないイメージは拒否します。 + +ST33 のファームウェアラインとファームウェアバージョンの関係については、[Supported hardware](supported-hardware.md) を参照してください。 + +### フィールドアップグレードのコマンドコード + +ST33 は、2 組のコマンドコードのいずれかでフィールドアップグレードを実装しています。誤った組を使用すると、マニフェストが解析される前に `TPM_RC_COMMAND_CODE` (`0x143`) が返されます。 + +| 組 | Start | Data | +| --- | --- | --- | +| 標準 TCG | `TPM_CC_FieldUpgradeStart` (`0x0000012F`) | `TPM_CC_FieldUpgradeData` (`0x00000141`) | +| ST33KTPM ベンダー | `0x2000030C` | `0x2000030D` | + +wolfTPM は、2 つの start コードについて `TPM_CAP_COMMANDS` を照会し、TPM がどちらの組を実装しているかを問い合わせます。これは確実な方法であり、パーツの対応表を必要としません。一方、ST 自身のリファレンスツールは、バージョン番号から組を推定します (実行中のファームウェアのマイナーバージョンが 256 未満の場合、またはイメージがファームウェア第 2 世代を対象とする場合は標準コード)。wolfTPM は、TPM が応答しない場合 (ファームウェアアップグレードモードに入った後がこれに該当します) や、両方の組が列挙された場合にのみ、同じルールである `wolfTPM2_ST33_FwUpgradeCommands()` にフォールバックします。 + +このプローブは重要です。ファームウェア 11.1 の ST33KTPMQ は、マイナーバージョンが 256 未満であるにもかかわらずベンダーの組しか実装していないため、バージョンのルールだけでは誤ったコードが選ばれてしまいます。 + +手動で選択する必要はありません。呼び出し側が用意したポリシーを使用する場合、`PolicyCommandCode` は実際に送信される start コードにバインドされ、`st33_fw_update` はコードが TPM から取得されたものか推定されたものかを報告します。 + +ファームウェアファイルを指定せずに `st33_fw_update` を実行すると、接続されているパーツが 4 つのコードのうちどれを実装しているかも、`TPM_CAP_COMMANDS` から読み取って報告します。これは読み取り専用であり、新しいパーツで `TPM_RC_COMMAND_CODE` が発生した場合の最も手早い診断方法です。 + +```sh +./st33_fw_update +... +Field upgrade command set: + 0x0000012f FieldUpgradeStart (standard): implemented + 0x00000141 FieldUpgradeData (standard): implemented + 0x2000030c FieldUpgradeStartVendor (ST33KTPM): not implemented + 0x2000030d FieldUpgradeDataVendor (ST33KTPM): not implemented +``` + +既知のファミリー以外のファームウェアメジャーバージョンは、推測せずに不明として扱われます。その場合、マニフェストサイズは断定されず、ツールはサイズをイメージから取得すると報告し、`st33_detect_blob0` のブロックチェーン検証がファイル自体から実際のサイズを確定します。これにより、ST33KTPMQ のような新しいラインのパーツが、該当しないルールを理由にイメージを拒否されることはありません。 + +### ファームウェアのアップデート + +`st33_fw_update` ツールはファームウェア形式を自動的に検出します。 + +```sh +# Help +./st33_fw_update --help +ST33 Firmware Update Usage: + ./st33_fw_update (get info) + ./st33_fw_update --abandon (cancel) + ./st33_fw_update --policytest (safe policy auth self-test) + ./st33_fw_update [policy opts] + ./st33_fw_update (default password auth) +Policy options (caller-supplied authorization): + --policy provision+satisfy a PolicyCommandCode + --policyor provision+satisfy a PolicyOR (multi-branch) + --sha256|--sha384|--sha512 policy hash (default SHA-256) + +Firmware format is auto-detected from TPM firmware version and the file: + - Generation 1 (e.g. 1.771): Non-LMS format (321 byte manifest) + - Generation 9 below 512: Non-LMS format (177 byte manifest) + - Generation 9 at 512 and above: LMS format (2697 byte manifest) + +# Run without arguments to display the current firmware information. +# This capture is an ST33TPHF2XSPI, which implements only the vendor codes. +./st33_fw_update +ST33 Firmware Update Tool +TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e +TPM2_Startup pass +Mfg STM (2), Vendor , Fw 1.258 (0x0) +Firmware version details: Major=1, Minor=258, Vendor=0x0 +Part line: ST33TPHF2X (SPI firmware line) +Firmware generation: 1 +Firmware update: Non-LMS format required (321 byte manifest) +Field upgrade command set: + 0x0000012f FieldUpgradeStart (standard): not implemented + 0x00000141 FieldUpgradeData (standard): not implemented + 0x2000030c FieldUpgradeStartVendor (ST33KTPM): implemented + 0x2000030d FieldUpgradeDataVendor (ST33KTPM): implemented + +# Run with firmware file (format auto-detected from TPM version) +./st33_fw_update TPM_ST33KTPM2X_00090200_V1.fi +ST33 Firmware Update Tool + Firmware File: TPM_ST33KTPM2X_00090200_V1.fi +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0) +Firmware version details: Major=9, Minor=257, Vendor=0x0 +Part line: ST33KTPM2X +Firmware generation: 9 below 512 +Firmware update: Non-LMS format required (177 byte manifest) + Format: Non-LMS (blob0 177 bytes, verified against the block chain) +Firmware Update: + Total file size: 364290 bytes + Manifest (blob0): 177 bytes + Firmware data: 364113 bytes + Image targets firmware: 9.512 (ST33KTPM2X) + Command codes: start 0x2000030c, data 0x2000030d +... +Firmware update completed successfully. +Please reset or power cycle the TPM. +``` + +!!! note + ファームウェアファイルは公開できないため、STMicroelectronics から別途入手する必要があります。 + +### LMS ファームウェア + +512 以上のファームウェアを搭載した第 9 世代の TPM では、LMS 形式が必須です。 + +```sh +./st33_fw_update ST33KTPM2X_FAC_00090200_V2.fi +ST33 Firmware Update Tool + Firmware File: ST33KTPM2X_FAC_00090200_V2.fi +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 3 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.512 (0x0) +Firmware version details: Major=9, Minor=512, Vendor=0x0 +Firmware generation: 9 at 512 and above +Firmware update: LMS format required (2697 byte manifest) + Format: LMS (blob0 2697 bytes, verified against the block chain) +Firmware Update: + Total file size: 360092 bytes + Manifest (blob0): 2697 bytes + Firmware data: 357395 bytes +... +Firmware update completed successfully. +Please reset or power cycle the TPM. +``` + +### アップデートのキャンセル + +```sh +./st33_fw_update --abandon +ST33 Firmware Update Tool +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +Mfg STM (2), Vendor ST33KTPM2X, Fw 9.257 (0x0) +Firmware version details: Major=9, Minor=257, Vendor=0x0 +Firmware generation: 9 below 512 +Firmware update: Non-LMS format required (177 byte manifest) +Firmware Update Abandon: +Success: Please reset or power cycle TPM +``` + +同じツールはメインの README にも短いブロックで説明されています: `./examples/firmware/st33_fw_update` はファームウェア情報を表示し、`--abandon` は進行中のアップデートをキャンセルし、`` ファイルを渡すと、TPM のファームウェアバージョンから形式を自動検出してアップデートを実行します。 + +## ポリシーベースの認可 (上級) + +デフォルトでは、wolfTPM はファームウェアアップデートの start コマンドに対するプラットフォーム階層の認可を内部で管理します。Infineon では、プラットフォームのプライマリポリシーに `PolicyCommandCode(TPM_CC_FieldUpgradeStartVendor)` ポリシーをインストールして満たします。ST33 では、空のプラットフォームパスワードによるパスワード認可 (`TPM_RS_PW`) を使用します。これは、プラットフォーム階層がデフォルト (空) の認可であることを前提としています。 + +ファームウェアアップグレードを独自のプラットフォームポリシー (例: 署名付きポリシーのチェック、PCR の状態、複数分岐の `PolicyOR`) で制御している環境では、`wolfTPM2_FirmwareUpgradeHash_ex()` を使用して、すでに満たされた認可セッションを渡すことができます。セッションを渡した場合の動作は次のとおりです。 + +- **Infineon**: ライブラリはプラットフォームのプライマリポリシーを上書きしません。プラットフォームの `authPolicy` は自分で (`authHandle = TPM_RH_PLATFORM` を指定した `TPM2_SetPrimaryPolicy` を通じて、SHA2-256 または SHA2-512 を使用して) プロビジョニングし、それを満たすセッションを渡します。これはライブラリに当てはまります。`--policy` と `--policyor` のサンプルモードは、それ自体がそのような呼び出し側であり、そのヘルパー (`examples/firmware/firmware_policy.c`) は、自ら生成したダイジェストでプラットフォームの `authPolicy` を上書きします。プラットフォーム階層に必要なポリシーがすでに設定されているシステムでは、これらのモードを実行しないでください。 +- **ST33**: 渡されたセッションが、デフォルトの `TPM_RS_PW` パスワード認可を置き換えます。 + +サポートされるセッションの要件: ベンダーの `FieldUpgradeStart` コマンドは、セッションハンドルのみを含む認可領域とともに送信されます。このとき `nonceCaller` は空、セッション属性はゼロ、HMAC は空です。したがって、渡すセッションは、auth 値を持たず、パラメータ暗号化も行わない、ソルトなし・バインドなしの `TPM_SE_POLICY` セッションでなければなりません。`wolfTPM2_PolicyAuthValue()` や `wolfTPM2_PolicyPassword()` で満たすポリシーは、必要となるセッション HMAC がこの経路ではシリアライズされないため、サポートされません。そのようなセッションは、TPM に何かが送信される前に `BAD_FUNC_ARG` で拒否されます。`PolicyPCR`、`PolicySigned`、`PolicySecret`、`PolicyAuthorize`、`PolicyCommandCode`、`PolicyOR` の各分岐は使用できます。 + +セッションハッシュは `wolfTPM2_StartSession_ex(..., authHash)` で選択され、`wolfTPM2_PolicyOR()` は分岐ごとのダイジェストサイズを保持するため、SHA2-256 (非 PQC) と SHA2-512 (PQC) の両方のポリシーダイジェストがサポートされます。 + +例: 複数分岐の `PolicyOR` (最大 8 分岐、ここでは SHA2-512) を満たし、その下でアップグレードを開始します。 + +```c +WOLFTPM2_SESSION session; +TPML_DIGEST orList; +uint8_t manifest_hash[TPM_SHA512_DIGEST_SIZE]; +int rc; + +/* zero both structs: orList must not carry uninitialized branch sizes */ +XMEMSET(&session, 0, sizeof(session)); +XMEMSET(&orList, 0, sizeof(orList)); + +/* start a policy session using the desired policy hash (SHA2-512 for PQC) */ +rc = wolfTPM2_StartSession_ex(&dev, &session, NULL, NULL, + TPM_SE_POLICY, TPM_ALG_NULL, TPM_ALG_SHA512); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* Satisfy one branch (PCR, PolicySigned, PolicyAuthorize, PolicyCommandCode, + * ...), then OR against the full branch list the platform authPolicy encodes. + * Set count and each digests[i].size/buffer for every branch you populate. + * PolicyOR requires at least 2 branches. */ +orList.count = 2; +/* orList.digests[0].size = ...; XMEMCPY(orList.digests[0].buffer, ...); */ +/* orList.digests[1].size = ...; XMEMCPY(orList.digests[1].buffer, ...); */ +rc = wolfTPM2_PolicyOR(&dev, &session, &orList); +if (rc != TPM_RC_SUCCESS) goto cleanup; + +/* hash the manifest with the matching algorithm, then start the upgrade under + * the caller-satisfied session (NULL would use the library-default auth) */ +rc = wc_Sha512Hash(manifest, manifest_sz, manifest_hash); +if (rc != 0) goto cleanup; +rc = wolfTPM2_FirmwareUpgradeHash_ex(&dev, TPM_ALG_SHA512, + manifest_hash, (uint32_t)sizeof(manifest_hash), + manifest, manifest_sz, fwDataCb, fwCbCtx, &session); + +cleanup: +/* On a successful FieldUpgradeStart the TPM consumes the session and the + * library sets session.handle.hndl to TPM_RH_NULL (0x40000007). It is NOT + * zeroed, so do not test for == 0 to detect consumption. Calling + * wolfTPM2_UnloadHandle is always safe: it is a no-op on TPM_RH_NULL, so this + * only releases a session that is still loaded. */ +if (session.handle.hndl != 0) + wolfTPM2_UnloadHandle(&dev, &session.handle); +``` + +最後の `startSession` 引数に `NULL` を渡すと、`wolfTPM2_FirmwareUpgradeHash_ex()` は `wolfTPM2_FirmwareUpgradeHash()` (ライブラリが管理する認可) とまったく同じ動作になるため、既存のコードには影響しません。 + +### 破壊的: プロビジョニングは既存のプラットフォームポリシーを置き換える + +!!! warning + `--policy` と `--policyor` は、サンプルが生成したダイジェストを使って、プラットフォーム階層に対して `TPM2_SetPrimaryPolicy` を呼び出します。TPM 2.0 には、階層の `authPolicy` を読み戻す手段がありません。読み取りコマンドは存在せず、`TPMA_PERMANENT` が報告するのは `authValue` の状態のみです。そのため、サンプルは既存のポリシーを検出することも、保持することも、復元することもできません。クリーンアップは、以前に設定されていたものを復元するのではなく、ポリシーを削除します。 + +プラットフォーム階層が、保持する必要のあるポリシーで制御されている場合は、これらのモードを実行しないでください。サンプルはプロビジョニング時にこの警告を表示します。`--policytest` は影響を受けません。非破壊であり、`TPM2_SetPrimaryPolicy` を呼び出すことはありません。 + +これらのモードは、通常の動作モードも必要とします。リカバリモードとファイナライズモードでは、ライブラリは `FieldUpgradeStart` を完全にスキップするため、呼び出し側が用意したセッションは使用されません。サンプルは、何も使用しないポリシーをインストールするのではなく、実行を拒否します。ST33 では、TPM がすでにファームウェアアップグレードモードにある場合も、start コマンドがすでに実行済みであるため、同様にポリシーフラグは拒否されます。 + +### サンプルがプロビジョニングしたポリシーのロールバック + +サンプルの `--policy` と `--policyor` モードは、アップグレードの前に `TPM2_SetPrimaryPolicy` でプラットフォーム階層の `authPolicy` をプロビジョニングします。失敗した場合、サンプルはそれを再びクリアするため、後続のデフォルト認可での実行がロックアウトされることはありません。成功した場合は、必要となる TPM リセットによってクリアされます。 + +- ロールバックは通常、プラットフォームのパスワード認可を使用します。TPM 2.0 Part 1 Sec. 19.7 によれば、階層は `authValue` または `authPolicy` のいずれかで認可されるため、`authPolicy` をインストールしてもパスワードの経路は無効になりません。デフォルトの空の `platformAuth` では、クリアは常に成功します。 +- `--policyor` は、ファームウェア start の分岐とともに `PolicyCommandCode(TPM_CC_SetPrimaryPolicy)` の分岐もプロビジョニングするため、ポリシー自身がその削除を認可できます。パスワードの経路が失敗した場合 (非デフォルトの `platformAuth` を設定した環境)、サンプルはその分岐でクリアを再試行します。 +- `--policy` は単一の `PolicyCommandCode(FieldUpgradeStart)` 分岐をプロビジョニングするため、ポリシーベースのロールバック経路はありません。`platformAuth` が引き続き使用できることに全面的に依存します。 +- ロールバックは、サンプルが実際にポリシーをインストールした場合にのみ試行されます。したがって、早期の失敗 (たとえばファームウェアファイルが見つからない場合) によって、環境側がプロビジョニングしたポリシーがクリアされることはありません。 +- ロールバックの失敗は明示的に報告され、終了ステータスになります。クリーンアップの前に実行が中断された場合、またはクリアに失敗した場合、TPM がリセットまたは電源を入れ直されるまで、プラットフォーム階層は引き続きそのポリシーを要求します。 + +## 関連項目 + +- [Supported hardware](supported-hardware.md) +- [Sealing and NVRAM](sealing-and-nvram.md) +- [TLS and certificates](tls-and-certificates.md) +- [Management and GPIO](management-and-gpio.md) diff --git a/docs/ja/fwtpm/building.md b/docs/ja/fwtpm/building.md new file mode 100644 index 00000000..148f2274 --- /dev/null +++ b/docs/ja/fwtpm/building.md @@ -0,0 +1,222 @@ +# fwTPM のビルド + +このページでは、fwTPM サーバーのビルド方法、それを制御する configure オプションとコンパイル定義、およびサイズや機能を調整するコンパイル時マクロについて説明します。fwTPM とは何かについては、[概要](overview.md)を参照してください。 + +## 前提条件 + +wolfSSL は、TPM サポート、keygen、および `WC_RSA_NO_PADDING` を有効にしてビルドする必要があります。 + +```sh +cd wolfssl +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +``` + +## fwTPM サーバーのビルド + +**ソケットトランスポート (SWTPM プロトコル、開発向けの既定):** + +```sh +cd wolftpm +./configure --enable-fwtpm --enable-swtpm +make +``` + +これにより `src/fwtpm/fwtpm_server` が生成され、ソケットベースの通信用に `WOLFTPM_SWTPM` を指定して wolfTPM クライアントライブラリがビルドされます。 + +**TIS および共有メモリトランスポート (fwTPM HAL 統合向け):** + +```sh +./configure --enable-fwtpm --disable-swtpm +make +``` + +`--enable-swtpm` を省略すると、ビルドでは TIS 共有メモリトランスポート (`WOLFTPM_FWTPM_HAL`、`WOLFTPM_ADV_IO`) が使用され、`fwtpm_tis.c` がサーバーにコンパイルされます。 + +**fwTPM サーバーのみ (クライアントライブラリとサンプルなし):** + +```sh +./configure --enable-fwtpm-only --enable-swtpm +make +``` + +これは `fwtpm_server` バイナリのみをビルドし、`libwolftpm`、サンプル、テストをスキップします。TPM サーバーだけが必要な組み込みターゲットで便利です。 + +**デバッグビルド:** + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-debug +make +``` + +## ビルド成果物 + +| 成果物 | 説明 | +|----------|-------------| +| `src/fwtpm/fwtpm_server` | スタンドアロンの fwTPM サーバーバイナリ | +| `src/.libs/libwolftpm.*` | wolfTPM クライアントライブラリ | + +## 主要なビルドフラグ + +| configure オプション | 効果 | +|-----------------|--------| +| `--enable-fwtpm` | `fwtpm_server` バイナリをビルドします (クライアントライブラリとあわせて) | +| `--enable-fwtpm-only` | `fwtpm_server` のみをビルドします (クライアントライブラリ、サンプル、テストなし) | +| `--enable-swtpm` | SWTPM の TCP ソケットトランスポートを使用します (ポート 2321 と 2322) | +| `--enable-fwtpm-nv-appendonly` | 書き込み一回限りのフラッシュ移植向けの追記専用 NV ジャーナル (既定では無効) | +| `--enable-pqc` (fwTPM ビルドでは `--enable-v185` に昇格) | TPM 2.0 v1.85 のポスト量子サポート ([ポスト量子サポート](post-quantum.md)を参照) | +| `--enable-spdm` | SPDM レスポンダ (`--enable-tcg` または `--enable-psk` とあわせて使用。[SPDM レスポンダ](spdm.md)を参照) | +| `--enable-fuzz` | ファジング用ビルド | +| `--enable-debug` | デバッグログを有効にします | + +| コンパイル定義 | 設定元 | +|---------------|--------| +| `WOLFTPM_FWTPM` | `fwtpm_server` ターゲットに対してのみ自動的に設定されます | +| `WOLFTPM_SWTPM` | `--enable-swtpm` | +| `WOLFTPM_FWTPM_HAL` | `--enable-fwtpm --disable-swtpm` | +| `WOLFTPM_FWTPM_TIS` | `--enable-fwtpm --disable-swtpm` | +| `WOLFTPM_ADV_IO` | `WOLFTPM_FWTPM_HAL` とあわせて設定されます | +| `WOLFTPM_FWTPM_NV_APPEND_ONLY` | `--enable-fwtpm-nv-appendonly` (CMake では `WOLFTPM_FWTPM_NV_APPEND_ONLY=yes`) | +| `WOLFTPM_FWTPM_TCG_TEST` | 手動で設定 (`CFLAGS=-DWOLFTPM_FWTPM_TCG_TEST`)。既定では無効 | + +既定ではベンダーコマンドは登録されません。オプションの `TPM2_Vendor_TCG_Test` (`0x20000000`) エコーコマンドをコンパイルして組み込むには、`WOLFTPM_FWTPM_TCG_TEST` を定義します。 + +## コマンドコードの検証 + +有効なコマンドコードは、16 ビットのインデックスと、ベンダーコマンドの場合の V ビット (`CC_VEND`、ビット 29) のみを持ちます。その他の予約ビットが設定されているコードや、ディスパッチテーブルにないコードは、`TPM_RC_COMMAND_CODE` で拒否されます。`TPM2_GetCapability(TPM_CAP_COMMANDS)` は、正しい `TPMA_CC` 値 (インデックス、ハンドル属性、V ビットで、コマンドコード順) を返します。 + +## 設定マクロ + +すべてのマクロはコンパイル時に上書きできます (例: `-DFWTPM_MAX_OBJECTS=8`)。 + +| マクロ | 既定値 | 説明 | +|-------|---------|-------------| +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | コマンドおよびレスポンスバッファの最大サイズ (バイト) | +| `FWTPM_MAX_RANDOM_BYTES` | 48 | `GetRandom` 1 回あたりの最大バイト数 | +| `FWTPM_MAX_OBJECTS` | 3 | 同時にロードできるトランジェントオブジェクトの最大数 | +| `FWTPM_MAX_PERSISTENT` | 8 | 永続オブジェクトの最大数 (`EvictControl` 経由) | +| `FWTPM_MAX_PRIVKEY_DER` | 1280 (`NO_RSA` の場合は 256) | DER エンコードされた秘密鍵の最大サイズ (バイト) | +| `FWTPM_MAX_HASH_SEQ` | 4 | 同時に実行できるハッシュおよび HMAC シーケンスの最大数 | +| `FWTPM_MAX_PRIMARY_CACHE` | 4 | 階層とテンプレートごとにキャッシュされるプライマリ鍵の数 | +| `FWTPM_MAX_SESSIONS` | 4 | 同時に実行できる認可セッションの最大数 | +| `FWTPM_MAX_NV_INDICES` | 16 | NV RAM インデックススロットの最大数。`FWTPM_NO_NV` の場合は `FWTPM_CTX` から省かれます | +| `FWTPM_MAX_NV_DATA` | 2048 | NV インデックスごとの最大データ量 (バイト) | +| `FWTPM_DA_DEFAULT_MAX_TRIES` | 32 | ロックアウトに至る DA の認証失敗回数 | +| `FWTPM_DA_DEFAULT_RECOVERY` | 600 | DA の自己回復間隔 (1 回あたりの秒数) | +| `FWTPM_DA_DEFAULT_LOCKOUT_RECOVERY` | 86400 | lockoutAuth の回復時間 (秒) | +| `FWTPM_DA_MAX_TRIES_LIMIT` | 0xFFFF | 再生された `maxTries` または `failedTries` の上限クランプ値 | +| `FWTPM_MAX_DATA_BUF` | 1024 | HMAC、ハッシュ、一般データ用の内部バッファ | +| `FWTPM_MAX_PUB_BUF` | 512 | 公開領域と署名用の内部バッファ | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | DER 署名と ECC 点用の内部バッファ | +| `FWTPM_MAX_ATTEST_BUF` | 1024 | アテステーションのマーシャリング用の内部バッファ | +| `FWTPM_MAX_CMD_AUTHS` | 3 | 1 コマンドあたりの認可セッションの最大数 (TPM 仕様上の厳密な上限) | +| `FWTPM_MAX_SENSITIVE_SIZE` | `FWTPM_MAX_PRIVKEY_DER + 128` | マーシャリングされるセンシティブ領域の最大サイズ (秘密鍵、認証値、ナンスの余裕分を含む) | +| `FWTPM_MAX_SIGN_SEQ` | 4 | 同時に実行できる v1.85 PQC の署名および検証シーケンスの最大数 | +| `FWTPM_MAX_SYM_KEY_SIZE` | 32 | 対称鍵バッファ (AES-256 に合わせたサイズ) | +| `FWTPM_MAX_HMAC_KEY_SIZE` | 64 | HMAC 鍵バッファ (SHA-512 のブロックに合わせたサイズ) | +| `FWTPM_MAX_HMAC_DIGEST_SIZE` | 64 | HMAC 出力バッファ (SHA-512 に合わせたサイズ) | +| `FWTPM_CMD_PORT` | 2321 | 既定の TCP コマンドポート | +| `FWTPM_PLAT_PORT` | 2322 | 既定の TCP プラットフォームポート | +| `FWTPM_NV_FILE` | `"fwtpm_nv.bin"` | 既定の NV ストレージファイルパス | +| `FWTPM_NV_MAX_WRITE_ALIGN` | 64 | 追記専用のプログラム単位の最大バイト数 (HAL の `writeAlign` の上限)。`WOLFTPM_FWTPM_NV_APPEND_ONLY` が設定されている場合、保留中の単位を保持するバッファのサイズを決定します | +| `FWTPM_PCR_BANKS` | 2 | PCR バンクの数 (SHA-256 と SHA-384) | +| `FWTPM_TIS_BURST_COUNT` | 64 | TIS FIFO のバーストカウント (1 回の転送あたりのバイト数) | +| `FWTPM_TIS_FIFO_SIZE` | 4096 | TIS のコマンドおよびレスポンス FIFO のサイズ | + +### スタックとヒープの制御 + +| マクロ | 効果 | +|-------|--------| +| `WOLFTPM_SMALL_STACK` | 大きなスタックオブジェクトにヒープ割り当てを使用します | +| `WOLFTPM2_NO_HEAP` | ヒープ割り当てを禁止します (すべてスタック) | + +!!! note + `WOLFTPM_SMALL_STACK` と `WOLFTPM2_NO_HEAP` は同時に指定できません。両方を定義するとコンパイルエラーになります。 + +### v1.85 の組み込み RAM への影響 + +`--enable-pqc` (または `--enable-v185`) を有効にすると、PQC の鍵と署名のサイズに対応するため、いくつかの内部バッファが拡大されます。既定値は、wolfCrypt のビルド時に有効になっている ML-DSA と ML-KEM のパラメータセット (`WOLFSSL_NO_ML_DSA_44/65/87`、`WOLFSSL_NO_KYBER512/768/1024`) に基づいて、コンパイル時に自動的に縮小されます。小さいパラメータセットのみを有効にしたボードでは、ボードごとの上書きなしで、より小さいバッファになります。 + +**有効なパラメータセット別のバッファサイズ:** + +| マクロ | クラシカル | MLDSA-44 + MLKEM-512 | MLDSA-65 + MLKEM-768 | MLDSA-87 + MLKEM-1024 | +|----------------------------|------------|--------------------|--------------------|--------------------| +| `FWTPM_TIS_FIFO_SIZE` | 4096 | 4096 | 8192 | 8192 | +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 4096 | 8192 | 8192 | +| `FWTPM_MAX_PUB_BUF` | 512 | 1440 | 2080 | 2720 | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | 2548 | 3437 | 4755 | +| `FWTPM_MAX_KEM_CT_BUF` | n/a | 832 | 1152 | 1632 | + +サイズ決定のロジックは、`wolftpm/fwtpm/fwtpm.h` (定数 `FWTPM_MAX_MLDSA_SIG_SIZE`、`FWTPM_MAX_MLDSA_PUB_SIZE`、`FWTPM_MAX_MLKEM_CT_SIZE`、`FWTPM_MAX_MLKEM_PUB_SIZE`) と `wolftpm/fwtpm/fwtpm_tis.h` (FIFO サイズ) にあります。ML-DSA の定数は wolfCrypt の `WC_MLDSA_{44,65,87}_*_SIZE` マクロから取得されます。ML-KEM の定数は FIPS 203 の仕様値です。これは、wolfCrypt の `WC_ML_KEM_*_SIZE` マクロをプリプロセッサで評価できないためです。 + +FIFO とコマンドバッファの 8192 への拡大は、MLDSA-65 または MLDSA-87 が有効な場合にのみ適用されます。これらの署名は、TPM ヘッダーを含めると 4096 バイトのレスポンスに収まらないためです。MLDSA-44 のみ、または MLKEM のみの v1.85 ビルドは 4096 のままです。 + +**デプロイごとの上書き:** 上記のすべてのマクロは引き続き `#ifndef` で保護されているため、自動的な既定値がワークロードに合わない場合、ボードごとにコンパイルラインで個別に上書きできます (例: `-DFWTPM_TIS_FIFO_SIZE=2048`)。 + +**ヒープとスタック:** `WOLFTPM_SMALL_STACK` を指定してビルドすると、呼び出しごとの大きなバッファがスタックから `XMALLOC` および `XFREE` の領域に移されます。PQC のパスはすでに、このフラグに従う `FWTPM_DECLARE_BUF` と `FWTPM_ALLOC_BUF` を使用しているため、ソースの変更は不要です。`WOLFTPM2_NO_HEAP` もサポートされていますが、スタックのコストをすべて負担することになるため、可能な限り小さい PQC パラメータセットと組み合わせてください。 + +### アルゴリズム機能マクロ + +これらのマクロは、wolfCrypt の既存のコンパイル時オプションを利用して、`fwtpm_server` で利用できる暗号アルゴリズムを制御します。アルゴリズムを無効にすると、対応する TPM コマンドはビルドから除外されます。 + +| マクロ | 既定値 | 効果 | +|-------|---------|--------| +| `NO_RSA` | 未定義 | RSA の鍵生成、署名、検証、`RSA_Encrypt`、`RSA_Decrypt` を除外します | +| `HAVE_ECC` | 定義済み | ECC の鍵生成、署名、検証、`ECDH_KeyGen`、`ECDH_ZGen`、`ECC_Parameters` を有効にします | +| `HAVE_ECC384` | 定義済み | P-384 曲線のサポートを有効にします | +| `HAVE_ECC521` または `HAVE_ALL_CURVES` | ビルドに依存 | `MAX_ECC_KEY_BITS >= 521` により 66 バイトの TPM ECC フィールドが提供される場合に、P-521 を有効にします | +| `ECC_MIN_KEY_SZ` | wolfCrypt が定義 | 小さい曲線を `ECC_Parameters` と `TPM_CAP_ECC_CURVES` から除外します | +| `NO_AES` | 未定義 | `EncryptDecrypt`、`EncryptDecrypt2`、AES によるパラメータ暗号化を除外します | +| `WOLFSSL_SHA384` | 定義済み | SHA-384 の PCR バンクを有効にします | + +アルゴリズムを無効にすると、そのアルゴリズムのみを使用するコマンドは、コンパイル時にディスパッチテーブルから削除されます。複数のアルゴリズムをサポートするコマンド (たとえば `CreatePrimary` や `Sign`) は引き続き利用できますが、無効にしたアルゴリズムタイプに対しては `TPM_RC_ASYMMETRIC` を返します。 + +### TPM 機能グループマクロ + +これらの fwTPM 固有のマクロは、TPM 2.0 の機能グループ全体を無効にして、リソースの限られたターゲットでコードサイズを削減します。 + +| マクロ | 既定値 | 除外されるコマンド | +|-------|---------|-------------------| +| `FWTPM_NO_ATTESTATION` | 未定義 | `Quote`、`Certify`、`CertifyCreation`、`GetTime`、`NV_Certify` | +| `FWTPM_NO_NV` | 未定義 | `NV_DefineSpace`、`NV_UndefineSpace`、`NV_ReadPublic`、`NV_Write`、`NV_Read`、`NV_Extend`、`NV_Increment`、`NV_WriteLock`、`NV_ReadLock`、`NV_Certify`。また、メモリ上の NV インデックススロットを `FWTPM_CTX` から削除します | +| `FWTPM_NO_POLICY` | 未定義 | `PolicyGetDigest`、`PolicyRestart`、`PolicyPCR`、`PolicyPassword`、`PolicyAuthValue`、`PolicyCommandCode`、`PolicyOR`、`PolicySecret`、`PolicyAuthorize`、`PolicyNV` | +| `FWTPM_NO_CREDENTIAL` | 未定義 | `MakeCredential`、`ActivateCredential` | +| `FWTPM_NO_DA` | 未定義 | `DictionaryAttackParameters`、`DictionaryAttackLockReset`、およびすべてのロックアウト処理 | +| `FWTPM_NO_PARAM_ENC` | 未定義 | セッションにおけるコマンドおよびレスポンスのパラメータ暗号化 (XOR と AES-CFB) のサポート | +| `FWTPM_NO_KEY_MIGRATION` | 未定義 | `Import`、`Duplicate`、`Rewrap` | +| `FWTPM_NO_ECDH` | 未定義 | `ECDH_KeyGen`、`ECDH_ZGen`、`EC_Ephemeral`、`ZGen_2Phase`、`ECC_Parameters` (ECDSA の署名と検証は維持されます)、および `FWTPM_CTX` 内の `ecEphemeral*` コミット状態 | +| `FWTPM_NO_HASH_CMDS` | 未定義 | `Hash`、`HMAC`、`HMAC_Start`、`HashSequenceStart`、`SequenceUpdate`、`SequenceComplete`、`EventSequenceComplete`、および `FWTPM_CTX` 内のハッシュシーケンススロット | +| `FWTPM_NO_CONTEXT` | 未定義 | `ContextSave`、`ContextLoad` (`FlushContext` は維持されます)、および `FWTPM_CTX` 内の起動ごとのコンテキスト保護鍵と保存済みコンテキストのリプレイリスト | +| `FWTPM_NO_SYM_ENCRYPT` | 未定義 | `EncryptDecrypt`、`EncryptDecrypt2` | +| `FWTPM_NO_CLOCK` | 未定義 | `ReadClock`、`ClockSet`、`ClockRateAdjust` | + +コマンドグループを削除すると、ディスパッチテーブルから導出される `TPM2_GetCapability(TPM_CAP_COMMANDS)` の通知と `TPM_PT_TOTAL_COMMANDS` の数からも、そのグループが削除されます。`WOLFTPM_MLDSA` をビルドする場合、ML-DSA の検証シーケンスがメッセージを `SequenceUpdate` 経由でストリーミングするため、`FWTPM_NO_HASH_CMDS` の下でも `SequenceUpdate` のみは維持されます。`SequenceComplete` は共有されません (ML-DSA のシーケンスは `TPM2_SignSequenceComplete` と `TPM2_VerifySequenceComplete` で完了します)。そのため、決して成功しないコマンドとして通知されることがないよう、他のハッシュコマンドとともに除外されます。 + +`FWTPM_DA_USED_RETRY` マクロ (既定では無効) は、コマンドを削除しません。これを有効にすると、起動後に DA で保護された認証が最初に使われたとき、サーバーは `TPM_RC_RETRY` を返し、実際の TPM が `daUsed` を永続化する動作をエミュレートします。[概要](overview.md)の Dictionary Attack Protection を参照してください。 + +**最小構成のビルド例。** すべてをまとめて無効にするマクロはありません。削除するコマンドグループを明示的に選択することで、それぞれを意図的な選択にします。たとえば、小規模な ECC 専用の署名および NV 対応 fTPM をビルドする場合 (この設定ではアテステーションを削除し、`Sign`、`VerifySignature`、PCR、NV を維持します): + +```sh +./configure --enable-fwtpm --enable-swtpm \ + CFLAGS="-DNO_RSA \ + -DFWTPM_NO_POLICY -DFWTPM_NO_ATTESTATION -DFWTPM_NO_CREDENTIAL \ + -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC -DFWTPM_NO_KEY_MIGRATION \ + -DFWTPM_NO_ECDH -DFWTPM_NO_HASH_CMDS -DFWTPM_NO_CONTEXT \ + -DFWTPM_NO_SYM_ENCRYPT -DFWTPM_NO_CLOCK" +``` + +この設定でも、コアとなる fTPM の機能は維持されます: `Startup`、`Shutdown`、`SelfTest`、`GetRandom`、`GetCapability`、`PCR_*` コマンド、`Create`、`CreatePrimary`、`Load`、`ReadPublic`、`FlushContext`、`Sign`、`VerifySignature`、`NV_*` コマンド、およびセッションのサポート (`StartAuthSession` と `Unseal`)。NV も削除するには `-DFWTPM_NO_NV` を追加し、上記の `-DFWTPM_NO_*` のいずれかを外すと、そのグループを維持できます。この ECC 専用ビルドは、リソースの限られた FPGA 上でソフトコア fTPM として動作できるほど小さくなります (`wolftpm-examples` リポジトリの MicroBlaze V の例を参照してください。ECC 専用の fTPM がオンチップメモリ約 192 KB に収まります)。 + +**依存関係:** + +- `FWTPM_NO_NV` は、`FWTPM_NO_ATTESTATION` が設定されていなくても `NV_Certify` を削除します。 +- `NO_RSA` は、RSA によるアテステーション署名が使えないことを意味します。ECC のみのアテステーションは `HAVE_ECC` で引き続き動作します。 + +## 関連項目 + +- [概要](overview.md) +- [使い方](usage.md) +- [HAL と移植](hal-and-porting.md) +- [ポスト量子サポート](post-quantum.md) +- [SPDM レスポンダ](spdm.md) diff --git a/docs/ja/fwtpm/hal-and-porting.md b/docs/ja/fwtpm/hal-and-porting.md new file mode 100644 index 00000000..3d8dd58e --- /dev/null +++ b/docs/ja/fwtpm/hal-and-porting.md @@ -0,0 +1,169 @@ +# HAL と移植 + +fwTPM はハードウェア抽象化レイヤー (HAL) を提供しており、コアロジックを変更せずに組み込みターゲットへ移植できます。トランスポート用の IO HAL、永続ストレージ用の NV HAL、およびオプションのクロック HAL があります。複数のボード向けの完全なリファレンス移植は、[wolftpm-examples](https://github.com/wolfSSL/wolftpm-examples) リポジトリにあります。 + +## IO HAL (トランスポート) + +IO HAL は、fwTPM サーバーとそのクライアント間のトランスポートを抽象化します。デフォルトの実装は TCP ソケット (SWTPM プロトコル) を使用します。組み込みターゲットでは、SPI、I2C、UART、または共有メモリのコールバックに置き換えます。 + +**コールバック構造体** (`fwtpm.h` で `FWTPM_IO_HAL` として定義): + +| コールバック | シグネチャ | 説明 | +|----------|-----------|-------------| +| `send` | `int (*)(void* ctx, const void* buf, int sz)` | クライアントへデータを送信 | +| `recv` | `int (*)(void* ctx, void* buf, int sz)` | クライアントからデータを受信 | +| `wait` | `int (*)(void* ctx)` | データまたは接続を待機。ビットマスクを返す: `0x01`=コマンドデータ、`0x02`=プラットフォームデータ、`0x04`=新しいコマンド接続、`0x08`=新しいプラットフォーム接続 | +| `accept` | `int (*)(void* ctx, int type)` | 新しい接続を受け入れる (type: 0=コマンド、1=プラットフォーム) | +| `close_conn` | `void (*)(void* ctx, int type)` | 接続を閉じる (type: 0=コマンド、1=プラットフォーム) | +| `ctx` | `void*` | ユーザーコンテキストポインタ | + +**登録:** + +```c +FWTPM_IO_HAL myHal; +myHal.send = my_send; +myHal.recv = my_recv; +myHal.wait = my_wait; +myHal.accept = my_accept; +myHal.close_conn = my_close; +myHal.ctx = &myTransportCtx; + +FWTPM_IO_SetHAL(&ctx, &myHal); +``` + +## NV HAL (永続ストレージ) + +NV HAL は永続ストレージを抽象化します。デフォルトの実装はローカルファイル (`fwtpm_nv.bin`) を使用します。組み込みターゲットでは、フラッシュ、EEPROM、その他の不揮発性ストレージのコールバックに置き換えます。 + +**コールバック構造体** (`fwtpm.h` で `FWTPM_NV_HAL` として定義): + +| コールバック | シグネチャ | 説明 | +|----------|-----------|-------------| +| `read` | `int (*)(void* ctx, word32 offset, byte* buf, word32 size)` | オフセットを指定して NV から読み取り | +| `write` | `int (*)(void* ctx, word32 offset, const byte* buf, word32 size)` | オフセットを指定して NV へ書き込み | +| `erase` | `fwtpm.h` を参照 | NV 領域を消去 (フラッシュの移植およびコンパクションで使用) | +| `ctx` | `void*` | ユーザーコンテキストポインタ | +| `maxSize` | `word32` | NV 領域のサイズ (バイト) | +| `appendOnly`, `writeAlign` | フィールド | アペンドオンリーモードとプログラム粒度のサイズ (後述) | +| `get_integrity_key` | コールバック | ジャーナルの認証に使用するデバイスシークレットを提供 | + +**登録:** + +```c +FWTPM_NV_HAL myNvHal; +myNvHal.read = my_flash_read; +myNvHal.write = my_flash_write; +myNvHal.ctx = &myFlashCtx; + +FWTPM_NV_SetHAL(&ctx, &myNvHal); +``` + +HAL は `FWTPM_Init()` の前に登録してください。 + +### 組み込み移植向けの NV ストレージ HAL + +NV アクセスは `FWTPM_NV_HAL` (`read`、`write`、`erase`、`ctx`、`maxSize`、`get_integrity_key`) を通じて行われます。デフォルトのバックエンドはファイルです。組み込みの移植では独自の HAL を用意し、`FWTPM_Init()` の前に登録します。 + +ジャーナルはログ構造です。バイトアドレス指定可能なバックエンド (デフォルトのファイル) では、バイト単位のオフセットに TLV エントリを書き込み、ヘッダーをその場で書き換え、追記のたびに末尾の整合性 MAC を書き換えます。内蔵フラッシュと NOR はライトワンスであり、プログラム粒度にアラインされているため、その場での書き換えには対応できません。 + +そのようなデバイスでは、`--enable-fwtpm-nv-appendonly` (`-DWOLFTPM_FWTPM_NV_APPEND_ONLY`、CMake では `WOLFTPM_FWTPM_NV_APPEND_ONLY=yes`) を指定してビルドし、HAL に `appendOnly` と `writeAlign` を設定します。ジャーナルはアペンドオンリーモードで動作します。 + +- ヘッダーはコンパクション時にのみ書き込まれます。 +- `writePos` はロード時のスキャンによって導出されます。 +- 各コミットは、`writeAlign` までパディングされた MAC チェックポイントエントリを追記することで封印されます。 + +既存の `read`、`write`、`erase` の HAL が統合ポイントです。別途アダプタはありません。 + +```c +/* Native flash HAL. In append-only mode the journal only ever calls write() + * with writeAlign-aligned, forward, into-erased bytes, so write() is a simple + * flash program; erase() erases the region (sector loop); read() reads raw. */ +FWTPM_NV_HAL hal; +XMEMSET(&hal, 0, sizeof(hal)); +hal.read = myRead; hal.write = myProgram; hal.erase = myErase; +hal.ctx = myCtx; hal.maxSize = NV_SIZE; +hal.appendOnly = 1; +hal.writeAlign = PROG_SIZE; /* flash word size, e.g. 16 (STM32H5) */ +hal.get_integrity_key = myDeviceSecret;/* recommended on flash */ +FWTPM_NV_SetHAL(&ctx, &hal); /* before FWTPM_Init() */ +``` + +アペンドオンリーモードでは、ジャーナルは保留中のプログラム粒度を内部でバッファリングし、満たされたアライン済みの粒度を `write()` 経由でフラッシュします。プログラム済みのセルが書き換えられることはなく、セクタ全体が消去されるのはコンパクション時のみです。そのため、ヘッダーセクタは追記のたびに消去されることがなく、(たとえば電源断による) 最後のコミットの中断は次回のロード時に無視され、それ以前にコミットされたすべての状態は保持されます。 + +フラッシュでは `get_integrity_key` コールバックを強く推奨します。これにより MAC チェックポイントがジャーナルを認証し、中断または改ざんされた末尾を拒否できます。`writeAlign <= 1` を設定するとバッファリングなしが選択され、バイト書き込み可能な NV (EEPROM または FRAM) でも単純な `write()` で動作します。 + +!!! warning + コンパクションでは、書き直す前に領域全体を依然として消去するため、コンパクション自体の最中に電源が失われる場合は脆弱な期間が残ります。将来、2 領域のピンポン方式のレイアウトを導入すれば、この問題を解消できます。 + +## クロック HAL + +クロック HAL はオプションです。起動からの経過ミリ秒を返す `get_ms()` を提供します。`FWTPM_Init()` の前に `FWTPM_Clock_SetHAL()` で登録してください。クロック HAL を登録すると、ディクショナリアタック保護が時間の経過とともに自己回復します ([概要](overview.md)を参照)。 + +## 移植の例 + +SPI トランスポートと SPI フラッシュの NV を使用するベアメタルの組み込みターゲットの例です。 + +```c +FWTPM_CTX ctx; +XMEMSET(&ctx, 0, sizeof(ctx)); + +/* Set custom NV storage before FWTPM_Init, which loads NV state through it */ +FWTPM_NV_HAL nvHal = { + .read = spi_flash_read, + .write = spi_flash_write, + .ctx = &flashHandle +}; +FWTPM_NV_SetHAL(&ctx, &nvHal); + +FWTPM_Init(&ctx); + +/* Set custom IO transport after FWTPM_Init, which does not preserve the IO HAL */ +FWTPM_IO_HAL ioHal = { + .send = spi_slave_send, + .recv = spi_slave_recv, + .wait = spi_slave_poll, + .accept = NULL, /* not connection-oriented */ + .close_conn = NULL, + .ctx = &spiHandle +}; +FWTPM_IO_SetHAL(&ctx, &ioHal); + +/* Initialize IO and run */ +FWTPM_IO_Init(&ctx); +FWTPM_IO_ServerLoop(&ctx); /* blocks */ + +FWTPM_IO_Cleanup(&ctx); +FWTPM_Cleanup(&ctx); +``` + +## 利用可能な移植 + +| 移植先 | リポジトリ | 説明 | +|------|-----------|-------------| +| STM32H5 | [STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) | TrustZone (CMSE) を備えた STM32H5 Cortex-M33。内蔵フラッシュの NV | +| PolarFire SoC | [Microchip/fwtpm-polarfire-miv](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/fwtpm-polarfire-miv) | MPFS250T。U54 RISC-V ハート上の M モードでベアメタル動作する fwTPM (Linux と並行する HSS AMP)、共有 L2-LIM メモリ上の TIS | +| Zynq UltraScale+ ZCU102 | [Xilinx/fwtpm-zcu102-r5](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zcu102-r5) | ZynqMP MPSoC。ロックステップの Cortex-R5 RPU ペア上でベアメタル動作する fwTPM、A53 (PetaLinux) 上の OpenAMP RPMsg クライアント。揮発性の DDR NV または永続的な QSPI | + +## 移植ガイド + +新しいプラットフォームを追加するには、次の HAL コールバックを実装します。 + +1. **NV ストレージ HAL** (`FWTPM_NV_HAL`): 永続的なフラッシュストレージのための `read()`、`write()`、`erase()`。`FWTPM_Init()` の前に `FWTPM_NV_SetHAL()` で登録します。 + + NV ジャーナルはログ構造です。バイトアドレス指定可能なバックエンドでは、バイト単位のオフセットに書き込み、追記のたびにヘッダーと末尾の整合性 MAC をその場で書き換えます。内蔵フラッシュと NOR はライトワンスであり、プログラム粒度にアラインされているため、その場での書き換えには対応できません。そのようなデバイスでは、`--enable-fwtpm-nv-appendonly` を指定してビルドし、`FWTPM_NV_SetHAL()` の前に `hal.appendOnly = 1` と `hal.writeAlign = ` (例: STM32H5 では 16) を設定します。 + + ジャーナルはその後、ヘッダーをコンパクション時にのみ書き込み、ロード時のスキャンで `writePos` を導出し、プログラム粒度にアラインされた MAC チェックポイントを追記して各コミットを封印し、保留中のプログラム粒度を内部でバッファリングします。`write()` が呼び出されるのは、`writeAlign` にアラインされた、前方へ進む、消去済みの領域へのバイトに対してのみです。したがって、移植側の `write()` はバッファリングや読み出し・修正・書き込みのない単純なフラッシュプログラムで済み、`erase()` は領域を消去し (セクタのループ)、`read()` は生のバイトを読み取ります。プログラム済みのセルが書き換えられることはなく、セクタ全体が消去されるのはコンパクション時のみであるため、追記のたびにヘッダーセクタが摩耗することはなく、最後のコミットが中断しても次回のロード時に無視されます。チェックポイントがジャーナルを認証できるよう、`FWTPM_NV_HAL` に `get_integrity_key` を指定してください。`writeAlign <= 1` を設定すると、EEPROM や FRAM などのバイト書き込み可能な NV に対してバッファリングが無効になります。 + +2. **クロック HAL** (オプション): 起動からの経過ミリ秒を返す `get_ms()`。`FWTPM_Init()` の前に `FWTPM_Clock_SetHAL()` で登録します。 + +3. **エントリポイント**: `FWTPM_CTX` をゼロクリアし、HAL を登録して `FWTPM_Init()` を呼び出し、その後 `FWTPM_ProcessCommand()` で TPM コマンドを処理します。 + +完全なリファレンス実装については、wolftpm-examples の STM32 の移植を参照してください。 + +## 関連項目 + +- [概要](overview.md) +- [ビルド](building.md) +- [使用方法](usage.md) +- [ポスト量子サポート](post-quantum.md) +- [SPDM レスポンダ](spdm.md) diff --git a/docs/ja/fwtpm/overview.md b/docs/ja/fwtpm/overview.md new file mode 100644 index 00000000..d39453c8 --- /dev/null +++ b/docs/ja/fwtpm/overview.md @@ -0,0 +1,379 @@ +# fwTPM 概要 + +wolfTPM の fwTPM (fTPM とも呼ばれます) は、wolfCrypt の暗号プリミティブを基盤とするファームウェア TPM 2.0 です。テスト専用のエミュレータではありません。スタンドアロンのサーバープロセス (`fwtpm_server`) として動作するか、組み込みファームウェアイメージにリンクして使用できる、ポータブルな TPM 2.0 コマンドプロセッサです。RSA、ECC、AES、およびすべての機能グループを有効にしたデフォルトビルドでは、TPM 2.0 Revision 1.38 の 112 個のコマンドコードのうち 103 個がディスパッチテーブルに含まれます。Version 185 のポスト量子コマンド 8 個を加えると 111 個になります。カウント方法と、最小限のセルフテストや `SU_STATE` による再開が未対応であることなどの既知の制限については、以下のコマンドカバレッジを参照してください。 + +fwTPM はテストに使用できるほか、ディスクリート TPM チップが利用できない、または使いたくない環境での本番運用、セキュリティ重視、分離型のデプロイメントにも使用できます。そのようなデプロイメントでは、TPM のセキュリティはそれをホストするプラットフォームに依存します。ファームウェア TPM は、それ自体ではディスクリート TPM チップのような物理的な分離を提供しません。そのため、インテグレーターが分離 (別コア、TrustZone のセキュアワールドなど) を用意し、NV ストレージを保護する必要があります。デフォルトのファイルベース NV ストアは、階層シード、認可値、秘密鍵を平文で保持し、`fwtpm_server` 自体は開発およびテスト用のツールです。また、fwTPM は TPM シリコンのないプラットフォームにポスト量子暗号と SPDM を提供します。 + +統合モデルの例: + +- ディスクリート TPM チップのない**組み込みおよび IoT プラットフォーム** (SPI または I2C の TIS HAL によるベアメタル) +- 別コア上で動作する TPM、TrustZone のセキュアワールド、Linux アプリケーションプロセッサの隣にあるロックステップのリアルタイムコアなどの**分離型デプロイメント**。分離はプラットフォームによって実現され、fwTPM が提供するものではありません。 +- TPM に依存するアプリケーションの**開発とテスト** (swtpm や Microsoft TPM シミュレータのドロップイン代替) +- TPM 機能を必要とする **CI/CD パイプライン** (tpm2-tools と互換性のあるソケットトランスポート) +- ハードウェアが利用可能になる前の TPM ワークフローの**プロトタイピング** +- TPM シリコンなしでの**ポスト量子および SPDM の作業** ([ポスト量子サポート](post-quantum.md)と [SPDM レスポンダ](spdm.md)を参照) + +## 機能 + +- デフォルトビルドで Revision 1.38 の 112 個のコマンドコードのうち 103 個をカバーする TPM 2.0 コマンドプロセッサ。制限事項はコマンドカバレッジに記載しています。 +- Microsoft TPM シミュレータプロトコルを使用する TCP ソケットトランスポート。wolfTPM のサンプルおよび tpm2-tools と互換性があります。mssim と swtpm の両方の TCTI プロトコルがコマンドポート上で自動検出されます。 +- POSIX 共有メモリ上の TIS レジスタレベルトランスポート、またはベアメタル統合向けの SPI もしくは I2C 上の TIS レジスタレベルトランスポート。 +- I/O と NV ストレージのための HAL 抽象化により、移植時にコアロジックを変更する必要がありません。[HAL と移植](hal-and-porting.md)を参照してください。 +- `--enable-pqc` によるポスト量子暗号: TCG TPM 2.0 Library Specification Version 185 に基づく ML-DSA (FIPS 204) 署名と ML-KEM (FIPS 203) 鍵カプセル化。`--enable-pqc` と `--enable-v185` はプロジェクト全体では別個のモードですが、fwTPM のビルドでは configure が `--enable-pqc` を完全な Version 185 モードに引き上げるため、fwTPM に関しては両者の動作は同じです。`--enable-fwtpm` が両方を備えた wolfCrypt に対してビルドされる場合、configure は PQC を自動検出します。[ポスト量子サポート](post-quantum.md)を参照してください。 +- シリコンなしで SPDM スタックをテストするための SPDM 1.3 レスポンダ。[SPDM レスポンダ](spdm.md)を参照してください。 +- 制約のあるターゲット向けにビルドを縮小するコンパイル時機能ゲート (`FWTPM_NO_*`)。[ビルド](building.md)を参照してください。 + +## アーキテクチャ + +``` ++---------------------+ +-------------------------------+ +| wolfTPM Client App | | fwtpm_server (or embedded) | +| (examples, tests) | | | ++----------+----------+ | +-------------------------+ | + | | | Transport Layer | | + TCP (SWTPM protocol) | | (socket or TIS) | | + or TIS shared memory | +------------+------------+ | + or SPI/I2C TIS | | | + | | +------------v------------+ | + +--------------->| | FWTPM_ProcessCommand | | + | | (fwtpm_command.c) | | + | +------+-----------+------+ | + | | | | + | +------v-----+ +---v------+ | + | | wolfCrypt | | NV | | + | | (RSA, ECC, | | backend | | + | | SHA, HMAC,| | (fwtpm_ | | + | | RNG, AES) | | nv.c) | | + | +------------+ +----------+ | + +-------------------------------+ +``` + +ソケットトランスポートと TIS トランスポートのどちらも、各コマンドを `FWTPM_ProcessCommand` に渡します。その後、コマンドハンドラが wolfCrypt と NV バックエンドを使用します。この流れは、スタンドアロンサーバーでも組み込み統合でも同じです。 + +**コンポーネント:** + +| ファイル | 役割 | +|------|------| +| `fwtpm_command.c` | TPM 2.0 コマンドプロセッサとディスパッチテーブル | +| `fwtpm_io.c` | トランスポート層: SWTPM TCP ソケットプロトコル (swtpm 構成で有効になります。この構成を使用しないビルドでは TIS パスを使用します) | +| `fwtpm_nv.c` | NV ストレージ: ファイルベース (デフォルト)。HAL で抽象化されており、ライトワンスフラッシュ向けの組み込みアペンドオンリーモードを備えます | +| `fwtpm_tis.c` | TIS レジスタステートマシン (トランスポート非依存) | +| `fwtpm_tis_shm.c` | POSIX 共有メモリとセマフォによる TIS トランスポート | +| `fwtpm_main.c` | サーバーのエントリポイント、CLI 引数の解析 | +| `tpm2_util.c` | 共有ユーティリティ (ハッシュヘルパー、ForceZero、PrintBin) | +| `tpm2_packet.c` | TPM パケットのマーシャルとアンマーシャル | +| `tpm2_param_enc.c` | パラメータ暗号化 (XOR および AES セッション暗号化) | + +## サポートされる TPM 2.0 コマンド + +このセクションは代表的なコマンドを列挙したもので、網羅的ではありません。`PCR_Event`、`PCR_Allocate`、`ClockRateAdjust`、いくつかのポリシーコマンド、およびアルゴリズムに依存する一部のコマンドなど、サポートされているコマンドの一部は省略しています。ディスパッチテーブルの内訳は後述のコマンドカバレッジにあります。デフォルトのビルド (`FWTPM_NO_*` マクロを設定しない場合) には、以下のすべてのグループが含まれます。ゲートマクロを設定すると、そのグループのコマンドがディスパッチテーブル、`TPM2_GetCapability(TPM_CAP_COMMANDS)`、および `TPM_PT_TOTAL_COMMANDS` のカウントから除外されます。ゲートについては[ビルド](building.md)を参照してください。 + +### 起動とセルフテスト + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_Startup` | TPM を初期化 (SU_CLEAR または SU_STATE) | +| `TPM2_Shutdown` | 状態を保存し、電源オフに備える | +| `TPM2_SelfTest` | 最小限のセルフテスト: SHA-256 の既知解テストと RNG のチェック。ソースコードではこれを仕様非準拠としています。 | +| `TPM2_IncrementalSelfTest` | 空の to-do リストを返すだけの何もしないスタブ | +| `TPM2_GetTestResult` | セルフテストの結果を返す | + +### 乱数生成 + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_GetRandom` | ランダムバイトを生成 (1 回の呼び出しで最大 48) | +| `TPM2_StirRandom` | RNG の状態にエントロピーを追加 | + +### ケイパビリティ + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_GetCapability` | TPM のプロパティ、アルゴリズム、ハンドルを照会 | + +### 鍵管理 + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_CreatePrimary` | 階層の下にプライマリ鍵を作成 | +| `TPM2_Create` | 親の下に子鍵を作成 | +| `TPM2_CreateLoaded` | 鍵の作成とロードを 1 つのコマンドで実行 | +| `TPM2_Load` | プライベート部とパブリック部から鍵をロード | +| `TPM2_LoadExternal` | 外部 (ソフトウェア) 鍵をロード | +| `TPM2_Import` | 外部でラップされた鍵をインポート | +| `TPM2_Duplicate` | 転送用に鍵をエクスポート (内側と外側のラッピング) | +| `TPM2_Rewrap` | 複製されたオブジェクトを古い親から新しい親へ再ラップ | +| `TPM2_FlushContext` | トランジェントオブジェクトまたはセッションをアンロード | +| `TPM2_ContextSave` | オブジェクトまたはセッションのコンテキストを保存 | +| `TPM2_ContextLoad` | 保存したコンテキストを復元 | +| `TPM2_ReadPublic` | ロード済みの鍵のパブリック領域を読み取り | +| `TPM2_ObjectChangeAuth` | 鍵の認可を変更 | +| `TPM2_EvictControl` | トランジェント鍵を永続化 (または削除) | +| `TPM2_HierarchyControl` | 階層を有効化または無効化 | +| `TPM2_HierarchyChangeAuth` | 階層の認可値を変更 | +| `TPM2_Clear` | ストレージプライマリシードを再生成し、オーナーとエンドースメントの認可およびポリシー状態をリセットして、対象となるオブジェクトを削除予定にする。プラットフォームシードとエンドースメントシードは再生成しない。 | +| `TPM2_ChangePPS` | プラットフォームプライマリシードを置換 | +| `TPM2_ChangeEPS` | エンドースメントプライマリシードを置換 | + +### 暗号操作 + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_Sign` | ロード済みの鍵でダイジェストに署名 | +| `TPM2_VerifySignature` | ロード済みの鍵に対して署名を検証 | +| `TPM2_RSA_Encrypt` | RSA 暗号化 (OAEP、PKCS1) | +| `TPM2_RSA_Decrypt` | RSA 復号 | +| `TPM2_EncryptDecrypt` | 対称鍵による暗号化と復号 | +| `TPM2_EncryptDecrypt2` | 対称鍵による暗号化と復号 (代替) | +| `TPM2_Hash` | ワンショットのハッシュ計算 | +| `TPM2_HMAC` | ワンショットの HMAC 計算 | +| `TPM2_ECDH_KeyGen` | 一時的な ECC 鍵ペアを生成 | +| `TPM2_ECDH_ZGen` | ECDH 共有秘密を計算 | +| `TPM2_ECC_Parameters` | ECC 曲線パラメータを取得 | +| `TPM2_TestParms` | アルゴリズムパラメータのサポートを検証 | + +### ハッシュシーケンス + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_HashSequenceStart` | ハッシュシーケンスを開始 | +| `TPM2_HMAC_Start` | HMAC シーケンスを開始 | +| `TPM2_SequenceUpdate` | ハッシュまたは HMAC シーケンスにデータを追加 | +| `TPM2_SequenceComplete` | ハッシュまたは HMAC シーケンスを完了して結果を取得 | +| `TPM2_EventSequenceComplete` | ハッシュシーケンスを完了して PCR を拡張 | + +### シーリング + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_Unseal` | シール済みオブジェクトからデータをアンシール | + +### PCR (Platform Configuration Registers) + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_PCR_Read` | PCR の値を読み取り | +| `TPM2_PCR_Extend` | ダイジェストで PCR を拡張 | +| `TPM2_PCR_Reset` | リセット可能な PCR をリセット | + +### クロック + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_ReadClock` | TPM クロックの値を読み取り | +| `TPM2_ClockSet` | TPM クロックを設定 | + +### セッションと認可 + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_StartAuthSession` | HMAC、ポリシー、またはトライアルセッションを作成 | + +### ポリシー + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_PolicyGetDigest` | 現在のポリシーセッションダイジェストを取得 | +| `TPM2_PolicyRestart` | ポリシーセッションダイジェストをリセット | +| `TPM2_PolicyPCR` | ポリシーを PCR 値にバインド | +| `TPM2_PolicyPassword` | ポリシーにパスワードを含める | +| `TPM2_PolicyAuthValue` | ポリシーに認可値を含める | +| `TPM2_PolicyCommandCode` | ポリシーを特定のコマンドに制限 | +| `TPM2_PolicyOR` | ポリシー分岐の論理和 | +| `TPM2_PolicySecret` | シークレットによる認可 | +| `TPM2_PolicyAuthorize` | 署名鍵でポリシーを承認 | +| `TPM2_PolicyNV` | NV インデックスの比較に基づくポリシー | +| `TPM2_PolicyLocality` | ポリシーを特定のローカリティに制限 | +| `TPM2_PolicySigned` | 外部署名鍵でポリシーを認可 | + +### ディクショナリアタック (DA) 保護 + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_DictionaryAttackParameters` | `maxTries`、`recoveryTime`、`lockoutRecovery` を設定 | +| `TPM2_DictionaryAttackLockReset` | 失敗試行カウンタをリセット (lockoutAuth) | + +fwTPM は、TPM 2.0 仕様 (Part 1、Section 19.8) をモデルとしたディクショナリアタック保護を実装しています。DA 保護されたエンティティの認可に失敗すると `failedTries` が増加します。`maxTries` に達すると、TPM は `TPM_RC_LOCKOUT` を返します。`failedTries` は失敗のたびに NV へ永続化されるため、電源の再投入でリセットすることはできません。 + +クロック HAL が登録されている場合 (`FWTPM_Clock_SetHAL`)、カウンタは `recoveryTime` 秒ごとに 1 回分ずつ自己回復し、非正常シャットダウンでは 1 回分のペナルティが加算されます。クロックのないビルドではどちらも適用されません。永続化された `failedTries` カウンタは自己回復せず、回復は `DictionaryAttackLockReset` または `Clear` のみで行われるため、通常の異常な電源断が積み重なってロックアウトに至ることはありません。 + +`lockoutAuth` の認可に失敗すると、ロックアウト階層がロックされます。クロック HAL のあるビルドでは、このロックは再起動後も維持され、`lockoutRecovery` 秒後に解除されます。ただし `lockoutRecovery` が 0 の場合 (再起動のみで回復) は除きます。クロックのないビルドでは、`lockoutAuth` の失敗によるロックは起動のたびに解除されます。クロック HAL がある場合、クロック HAL は起動からの経過ミリ秒を報告するため、このタイマーは再起動をまたいだ実時間ではなく、起動後の連続稼働時間を計測します。`lockoutRecovery` より短い間隔で再起動するデバイスでは、実効的な回復期間が延びます。 + +ゲートは 2 つあり、互いに独立しています。`lockoutAuth` の認可に失敗すると、以降の `lockoutAuth` の使用 (`DictionaryAttackLockReset`、`DictionaryAttackParameters`、およびロックアウト認可の `Clear`) がブロックされます。`maxTries` に達すると、DA 保護されたオブジェクト、NV インデックス、およびバインドされたエンティティの認可がブロックされ、TPM は `TPM_RC_LOCKOUT` を返します。プラットフォーム階層は常に退避経路となります。`TPM2_ClearControl(platformAuth, clearDisable=NO)` に続けて `TPM2_Clear(platformAuth)` を実行すれば、`disableClear` が設定されていても回復できます。`Startup` と `Shutdown` は DA によってゲートされることがないため、ロックアウト中でも再起動すれば常に回復できます。`noDA` が設定されたエンティティ (オブジェクトでは `TPMA_OBJECT_noDA`、NV インデックスでは `TPMA_NV_NO_DA`) はカウンタに影響せず、ロックアウト中も使用可能なままです。 + +`TPM2_GetCapability(TPM_CAP_TPM_PROPERTIES)` は、`TPM_PT_MAX_AUTH_FAIL`、`TPM_PT_LOCKOUT_INTERVAL`、`TPM_PT_LOCKOUT_RECOVERY`、`TPM_PT_LOCKOUT_COUNTER`、および `TPM_PT_PERMANENT` の `inLockout` ビットを報告します。 + +永続的なアカウンティングでは、DA 保護された認可の失敗ごとに (および起動ごとの最初の DA 保護された認可の使用時に) NV の FLAGS エントリを書き込みます。カウンタは `maxTries` にある間は増加しませんが、クロックによる自己回復でカウンタが下がることがあり、その場合は同じ起動中にさらに認可失敗と NV 書き込みが発生し得るため、起動ごとの書き込み回数に厳密な上限はありません。フラッシュを使用するターゲットでは、それでも摩耗が増え、認可失敗時のレイテンシが NV に律速されるため、NV バックエンドの選定時にこれを考慮してください。 + +起動後に DA 保護された (`noDA` でない) 認可を最初に使用すると、TPM によっては `daUsed` フラグを NV に永続化し、書き込み中は `TPM_RC_RETRY` ("同一のコマンドを再送せよ") を返すことがあります。TCG のアーキテクチャでは、これは実装方法の 1 つとして説明されており、すべての TPM に求められる要件ではありません。`FWTPM_DA_USED_RETRY` を指定してビルドすると、この動作をエミュレートし、クライアントの再送およびリトライ処理を検証できます。デフォルトではオフで、DA のアカウンティングと永続化はこの設定に関係なく有効です。`FWTPM_NO_DA` で DA ロジックをすべてコンパイル対象から外せます。 + +カバレッジ: `tests/fwtpm_unit_tests.c` の DA、noDA、ロックアウト、自己回復、永続化のユニットテスト、`examples/management/da_check` のエンドツーエンドサンプル (破壊的なロックアウトと回復のパスには `-lockout` を追加)、および `FWTPM_DA_USED_RETRY` ビルドに対して `TPM_RC_RETRY` のパスを検証する `tests/fwtpm_da_retry.sh` ハーネス。 + +### 不揮発性ストレージ (NV) + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_NV_DefineSpace` | NV インデックスを作成 | +| `TPM2_NV_UndefineSpace` | NV インデックスを削除 | +| `TPM2_NV_ReadPublic` | NV インデックスのパブリックメタデータを読み取り | +| `TPM2_NV_Write` | NV インデックスにデータを書き込み | +| `TPM2_NV_Read` | NV インデックスからデータを読み取り | +| `TPM2_NV_Extend` | NV インデックスを拡張 (ハッシュ拡張) | +| `TPM2_NV_Increment` | NV カウンタをインクリメント | +| `TPM2_NV_WriteLock` | NV インデックスを書き込みロック | +| `TPM2_NV_ReadLock` | NV インデックスを読み取りロック | +| `TPM2_NV_SetBits` | NV ビットフィールドインデックスにビットを OR | +| `TPM2_NV_ChangeAuth` | NV インデックスの認可値を変更 | + +### アテステーションとクレデンシャル + +| コマンド | 説明 | +|---------|-------------| +| `TPM2_Quote` | 署名付き PCR クォートを生成 | +| `TPM2_Certify` | ロード済みの鍵を証明 | +| `TPM2_CertifyCreation` | 鍵がこの TPM で作成されたことを証明 | +| `TPM2_GetTime` | TPM クロックの署名付きアテステーション | +| `TPM2_NV_Certify` | NV インデックスの内容を証明 | +| `TPM2_MakeCredential` | 鍵用のクレデンシャルブロブを作成 | +| `TPM2_ActivateCredential` | クレデンシャルブロブをアンラップ | + +## コマンドカバレッジ + +### 実装済み (Revision 1.38 のコマンドコード 103 個) + +このページではコマンド名ではなくコマンドコードを数え、標準の合計から `TPM_CC_Vendor_TCG_Test` を除外しています。Revision 1.38 は 112 個の標準コマンドコードを定義しています。RSA、ECC、AES、およびすべての機能グループを有効にした場合、ディスパッチテーブルにはそのうち 103 個が含まれ、これは Revision 1.38 の約 92% にあたります。Version 185 のポスト量子コマンドがさらに 8 個加わります。エントリ数を 113 にするには、`WOLFTPM_SPDM` (コマンド 1 個、`PolicyTransportSPDM` が追加されます) とテスト専用のベンダーコマンドも必要です。 + +**コアセット、ゲートされない (36 コマンド):** +Startup, Shutdown, SelfTest, IncrementalSelfTest, GetTestResult, GetRandom, StirRandom, GetCapability, TestParms, PCR_Read, PCR_Extend, PCR_Reset, PCR_Event, PCR_Allocate, PCR_SetAuthPolicy, PCR_SetAuthValue, CreatePrimary, FlushContext, ReadPublic, Clear, ClearControl, ChangeEPS, ChangePPS, HierarchyControl, HierarchyChangeAuth, SetPrimaryPolicy, EvictControl, Create, ObjectChangeAuth, Load, Sign, VerifySignature, StartAuthSession, Unseal, LoadExternal, CreateLoaded + +これらはすべてのビルドに含まれます。 + +**オプションのベンダーコマンド (デフォルトではオフ、`WOLFTPM_FWTPM_TCG_TEST`):** +Vendor_TCG_Test + +**アルゴリズムに依存 (`NO_RSA`、`HAVE_ECC`、`NO_AES`):** +RSA_Encrypt, RSA_Decrypt, ECDH_KeyGen, ECDH_ZGen, ECC_Parameters, EC_Ephemeral, ZGen_2Phase, EncryptDecrypt, EncryptDecrypt2 + +**機能マクロに依存:** + +- `FWTPM_NO_POLICY`: PolicyGetDigest, PolicyRestart, PolicyPCR, PolicyPassword, PolicyAuthValue, PolicyCommandCode, PolicyOR, PolicySecret, PolicyAuthorize, PolicyLocality, PolicySigned, PolicyNV, PolicyPhysicalPresence, PolicyCpHash, PolicyNameHash, PolicyDuplicationSelect, PolicyNvWritten, PolicyTemplate, PolicyCounterTimer, PolicyTicket, PolicyAuthorizeNV (21 コマンド)。条件付きの `PolicyTransportSPDM` コマンドもゲートします。 +- `FWTPM_NO_NV`: NV_DefineSpace, NV_UndefineSpace, NV_UndefineSpaceSpecial, NV_ReadPublic, NV_Write, NV_Read, NV_Extend, NV_Increment, NV_WriteLock, NV_ReadLock, NV_SetBits, NV_ChangeAuth, NV_GlobalWriteLock (13 コマンド)。ポリシーが有効な場合は PolicyNV と PolicyAuthorizeNV もゲートし、`FWTPM_CTX` からメモリ内の NV インデックススロットを削除します。NV_Certify は `FWTPM_NO_ATTESTATION` に加えて `FWTPM_NO_NV` でもゲートされます。 +- `FWTPM_NO_ATTESTATION`: Quote, Certify, CertifyCreation, GetTime, NV_Certify (NV_Certify は `FWTPM_NO_NV` でも削除されます) +- `FWTPM_NO_CREDENTIAL`: MakeCredential, ActivateCredential +- `FWTPM_NO_DA`: DictionaryAttackLockReset, DictionaryAttackParameters (2 コマンド) +- `FWTPM_NO_PARAM_ENC`: コマンドおよびレスポンスパラメータの暗号化と復号を無効にします。セッションは HMAC 認可として引き続き機能しますが、暗号化トランスポートは無効になります。AES-CFB と XOR のパラメータ暗号化を削除することでコードサイズを削減します。 +- `FWTPM_NO_KEY_MIGRATION`: Import, Duplicate, Rewrap (3 コマンド)。Create と Load が使用する共有の鍵ヘルパーは残ります。 +- `FWTPM_NO_ECDH`: ECDH_KeyGen, ECDH_ZGen, EC_Ephemeral, ZGen_2Phase, ECC_Parameters (5 コマンド)。ECDSA の署名と検証は残ります。`FWTPM_CTX` から `ecEphemeral*` のコミット状態も削除します。 +- `FWTPM_NO_HASH_CMDS`: Hash, HMAC, HMAC_Start, HashSequenceStart, SequenceUpdate, SequenceComplete, EventSequenceComplete (7 コマンド)。`WOLFTPM_MLDSA` がビルドされている場合、ML-DSA の検証シーケンスがメッセージを SequenceUpdate 経由でストリーミングするため、SequenceUpdate のみが残ります。SequenceComplete は共有されません。ML-DSA のシーケンスは SignSequenceComplete と VerifySequenceComplete で完了するため、ゲートされたビルドで SequenceComplete を公開すると、決して成功しないコマンドを公開することになります。また、`FWTPM_CTX` からインスタンスごとのハッシュシーケンススロット (`hashSeq[FWTPM_MAX_HASH_SEQ]`) も削除します。 +- `FWTPM_NO_CONTEXT`: ContextSave, ContextLoad (2 コマンド)。FlushContext は残ります。`FWTPM_CTX` から起動ごとのコンテキスト保護鍵と保存済みコンテキストのリプレイリストも削除します。 +- `FWTPM_NO_SYM_ENCRYPT`: EncryptDecrypt, EncryptDecrypt2 (2 コマンド)。`NO_AES` の内側にネストされます。AES 自体は、セッションパラメータ暗号化、AES-GCM、および (`FWTPM_NO_CONTEXT` も設定されていない場合は) コンテキスト保護のために残ります。 +- `FWTPM_NO_CLOCK`: ReadClock, ClockSet, ClockRateAdjust (3 コマンド)。GetTime はこのフラグではなく `FWTPM_NO_ATTESTATION` の対象です。 +- `FWTPM_NO_PP`: PolicyPhysicalPresence と物理プレゼンスの強制。物理プレゼンス HAL、プラットフォームラッチ、および `FWTPM_PP_SetHAL` を削除します。 + +これらのゲートは独立しており、意図的に包括的なマクロは用意されていません。fTPM に不要なグループだけを正確に選択してください。すべてのゲートを適用すると、常に存在する 36 個のコアコマンドと、アルゴリズム構成によって残るコマンドだけが残ります (NV を残すか、`FWTPM_NO_NV` を追加して NV も削除する)。具体的な選択例については、`wolftpm-examples` リポジトリの MicroBlaze V サンプル ([使用方法](usage.md)に記載) を参照してください。 + +### 未実装コマンド + +#### Revision 1.38 ベースライン (未実装のコマンドコード 9 個) + +中程度 (処理はやや複雑で、既存のインフラを土台にできる): + +| コマンド | 仕様セクション | 難易度 | 備考 | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_SetCommandCodeAuditStatus` | 21.2 | 中 | 監査対象コマンドのリストを管理。コンテキストに監査ビットマップが必要 | +| `TPM2_PP_Commands` | 26.2 | 中 | 物理プレゼンスコマンドのリストを管理。PP コマンドのビットマップが必要 | + +高 (複雑な暗号処理または新しいサブシステムが必要): + +| コマンド | 仕様セクション | 難易度 | 備考 | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_GetSessionAuditDigest` | 18.5 | 高 | セッション監査ダイジェストに署名。セッション監査の追跡 (セッション内の全コマンドの連続ハッシュ) が必要。新しいサブシステム | +| `TPM2_GetCommandAuditDigest` | 18.6 | 高 | コマンド監査ダイジェストに署名。連続ハッシュを持つコマンド監査ログが必要。新しいサブシステム | +| `TPM2_Commit` | 19.2 | 高 | DAA と匿名アテステーションの一時鍵。複雑な ECC 点演算 (K、L、E の生成)。wolfCrypt での DAA サポートが必要 | +| `TPM2_SetAlgorithmSet` | 26.3 | 高 | ベンダー固有のアルゴリズム設定。実装されることはまれで、TPM_RC_COMMAND_CODE を返してもよい | +| `TPM2_FieldUpgradeStart` | 27.2 | 高 | ファームウェアアップグレードの開始。ベンダー固有で、安全な更新基盤が必要 | +| `TPM2_FieldUpgradeData` | 27.3 | 高 | ファームウェアアップグレードのデータブロック。ベンダー固有 | +| `TPM2_FirmwareRead` | 27.4 | 高 | バックアップ用にファームウェアを読み取り。ベンダー固有 | + +#### Revision 1.59 での追加 (新しいコマンドコード 5 個) + +`TPM2_MAC` はコマンドコード 0x155 を `TPM2_HMAC` と共有し、`TPM2_MAC_Start` は 0x15B を `TPM2_HMAC_Start` と共有しているため、新しいコードは追加されません。ソースコードには HMAC 形式のみが見られ (CMAC の処理は見つかりませんでした)、対称鍵による MAC 形式がサポートされているかどうかは確認できていません。 + +| コマンド | 仕様セクション | 難易度 | 備考 | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_MAC` | 15.6 | 中 | ブロック暗号 MAC (CMAC)。HMAC に似ているが対称鍵を使用。wolfCrypt の CMAC が必要 | +| `TPM2_MAC_Start` | 17.3 | 中 | MAC シーケンスを開始。CMAC 向けに HMAC_Start と対をなす | +| `TPM2_CertifyX509` | 18.8 | 高 | 部分的な X.509 証明書を生成。複雑な ASN.1 構築が必要で、呼び出し側が tbsCert テンプレートを提供する。Version 184 で非推奨 | +| `TPM2_AC_GetCapability` | 32.2 | 高 | Version 184 で非推奨。アタッチされたコンポーネントのケイパビリティ照会。ハードウェア固有で、ソフトウェア TPM ではほとんど不要 | +| `TPM2_AC_Send` | 32.3 | 高 | Version 184 で非推奨。アタッチされたコンポーネントへのデータ送信。ハードウェア固有 | +| `TPM2_Policy_AC_SendSelect` | 32.4 | 中 | Version 184 で非推奨。AC_Send 用のポリシー。他のポリシーコマンドと同様 | +| `TPM2_ACT_SetTimeout` | 33.2 | 中 | 認証付きカウントダウンタイマーを設定。ACT の状態とタイマー基盤が必要 | + +#### Version 184 での追加 (コマンドコード 9 個、未実装 8 個) + +Version 184 では、`CreateLoaded`、`AC_GetCapability`、`AC_Send`、`Policy_AC_SendSelect`、`CertifyX509` が非推奨とされています。`CreateLoaded` はここでは引き続き実装されています。 + +| コマンド | 仕様セクション | 難易度 | 備考 | +|------------------------------------------|--------|--------|------------------------------------------| +| `TPM2_ECC_Encrypt` | 14.8 | 中 | Part 1 Annex C で定義された TPM 固有の構成 (一時的な ECDH 点、KDF によるマスキング、および完全性データ) を用いる ECC ベースの暗号化。このコマンドではスキームを選択できません。 | +| `TPM2_ECC_Decrypt` | 14.9 | 中 | ECC ベースの復号。ECC_Encrypt と対をなす | +| `TPM2_PolicyCapability` | 23.x | 易 | ポリシーセッションで TPM のケイパビリティ値をアサート | +| `TPM2_PolicyParameters` | 23.x | 易 | ポリシーセッションでコマンドパラメータをアサート | +| `TPM2_SetCapability` | 30.x | 中 | TPM のケイパビリティ設定を変更。プラットフォーム認可が必要 | +| `TPM2_NV_DefineSpace2` | 31.x | 中 | 拡張 NV 領域の定義 (より大きな属性フィールド)。既存の NV_DefineSpace を拡張 | +| `TPM2_NV_ReadPublic2` | 31.x | 易 | 拡張 NV のパブリック読み取り。既存の NV_ReadPublic を拡張 | +| `TPM2_ReadOnlyControl` | 24.x | 易 | TPM の読み取り専用モードを切り替え。単純なフラグ | + +#### 条件付きで実装 + +`TPM2_PolicyTransportSPDM` は、`WOLFTPM_SPDM` が有効な場合は常にハンドラとディスパッチテーブルのエントリを持ち、`FWTPM_NO_POLICY` によって削除されます。未実装ではありません。[SPDM レスポンダ](spdm.md)を参照してください。 + +### カバレッジのまとめ + +8 つの Version 185 PQC コマンド (`TPM2_Encapsulate`、`TPM2_Decapsulate`、`TPM2_SignDigest`、`TPM2_VerifyDigestSignature`、`TPM2_SignSequenceStart`、`TPM2_SignSequenceComplete`、`TPM2_VerifySequenceStart`、`TPM2_VerifySequenceComplete`) は、`--enable-pqc` の下で実装されています。これらのコマンドの PQC 限定の制約については、[ポスト量子サポート](post-quantum.md)を参照してください。 + +| 仕様バージョン | コマンドコード総数 | 実装済み (デフォルトビルド) | 未実装 | カバレッジ | +|-------------|---------------------|-----------------------------|---------|----------| +| Revision 1.38 | 112 | 103 | 9 | 92% | +| Revision 1.59 | 117 | 103 | 14 | 88% | +| Version 184 | 126 | 103 | 23 | 82% | +| Version 185 | 134 | 111 | 23 | 83% | + +実装済みの数は、RSA、ECC、AES、およびすべての機能グループが有効で、SPDM、PQC (Version 185 の行を除く)、およびベンダーテストコマンドが無効であることを前提としています。`WOLFTPM_SPDM` を有効にすると `PolicyTransportSPDM` が加わります (実装済みのコードが 1 個増えます)。Version 185 の行には 8 個の PQC コマンドが含まれます。 + +既知の制限: `TPM2_SelfTest` は最小限のスモークテストで、`TPM2_IncrementalSelfTest` はスタブです (前述のとおり)。また、`SU_STATE` による再開はサポートされていません (ライフサイクルのセクションを参照)。上記のコマンドカバレッジを、TCG 仕様への完全な準拠を示すものと解釈しないでください。 + +## 起動とシャットダウンのライフサイクル + +1. **初回起動:** `FWTPM_NV_Init` が NV ファイルを見つけられない場合、ランダムな階層シードを生成し、初期状態を保存します。 +2. **`TPM2_Startup(SU_CLEAR)`:** トランジェントオブジェクトとセッションをフラッシュし、PCR をリセットします。ほとんどの TPM コマンドよりも前に必要です。`TPM2_GetCapability` は `Startup` の前でも受け付けられます。 +3. **通常動作:** コマンドは `FWTPM_ProcessCommand` を通じて処理されます。 +4. **`TPM2_Shutdown`:** NV の状態を保存しますが、"started" フラグはクリアしません。TPM は論理的に電源オンのままです。 +5. **サーバーの再起動** (プロセスの終了と再起動) が電源の再投入に相当します。`TPM2_Startup` を再度呼び出せるのは、電源の再投入後のみです。 + +すでに起動済みの TPM に対して `TPM2_Startup` を呼び出すと、`TPM_RC_INITIALIZE` が返されます。 + +既知の制限: `Startup(SU_STATE)` は、事前に対応する `Shutdown(SU_STATE)` が行われたかどうかを確認せずに受け付けられ、プロセスを再起動すると `FWTPM_CTX` がゼロクリアされて NV に保存された状態だけが再ロードされます。そのため、トランジェントオブジェクトとセッションは再起動をまたいで保持されませんが、仕様に準拠した TPM Resume ではこれらの保持が求められます。揮発性状態のシリアライズと、シャットダウンおよび起動のシーケンスチェックが実装されるまでは、この制限が残ります。 + +## プライマリ鍵の導出 + +プライマリ鍵は、この実装に固有の KDFa ベースの式を用いて、階層シードから決定論的に導出されます。同じシード、同じパブリックテンプレート、同じ `sensitiveCreate.data` からは、常に同じ鍵が生成されます。プライマリオブジェクトの作成については、Revision 1.38 の Clause 27 で説明されています。 + +- **RSA:** 素数 p と q は、ラベル `"RSA p"` と `"RSA q"` を用いた反復的な KDFa、素数判定、CRT 計算によって導出されます。 +- **ECC:** 秘密スカラー d は `KDFa(nameAlg, seed, "ECC", hashUnique, counter)` で導出され、公開点は Q = d*G です。 +- **KEYEDHASH と SYMCIPHER:** 鍵バイト列は `KDFa(nameAlg, seed, label, hashUnique)` で導出されます。KEYEDHASH では、空でない `sensitiveCreate.data` はそのまま使用され、導出されません。 +- **hashUnique:** `H(sensitiveCreate.data || inPublic.unique)` です。`sensitiveCreate.data` は `hashUnique` とキャッシュダイジェストに入力されるため、値が異なれば鍵も異なります。 + +プライマリ鍵キャッシュ (テンプレートの SHA-256、`FWTPM_MAX_PRIMARY_CACHE` スロット) により、`CreatePrimary` を繰り返し呼び出した場合でも、コストの高い RSA 鍵の再導出を避けられます。 + +階層シードは `ChangePPS` (プラットフォーム) と `ChangeEPS` (エンドースメント) で管理されます。`Clear` はオーナー (ストレージプライマリ) シードを再生成し、エンドースメントの認可とポリシー状態をリセットしますが、エンドースメントシードとプラットフォームシードは変更しません。エンドースメントシードを置換するには `ChangeEPS` を使用してください。ヌルシードは `Startup(CLEAR)` のたびに再ランダム化されます。ポスト量子のプライマリ鍵については、[ポスト量子サポート](post-quantum.md)を参照してください。 + +## 関連項目 + +- [ビルド](building.md) +- [使用方法](usage.md) +- [HAL と移植](hal-and-porting.md) +- [ポスト量子サポート](post-quantum.md) +- [SPDM レスポンダ](spdm.md) +- [ポスト量子 (ライブラリ全体)](../post-quantum.md) +- [SPDM (ライブラリ全体)](../spdm.md) diff --git a/docs/ja/fwtpm/post-quantum.md b/docs/ja/fwtpm/post-quantum.md new file mode 100644 index 00000000..65bde478 --- /dev/null +++ b/docs/ja/fwtpm/post-quantum.md @@ -0,0 +1,100 @@ +# fwTPM のポスト量子サポート (TPM 2.0 v1.85) + +fwTPM は、wolfCrypt の FIPS 203 (ML-KEM) および FIPS 204 (ML-DSA) モジュールを使用して、TCG TPM 2.0 Library Specification v1.85 のポスト量子に関する追加仕様を実装しています。これにより、TPM シリコンのないプラットフォームにポスト量子の鍵、署名、鍵カプセル化が提供されます。これらの v1.85 コマンドにより、実装済みのコマンド数は 103 から 111 に増加します。ライブラリ全体のポスト量子に関する概要については、[ポスト量子](../post-quantum.md)を参照してください。 + +configure 時に `--enable-pqc` で有効にします。fwTPM ビルドでは、これは完全な `--enable-v185` に昇格されます。`--enable-fwtpm` が ML-DSA と ML-KEM の両方を備えた wolfCrypt に対してビルドされる場合にも、自動検出されます。どちらのフラグも、実装を制御する内部マクロ `WOLFTPM_V185` を設定します。自動検出で有効になってしまう場合に無効化するには、`--disable-pqc` を指定します。 + +## アルゴリズム + +| アルゴリズム | パラメータセット | 用途 | +|---|---|---| +| `TPM_ALG_MLKEM` (0x00A0) | ML-KEM-512 / 768 / 1024 | 鍵カプセル化 (復号専用の鍵) | +| `TPM_ALG_MLDSA` (0x00A1) | ML-DSA-44 / 65 / 87 | Pure ML-DSA によるメッセージ署名 | +| `TPM_ALG_HASH_MLDSA` (0x00A2) | HashML-DSA-44 / 65 / 87 | 事前ハッシュ済みの ML-DSA 署名 | + +## コマンド + +8 つの v1.85 PQC コマンドは `src/fwtpm/fwtpm_command.c` にあります。 + +| コマンド | CC | 目的 | +|---|---|---| +| `TPM2_Encapsulate` | `0x000001A7` | ML-KEM のカプセル化。sharedSecret と ciphertext を返す | +| `TPM2_Decapsulate` | `0x000001A8` | ciphertext からの ML-KEM のデカプセル化 (USER 認可が必要) | +| `TPM2_SignSequenceStart` | `0x000001AA` | ML-DSA の署名シーケンスを開始 | +| `TPM2_SignSequenceComplete` | `0x000001A4` | メッセージバッファで署名シーケンスを完了 | +| `TPM2_VerifySequenceStart` | `0x000001A9` | ML-DSA の検証シーケンスを開始 | +| `TPM2_VerifySequenceComplete` | `0x000001A3` | 検証シーケンスを完了し、TPMT_TK_VERIFIED を返す | +| `TPM2_SignDigest` | `0x000001A6` | ワンショットのダイジェスト署名 (HashML-DSA または ext-mu ML-DSA) | +| `TPM2_VerifyDigestSignature` | `0x000001A5` | ダイジェスト署名を検証 | + +## プライマリ鍵の導出 + +PQC のプライマリ鍵は、RSA や ECC と同じ決定論的な導出モデルに従います。すなわち、階層シードとテンプレートから KDFa で導出したシードを得て、FIPS 203 または FIPS 204 の鍵展開を行います。 + +- **ML-DSA:** `KDFa(nameAlg, seed, "MLDSA", hashUnique)` から 32 バイトの Xi が得られます。`wc_MlDsaKey_MakeKeyFromSeed` がこれを公開鍵と展開済みの秘密鍵に変換します。ワイヤフォーマットには、TCG Part 2 Table 210 に従い、32 バイトの Xi のみが格納されます。 +- **HashML-DSA:** ラベルは `"HASH_MLDSA"` で、シードのサイズと展開は同じです。 +- **ML-KEM:** `KDFa(nameAlg, seed, "MLKEM", hashUnique)` から 64 バイトの値 (d に続けて z) が得られます。`wc_MlKemKey_MakeKeyWithRandom` がこれをカプセル化鍵とデカプセル化鍵に変換します。ワイヤフォーマットには、TCG Part 2 Table 206 に従い、64 バイトのシードのみが格納されます。 + +!!! note + これらのラベル文字列は解釈に基づくものです。これらを規範的に規定するはずの TCG Part 4 v185 は未公開です。後のリリース候補または Part 4 v185 が異なるラベルを規定した場合、変更される可能性があります。 + +## 署名および検証シーケンス + +Pure ML-DSA のシーケンスは、署名と検証の両方でストリーミングが可能なため、`TPM2_SequenceUpdate` が受け付けられます。`TPM_RC_ONE_SHOT_SIGNATURE` が適用されるのは EdDSA のようなマルチパスのスキームであり、Pure ML-DSA には適用されません。呼び出し側は、メッセージ全体を `TPM2_SignSequenceComplete` の `buffer` パラメータ経由で渡すこともできます。`TPM2_VerifySequenceComplete` には buffer パラメータがないため、検証シーケンスは `TPM2_SequenceUpdate` を通じてメッセージを蓄積します。 + +HashML-DSA のシーケンス (署名と検証の両方) は、wolfCrypt の `wc_HashAlg` コンテキストを使用して、メッセージを鍵のハッシュアルゴリズムへストリーミングします。`TPM2_SignSequenceComplete` はハッシュを完了し、`wc_MlDsaKey_SignCtxHash` を呼び出します。 + +署名のワイヤフォーマットは、仕様 Part 2 Table 217 に従って異なります。 + +- **Pure ML-DSA:** `TPM2B_SIGNATURE_MLDSA`。`sigAlg + size + bytes` の配置 +- **HashML-DSA:** `TPMS_SIGNATURE_HASH_MLDSA`。`sigAlg + hashAlg + size + bytes` の配置 + +## バッファ定数 + +`WOLFTPM_V185` のもとでは、ML-DSA-87 の署名 (4627 バイト) と公開鍵 (2592 バイト) に収まるようにバッファが拡大されます。 + +| シンボル | v1.38 | v1.85 | +|---|---|---| +| `FWTPM_MAX_COMMAND_SIZE` | 4096 | 8192 | +| `FWTPM_MAX_PUB_BUF` | 512 | 2720 | +| `FWTPM_MAX_DER_SIG_BUF` | 256 | 4736 | +| `FWTPM_MAX_KEM_CT_BUF` | n/a | 1600 | +| `FWTPM_TIS_FIFO_SIZE` | 4096 | 8192 | +| `FWTPM_NV_PUBAREA_EST` | 600 | 2720 | + +これらは最悪ケースの値です。デフォルト値は、wolfCrypt のビルド時に有効だったパラメータセットに合わせて、コンパイル時に縮小されます。パラメータセットごとの表については、[ビルド](building.md)の "v1.85 Embedded RAM Impact" を参照してください。 + +## 制限事項と対象範囲 + +v1.85 コマンドは、ポスト量子の鍵に対してのみ実装されています。仕様がこれらのコマンドを汎用的に定義している場合でも、PQC 以外の鍵タイプは `TPM_RC_KEY` または `TPM_RC_SCHEME` で拒否されます。 + +- `TPM2_Encapsulate` と `TPM2_Decapsulate`: ML-KEM のみ。ECC DHKEM (非 NULL の KDF を伴う Table 100 の `ecdh` アーム) は実装されていません。 +- `TPM2_SignSequenceStart`、`TPM2_VerifySequenceStart`、`TPM2_SignSequenceComplete`、`TPM2_VerifySequenceComplete`: ML-DSA と HashML-DSA のみ。仕様がこれらのコマンドを通じて許可している従来のスキーム (RSASSA、RSAPSS、ECDSA、SM2、ECSCHNORR、HMAC) はサポートされていません。 +- `TPM2_SignDigest` と `TPM2_VerifyDigestSignature`: ML-DSA と HashML-DSA のみ。これらの新しいコマンドによる従来のダイジェスト署名 (RSASSA、RSAPSS、ECDSA) はサポートされていません。これらのスキームには、既存の `TPM2_Sign` と `TPM2_VerifySignature` コマンドを使用してください。 + +## 先送りおよび対象外 + +3 つの v1.85 機能は、それぞれ文書化された理由により先送りされています。 + +1. **ML-KEM をソルトとするセッション。** Part 3 Sec.11.1 (`TPM2_StartAuthSession`) には、RSA-OAEP と ECDH のパスに並ぶ ML-KEM の項目の記述がありませんが、Part 2 Sec.11.4.2 Table 222 は `TPMU_ENCRYPTED_SECRET` の `mlkem` アームを定義しています。これを規範的に規定するはずの Part 4 v185 は、まだ公開されていません。現在の動作: ML-KEM の tpmKey に対して `TPM2_StartAuthSession` は `TPM_RC_KEY` を返します。Part 4 v185 が公開された時点で見直します。 +2. **External-mu ML-DSA 署名。** wolfCrypt には mu を直接指定する署名 API がありません。Part 2 Sec.12.2.3.7 は "512-byte external Mu" としていますが、FIPS 204 Algorithm 7 Line 6 は 64 バイト (SHAKE256 の出力) を生成します。wolfCrypt への API 追加と TCG の正誤表による確認を待っています。現在の動作: ext-mu のパスには `TPM_RC_SCHEME` を、`allowExternalMu` のない Pure ML-DSA 鍵には `TPM_RC_EXT_MU` を返します。 +3. **Encapsulate と Decapsulate の ECC KEM アーム。** Part 2 Sec.10.3.13 Table 100 には `mlkem` と `ecdh` の両方のアームがありますが、表の注記では、実装がサポートするアルゴリズムに基づいてユニオンを変更することを許容しています。fwTPM がサポートするのは `mlkem` アームのみです。 + +## テストカバレッジ + +`tests/fwtpm_unit_tests.c` には、全パスを検証する 10 個の PQC テストが含まれています。 + +- ML-KEM-768 と ML-DSA-65 の CreatePrimary +- Encapsulate と Decapsulate の完全なラウンドトリップ (共有秘密のバイト一致) +- HashML-DSA の SignDigest と VerifyDigestSignature のラウンドトリップ +- Pure ML-DSA の署名シーケンスと検証シーケンスのラウンドトリップ +- ML-DSA-44 の検証、ML-DSA-44 の鍵生成の決定性、乱数を固定した ML-KEM-512 のカプセル化、ML-KEM-512 の鍵生成の決定性に対する、2 つのソース (NIST ACVP と wolfSSL 内部ベクタ) による既知解テスト +- fwTPM ハンドラー経由での NIST ACVP の ML-DSA-44 公開鍵の LoadExternal + +## 関連項目 + +- [概要](overview.md) +- [ビルド](building.md) +- [使用方法](usage.md) +- [SPDM レスポンダ](spdm.md) +- [ポスト量子 (ライブラリ全体)](../post-quantum.md) diff --git a/docs/ja/fwtpm/spdm.md b/docs/ja/fwtpm/spdm.md new file mode 100644 index 00000000..7e742c73 --- /dev/null +++ b/docs/ja/fwtpm/spdm.md @@ -0,0 +1,64 @@ +# fwTPM の SPDM レスポンダ + +fwTPM には SPDM 1.3 レスポンダが同梱されているため、シリコンの裏付けがない TPM に対して SPDM スタック全体を検証できます。TCG の raw 公開鍵ハンドシェイク (GET_PUBK と GIVE_PUB、証明書なし) と、DSP0274 の事前共有鍵 (PSK) ハンドシェイクの両方をサポートしています。これにより、実際のハードウェアが利用可能になる前に、CI やワークステーション上で SPDM で保護された TPM 通信を開発およびテストできます。ライブラリ全体の SPDM に関する概要については、[SPDM](../spdm.md)を参照してください。 + +## 動作の仕組み + +SPDM が有効な場合、レスポンダは既存のトランスポート HAL の上位に位置し、TCG フレーミングされたメッセージを SPDM ステートマシンへディスパッチします。2 つのメッセージタグは次のとおりです。 + +| タグ | 意味 | +|-----|---------| +| `0x8101` | クリア (保護されていない) SPDM メッセージ | +| `0x8201` | セキュア SPDM メッセージ | + +平文の TPM フレームは、リクエスタが `SPDMONLY LOCK` を発行するまで、通常のコマンドディスパッチャに渡されます。その後は `TPM2_GetCapability` のみが平文で許可され、これは Nuvoton および Nations のシリコンの動作と一致します。 + +## ビルド + +`--enable-fwtpm --enable-spdm` に加えて、`--enable-tcg` または `--enable-psk` の少なくとも一方を指定してビルドします。 + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-spdm --enable-tcg --enable-psk --enable-nuvoton --enable-nations +make +``` + +## レスポンダの起動 + +サーバーは 3 つのモードのいずれかで起動します。 + +```sh +SPDM_PSK=dbc2192291d807742441b963f6712841f7697e2e39c45931f3abc53658c8b9338bd3561cab5d90cf9e493295bb5bd6b2c455e0fd19392e0ce4f3433cbcfc7047 +./src/fwtpm/fwtpm_server --spdm-tcg # TCG raw public key handshake +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" # PSK handshake +./src/fwtpm/fwtpm_server --no-spdm # plaintext only (default) +``` + +レスポンダは、空ではなく最大 64 バイト (16 進数 128 文字) の PSK を受け付けます。64 バイトちょうどであることが求められるのは Nations ハードウェアのプロビジョニングであり、このレスポンダではありません。上記の値は `spdm_test.sh` で使用されるテスト値です。手動で PSK をテストする場合は、リクエスタにも同じ値を指定してください (例: `spdm_ctrl --psk "$SPDM_PSK"`)。 + +## レスポンダの ID 鍵 + +レスポンダは起動時に新しい P-384 の ID 鍵ペアを生成します。これは `GET_PUBK` と `KEY_EXCHANGE` への署名に使用されます。秘密鍵が `fwtpm_server` のメモリの外に出ることはなく、スタック上のコピーは、レスポンダコンテキストに渡された後に `wc_ForceZero` でゼロ化されます。 + +TCG モードでは、サーバーは起動時に公開鍵側を出力します。これにより、ローカルのテストハーネスが、レスポンダ鍵ピンニング API を通じてリクエスタへ渡せます。 + +!!! warning + この出力される公開鍵は、テスト用のブートストラップチャネルです。認証されたデバイスのプロビジョニングの代わりにはならず、ハードウェアレスポンダ向けのトラストアンカーでもありません。 + +## テスト + +エンドツーエンドのカバレッジには、実際のシリコンを駆動するのと同じスクリプトを使用します。 + +```sh +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-tcg +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-psk +``` + +CI は、`spdm-test.yml` を通じて `ubuntu-latest` 上で、7 つのビルドのみの configure の組み合わせと、2 つのエンドツーエンドモードを、fwTPM の SPDM レスポンダに対して実行します。 + +## 関連項目 + +- [概要](overview.md) +- [ビルド](building.md) +- [使用方法](usage.md) +- [ポスト量子サポート](post-quantum.md) +- [SPDM (ライブラリ全体)](../spdm.md) diff --git a/docs/ja/fwtpm/usage.md b/docs/ja/fwtpm/usage.md new file mode 100644 index 00000000..55f1a504 --- /dev/null +++ b/docs/ja/fwtpm/usage.md @@ -0,0 +1,292 @@ +# fwTPM の使用方法 + +このページでは、fwTPM サーバーの実行、クライアントの接続、トランスポートモード、NV の永続化、テスト、C API、および実際のボードでのサンプルについて説明します。先にサーバーをビルドするには、[ビルド](building.md)を参照してください。 + +## サーバーの起動 + +```sh +./src/fwtpm/fwtpm_server [options] +``` + +**オプション:** + +| オプション | 説明 | +|--------|-------------| +| `--help`, `-h` | 使用方法を表示 | +| `--version`, `-v` | バージョン文字列を表示 | +| `--port ` | コマンドポート (デフォルト: 2321) | +| `--platform-port ` | プラットフォームポート (デフォルト: 2322) | +| `--clear` | NV をクリアした状態で起動 | +| `--spdm-tcg`, `--spdm-psk`, `--no-spdm` | SPDM レスポンダモード ([SPDM レスポンダ](spdm.md)を参照) | + +`--port` と `--platform-port` オプションはソケットモード専用であり、TIS ビルド (`--enable-swtpm` なしの `--enable-fwtpm`) では使用できません。 + +**例:** + +```sh +# Start with default ports (localhost:2321 command, :2322 platform) +./src/fwtpm/fwtpm_server + +# Start on custom ports +./src/fwtpm/fwtpm_server --port 2331 --platform-port 2332 + +# Start with clear NV +./src/fwtpm/fwtpm_server --clear +``` + +サーバーは起動時に設定を出力します。 + +``` +wolfTPM fwTPM Server v0.1.0 + Command port: 2321 + Platform port: 2322 + Manufacturer: WOLF + Model: fwTPM +``` + +`--spdm-tcg` のテストモードでは、サーバーは生成したレスポンダの公開鍵も出力します。これはローカルのテストハーネス向けの便宜であり、ハードウェアレスポンダ向けのプロビジョニングやトラストアンカーのチャネルではありません。 + +## wolfTPM クライアントの接続 + +`--enable-swtpm` でビルドされた wolfTPM アプリケーションは、TCP 経由で fwTPM サーバーに自動的に接続します。組み込みの swtpm クライアントは mssim プロトコルを使用します。 + +```sh +# In one terminal: start the server +./src/fwtpm/fwtpm_server + +# In another terminal: run wolfTPM examples +./examples/wrap/wrap_test +./examples/wrap/caps +./examples/keygen/keygen keyblob.bin -rsa -t +./examples/attestation/make_credential +``` + +### tpm2-tools の使用 + +ソケットモード (`--enable-swtpm`) では、サーバーは mssim (Microsoft TPM シミュレータ) と swtpm (Stefan Berger) の両方の TCTI プロトコルをサポートし、コマンドポート上で自動検出します。どちらの TCTI も使用できます。 + +```sh +# mssim TCTI (default for wolfTPM test scripts) +export TPM2TOOLS_TCTI="mssim:host=localhost,port=2321" +tpm2_startup -c + +# swtpm TCTI (also works, auto-detected) +export TPM2TOOLS_TCTI="swtpm:host=localhost,port=2321" +tpm2_getrandom 8 +``` + +## NV の永続化 + +サーバーは、永続的な状態 (階層シード、認可値、PCR の状態、NV インデックス) を `fwtpm_nv.bin` (`FWTPM_NV_FILE` で変更可能) に保存します。初回起動時にシードがランダムに生成されて保存され、以降の起動では既存の状態が再読み込みされます。 + +組み込みターゲットでは、ファイルバックエンドをフラッシュ、EEPROM、その他の NV HAL に置き換えます。ライトワンスフラッシュ向けのアペンドオンリーモードも含まれます。[HAL と移植](hal-and-porting.md)を参照してください。 + +## トランスポートモード + +### ソケット / SWTPM (デフォルト) + +`--enable-fwtpm --enable-swtpm` でビルドします。サーバーは SWTPM ワイヤプロトコルを使用して 2 つの TCP ポートで待ち受けます。 + +- **コマンドポート** (デフォルト 2321): TPM コマンドとレスポンスのトラフィック +- **プラットフォームポート** (デフォルト 2322): プラットフォームシグナル (電源オンとオフ、NV オン、キャンセル、リセット、セッション終了、停止) + +**SWTPM TCP プロトコルのコマンド** (プラットフォームポート): + +| シグナル | 値 | 説明 | +|--------|-------|-------------| +| `SIGNAL_POWER_ON` | 1 | TPM の電源をオン | +| `SIGNAL_POWER_OFF` | 2 | TPM の電源をオフ | +| `SIGNAL_PHYS_PRES_ON` | 3 | 物理プレゼンスをアサート | +| `SIGNAL_PHYS_PRES_OFF` | 4 | 物理プレゼンスをデアサート | +| `SIGNAL_HASH_START` | 5 | メジャードブートのハッシュを開始 | +| `SIGNAL_HASH_DATA` | 6 | メジャードブートのデータを提供 | +| `SIGNAL_HASH_END` | 9 | メジャードブートのハッシュを終了 | +| `SEND_COMMAND` | 8 | TPM コマンドを送信 (コマンドポート) | +| `SIGNAL_NV_ON` | 11 | NV ストレージが利用可能 | +| `SIGNAL_CANCEL_ON` | 13 | 現在のコマンドをキャンセル | +| `SIGNAL_CANCEL_OFF` | 14 | キャンセルを解除 | +| `SIGNAL_RESET` | 17 | TPM をリセット | +| `SESSION_END` | 20 | TCP セッションを終了 | +| `STOP` | 21 | サーバーを停止 | + +wolfTPM クライアントは標準の SWTPM インターフェースを通じて接続します。これは `tpm2-tools` やその他の SWTPM 対応ソフトウェアと互換性があります。 + +### TIS / 共有メモリ + +`--enable-fwtpm` (`--enable-swtpm` なし) でビルドします。このモードは、POSIX 共有メモリと名前付きセマフォを使用して、TIS (TPM Interface Specification) のレジスタレベルのアクセスをエミュレートします。SPI 接続の TPM をシミュレートします。 + +**共有メモリのレイアウト** (`FWTPM_TIS_SHM`): + +| フィールド | 説明 | +|-------|-------------| +| `magic` / `version` | 検証用ヘッダー (`0x57544953` / "WTIS"、プロトコルバージョン 2) | +| `reg_addr`, `reg_len`, `reg_is_write`, `reg_data` | レジスタアクセス要求 | +| TIS レジスタシャドウ: `access`, `sts`, `int_enable`, `int_status`, `intf_caps`, `did_vid`, `rid` | エミュレートされた TIS レジスタ | +| `cmd_buf[4096]`, `cmd_len`, `fifo_write_pos` | コマンド FIFO | +| `rsp_buf[4096]`, `rsp_len`, `fifo_read_pos` | レスポンス FIFO | + +**パス** (コンパイル時に設定可能): + +| 定義 | デフォルト | 説明 | +|--------|---------|-------------| +| `FWTPM_TIS_SHM_PATH` | `/tmp/fwtpm.shm` | 共有メモリファイル。クライアントは、通常ファイル、単一リンク、同一 UID、サイズが完全一致する `0600` のエンドポイントを必要とします | +| `FWTPM_TIS_SEM_CMD` | `/fwtpm_cmd` | コマンドセマフォの名前 | +| `FWTPM_TIS_SEM_RSP` | `/fwtpm_rsp` | レスポンスセマフォの名前 | + +クライアントは、プロトコルバージョンと共有領域サイズの完全一致を要求します。`FWTPM_TIS_FIFO_SIZE` に影響するオプションを変更する場合は、クライアントライブラリと `fwtpm_server` を併せて再ビルドしてください。デフォルトのパスはグローバルであるため、ホストごとに 1 つのサーバーを実行してください。 + +**サーバー側 API:** + +- `FWTPM_TIS_Init()`: 共有メモリとセマフォを作成 +- `FWTPM_TIS_Cleanup()`: 共有メモリとセマフォを削除 +- `FWTPM_TIS_ServerLoop()`: TIS レジスタアクセスを処理し、コマンドをディスパッチ + +**クライアント側 API** (`WOLFTPM_FWTPM_HAL` で有効化): + +- `FWTPM_TIS_ClientConnect()`: 既存の共有メモリにアタッチ +- `FWTPM_TIS_ClientDisconnect()`: 共有メモリからデタッチ + +## テスト + +```sh +make check # Build + unit.test + run_examples.sh + tpm2-tools +scripts/tpm2_tools_test.sh # tpm2-tools only (311 tests) +``` + +`make check` は `tests/fwtpm_check.sh` を実行し、これが `fwtpm_server` を自動的に起動および停止します。このためにサーバーを手動で起動しないでください。 + +### CI テスト (fwtpm-test.yml) + +以下のテストはすべて GitHub Actions の CI で実行されます。PR を提出する前に手動で実行してください。ASan、UBSan、LeakSan のカバレッジは、このワークフローではなく `sanitizer.yml` にあります。 + +**ランタイムテスト (ビルド、run_examples.sh、make check):** + +| 名前 | wolfTPM の設定 | 追加 | 備考 | +|------|---------------|-------|-------| +| fwtpm-socket | `--enable-fwtpm --enable-swtpm --enable-debug` | | 主要なテスト | +| fwtpm-tis | `--enable-fwtpm --disable-swtpm --enable-debug` | | TIS/SHM トランスポート | +| fwtpm-v185 | `--enable-fwtpm --enable-v185` | | PQC: ラッパーとハンドラーのユニットテスト | +| fwtpm-macos-socket | `--enable-fwtpm --enable-swtpm --enable-debug` | | macOS ランナー | + +**ランタイムテスト、ゲートされたビルド (`fwtpm-gated-runtime` ジョブ):** + +これらの構成はコマンドを削除するため、(サンプルと tpm2-tools を実行する) `make check` は適用できません。このジョブは `tests/fwtpm_unit.test` のみをビルドして実行します。`test_fwtpm_command_gates`、`test_fwtpm_total_commands`、`test_fwtpm_pcr_bounds` の各ケースは、ゲートされたコマンドが `TPM_RC_COMMAND_CODE` で拒否されること、`TPM_CAP_COMMANDS` に含まれないこと、`TPM_PT_TOTAL_COMMANDS` にカウントされないことを検証します。 + +| 名前 | wolfTPM の設定 | wolfSSL の設定 | 追加の CFLAGS | +|------|---------------|---------------|-------------| +| all-gates-ecc-only | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | 11 個のコマンドグループ `-DFWTPM_NO_*` ゲートをすべて併用 (NV は残す) | +| all-gates-mldsa | `--enable-fwtpm --enable-swtpm --enable-v185 --enable-mldsa` | `--enable-dilithium --enable-mlkem` | 同じ 11 個のゲート。ML-DSA では SequenceUpdate が残り、SequenceComplete が残らないことを検証 | +| reduced-pcr | `--enable-fwtpm --enable-swtpm` | | `-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8` | + +**ビルドのみのテスト:** + +| 名前 | wolfTPM の設定 | wolfSSL の設定 | 追加の CFLAGS | +|------|---------------|---------------|-------------| +| fwtpm-no-rsa | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | | +| fwtpm-no-ecc | `--enable-fwtpm --enable-swtpm` | `--disable-ecc` | | +| fwtpm-no-sha384 | `--enable-fwtpm --enable-swtpm` | `--disable-sha384` | | +| fwtpm-no-sha1 | `--enable-fwtpm --enable-swtpm` | `--disable-sha` | `-DNO_SHA` | +| fwtpm-v185-build-only | `--enable-fwtpm --enable-v185` | | `-DDEBUG_WOLFTPM` | +| fwtpm-only | `--enable-fwtpm-only --enable-swtpm` | | クライアントライブラリなし | +| fwtpm-minimal | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ATTESTATION -DFWTPM_NO_NV -DFWTPM_NO_POLICY -DFWTPM_NO_CREDENTIAL -DFWTPM_NO_DA -DFWTPM_NO_PARAM_ENC` | +| fwtpm-no-policy | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_POLICY` | +| fwtpm-no-nv | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_NV` | +| fwtpm-no-attestation | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ATTESTATION` | +| fwtpm-no-credential | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CREDENTIAL` | +| fwtpm-no-da | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_DA` | +| fwtpm-no-param-enc | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_PARAM_ENC` | +| fwtpm-no-key-migration | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_KEY_MIGRATION` | +| fwtpm-no-ecdh | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_ECDH` | +| fwtpm-no-hash-cmds | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_HASH_CMDS` | +| fwtpm-no-context | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CONTEXT` | +| fwtpm-no-sym-encrypt | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_SYM_ENCRYPT` | +| fwtpm-no-clock | `--enable-fwtpm --enable-swtpm` | | `-DFWTPM_NO_CLOCK` | +| fwtpm-reduced-pcr | `--enable-fwtpm --enable-swtpm` | | `-DIMPLEMENTATION_PCR=8 -DPLATFORM_PCR=8` | +| fwtpm-no-rsa-no-policy | `--enable-fwtpm --enable-swtpm` | `--disable-rsa` | `-DFWTPM_NO_POLICY` | +| fwtpm-no-ecc-no-nv | `--enable-fwtpm --enable-swtpm` | `--disable-ecc` | `-DFWTPM_NO_NV` | +| fwtpm-small-stack | `--enable-fwtpm --enable-swtpm` | | `-DWOLFTPM_SMALL_STACK` | + +**Pedantic ビルド (ビルドのみ、-Werror):** + +| 名前 | コンパイラ | 設定 | +|------|----------|--------| +| fwtpm-pedantic-gcc | gcc | `--enable-fwtpm --enable-swtpm` | +| fwtpm-pedantic-clang | clang | `--enable-fwtpm --enable-swtpm` | +| fwtpm-pedantic-only | gcc | `--enable-fwtpm-only` | + +**別ジョブ: tpm2-tools (311 テスト):** + +```sh +scripts/tpm2_tools_test.sh +``` + +## API リファレンス + +### コア (`fwtpm.h`) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_Init(FWTPM_CTX* ctx)` | fwTPM コンテキストと RNG を初期化し、NV の状態をロード | +| `int FWTPM_Cleanup(FWTPM_CTX* ctx)` | NV を保存し、リソースを解放し、センシティブデータをゼロ化 | +| `const char* FWTPM_GetVersionString(void)` | バージョン文字列を返す (例: `"0.1.0"`) | + +### コマンドプロセッサ (`fwtpm_command.h`) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_ProcessCommand(FWTPM_CTX* ctx, const byte* cmdBuf, int cmdSize, byte* rspBuf, int* rspSize, int locality)` | 生の TPM コマンドパケットを処理し、レスポンスを生成します。処理に成功した場合は `TPM_RC_SUCCESS` を返します。レスポンスバッファには TPM のエラー RC が含まれる場合があります。 | + +### IO トランスポート (`fwtpm_io.h`) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_IO_SetHAL(FWTPM_CTX* ctx, FWTPM_IO_HAL* hal)` | カスタム IO トランスポートのコールバックを登録 | +| `int FWTPM_IO_Init(FWTPM_CTX* ctx)` | トランスポート (ソケットまたはカスタム HAL) を初期化 | +| `void FWTPM_IO_Cleanup(FWTPM_CTX* ctx)` | トランスポートを閉じ、リソースを解放 | +| `int FWTPM_IO_ServerLoop(FWTPM_CTX* ctx)` | メインのサーバーループ。`ctx->running` がクリアされるまでブロック | + +### NV ストレージ (`fwtpm_nv.h`) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_NV_Init(FWTPM_CTX* ctx)` | ストレージから NV の状態をロード、または新規作成 (シードを生成) | +| `int FWTPM_NV_Save(FWTPM_CTX* ctx)` | 現在の TPM の状態を NV ストレージに保存 | +| `int FWTPM_NV_SetHAL(FWTPM_CTX* ctx, FWTPM_NV_HAL* hal)` | カスタム NV ストレージのコールバックを登録 | + +### TIS サーバー (`fwtpm_tis.h`) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_TIS_Init(FWTPM_CTX* ctx)` | 共有メモリ領域とセマフォを作成 | +| `void FWTPM_TIS_Cleanup(FWTPM_CTX* ctx)` | 共有メモリとセマフォをアンリンク | +| `int FWTPM_TIS_ServerLoop(FWTPM_CTX* ctx)` | TIS レジスタアクセスを処理 (ブロック) | + +### TIS クライアント (`fwtpm_tis.h`、`WOLFTPM_FWTPM_HAL` が必要) + +| 関数 | 説明 | +|----------|-------------| +| `int FWTPM_TIS_ClientConnect(FWTPM_TIS_CLIENT_CTX* client)` | fwTPM の共有メモリにアタッチ | +| `void FWTPM_TIS_ClientDisconnect(FWTPM_TIS_CLIENT_CTX* client)` | 共有メモリからデタッチ | + +## 実際のボードでのサンプル + +[wolftpm-examples](https://github.com/wolfSSL/wolftpm-examples) リポジトリには、実際のボード向けの完全な fwTPM プロジェクトが収められています。それぞれが、分離方式またはストレージ方式の異なる選択を示しています。 + +| ボード | プロジェクト | 示している内容 | +|-------|---------|----------------| +| STM32H5 NUCLEO-H563ZI | [STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) | Cortex-M33 TrustZone のセキュアワールド上の fwTPM、内蔵フラッシュの NV、mssim プロトコルを使用する UART | +| Xilinx ZCU102 (R5、ロックステップ) | [Xilinx/fwtpm-zcu102-r5](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zcu102-r5) | AMP: ロックステップの Cortex-R5 ペア上でベアメタル動作する fwTPM、A53 上の PetaLinux クライアントが OpenAMP RPMsg 経由で接続。揮発性の DDR NV または永続的な QSPI | +| Xilinx ZC702 (A9) | [Xilinx/fwtpm-zc702-a9](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-zc702-a9) | SRAM-PUF から導出したデバイス固有の NV 鍵により、ルート鍵をフラッシュに保存しない | +| SCU35 (MicroBlaze-V ソフトコア) | [Xilinx/fwtpm-scu35-microblazev](https://github.com/wolfSSL/wolftpm-examples/tree/main/Xilinx/fwtpm-scu35-microblazev) | 約 190 KB のブロック RAM に収まる ECC 専用の fwTPM | +| PolarFire SoC MPFS250T | [Microchip/fwtpm-polarfire-miv](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/fwtpm-polarfire-miv) | AMP: Linux から分離された U54 ハート上でベアメタル動作する fwTPM、共有 L2-LIM メモリ上の TIS | +| PolarFire MPF300 Splash (ソフト MIV) | [Microchip/miv-mpf300-splash](https://github.com/wolfSSL/wolftpm-examples/tree/main/Microchip/miv-mpf300-splash) | 永続的なオンダイ sNVM を備えたソフト Mi-V コア | + +STM32H5、PolarFire SoC、ZCU102 のプロジェクトは、[HAL と移植](hal-and-porting.md)にも移植例として掲載されています。 + +## 関連項目 + +- [概要](overview.md) +- [ビルド](building.md) +- [HAL と移植](hal-and-porting.md) +- [ポスト量子サポート](post-quantum.md) +- [SPDM レスポンダ](spdm.md) diff --git a/docs/ja/getting-started.md b/docs/ja/getting-started.md new file mode 100644 index 00000000..86238740 --- /dev/null +++ b/docs/ja/getting-started.md @@ -0,0 +1,75 @@ +# はじめに + +wolfTPM は、ネイティブ API、ラッパー API、およびビルド成功後すぐに使えるサンプルアプリケーション群を備えた、ポータブルな TPM 2.0 ライブラリです。サンプルは TPM 2.0 モジュールの機能を示し、`examples/tpm_test.h` で定義されたハンドルを使用して、テスト用の RSA 鍵と ECC 鍵を NV ストレージに作成します。このページでは、チェックアウト直後の状態から最初のサンプルを動作させるまでの最短手順を説明します。 + +## 前提条件と wolfSSL のビルド + +wolfTPM には、wolfTPM 用オプションを有効にしてビルドした wolfSSL (wolfCrypt) が必要です。最初に wolfSSL をビルドしてインストールします。 + +```bash +git clone https://github.com/wolfSSL/wolfssl.git +cd wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +sudo ldconfig +``` + +`autogen.sh` には automake と libtool が必要です: `sudo apt-get install automake libtool`。 + +別のディレクトリにインストールした wolfSSL を使用する方法については、[wolfTPM のビルド](building.md)を参照してください。 + +## wolfTPM のビルド + +```bash +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +./autogen.sh +./configure +make +``` + +!!! note + Linux の x86_64 と aarch64 では、オプションなしの `./configure` を実行すると、ソフトウェア TPM バックエンド (swTPM と fwTPM) が自動的に有効になります。これにより、TPM ハードウェアを接続しなくても `make check` を実行できます。`--enable-devtpm` や `--enable-autodetect` などのハードウェア向けパスを選択すると、この既定の動作は無効になります。[システムインターフェース](system-interfaces.md)を参照してください。 + +ハードウェア固有のビルド手順については、[対応ハードウェア](supported-hardware.md)を参照してください。 + +## 最初のサンプルを実行する + +サンプルを実行する前に、TPM に接続できる状態である必要があります。Linux x86_64 および aarch64 の既定のビルドでは、サンプルはソケット経由でソフトウェア TPM と通信します。`make` はその TPM (`fwtpm_server`) をビルドしますが、起動はしません。別のターミナルで、wolfTPM ディレクトリから次のように起動します。 + +```sh +./src/fwtpm/fwtpm_server --clear +``` + +`--clear` オプションは、保存されている NV の状態を削除し、新しい状態の TPM で開始します。サーバーは起動したままにしておいてください。 + +!!! note + `caps` やその他のサンプルが接続できるようにするには、ソフトウェア TPM を事前に起動しておく必要があります。ハードウェア向けにビルドした場合は、TPM モジュールを接続し、この手順を省略してください。 + +最も単純なサンプルは、TPM の機能 (capabilities) を読み取り、永続ハンドルを検索します。 + +```sh +./examples/wrap/caps +TPM2 Get Capabilities +wolfSSL Entering wolfCrypt_Init +Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 +Found 2 persistent handles +``` + +ここに示した出力は一例です。接続した TPM の製造元とファームウェアの情報が表示されるため、モジュールごと、またソフトウェア TPM では異なる内容になります。 + +他のサンプルでは、さらに多くの機能を試せます。`./examples/native/native_test` は、ネイティブの `TPM2_*` API を直接呼び出します (スタートアップ、セルフテスト、乱数生成、ハッシュ、PCR 操作など)。PKCS #7 と TLS のサンプルでは、CSR を生成し、テストスクリプトで署名する必要があります。詳細はソースツリー内の `examples/README.md` を参照してください。 + +サンプルでパラメータ暗号化を使用するには、AES-CFB モードでは `-aes`、XOR モードでは `-xor` を指定します。パラメータ暗号化に対応しているのは、一部の TPM コマンドとレスポンスのみです。 + +!!! note + TLS サーバーとクライアントを同じマシン上で実行するには、`WOLFTPM_TIS_LOCK` (`--enable-tislock`) を指定してビルドし、並行アクセスからの保護を有効にしてください。 + +## 関連項目 + +- [wolfTPM のビルド](building.md) +- [ビルドオプション](build-options.md) +- [対応ハードウェア](supported-hardware.md) +- [システムインターフェース](system-interfaces.md) diff --git a/docs/ja/hal-io-callback.md b/docs/ja/hal-io-callback.md new file mode 100644 index 00000000..7f74cb33 --- /dev/null +++ b/docs/ja/hal-io-callback.md @@ -0,0 +1,145 @@ +# HAL IO コールバック + +TPM ハードウェアとの通信を処理するために、単一のハードウェア抽象化レイヤー (HAL) コールバックを登録する必要があります。このページでは、コールバック、wolfTPM に同梱されている実装例、およびそれらを制御するビルドオプションについて説明します。 + +初期セットアップを支援するため、複数のプラットフォーム向けのサンプルが用意されています。システムが提供する組み込みのハードウェアインターフェースを使用する場合は、HAL IO コールバックとして `NULL` を指定できます。 + +利用可能なシステム TPM インターフェースは次のとおりです。 + +* Linux `/dev/tpm0`: `WOLFTPM_LINUX_DEV` または `--enable-devtpm` で有効化します。 +* Windows TBS: `WOLFTPM_WINAPI` または `--enable-winapi` で有効化します。 +* ソフトウェア TPM シミュレータ: `WOLFTPM_SWTPM` または `--enable-swtpm` で有効化します。 + +HAL IO コールバックを使用する場合は、ライブラリの初期化時に次の関数で登録します。 + +* TPM2 ネイティブ API: `TPM2_Init` +* wolfTPM ラッパー: `wolfTPM2_Init` + +## HAL 実装例 + +| プラットフォーム | サンプルファイル | ビルドオプション | +| -------- | ------------ | ------------ | +| Atmel ASF | `tpm_io_atmel.c` | `WOLFSSL_ATMEL` | +| Barebox | `tpm_io_barebox.c` | `__BAREBOX__` | +| Infineon | `tpm_io_infineon.c` | `WOLFTPM_INFINEON_TRICORE` | +| Linux | `tpm_io_linux.c` | `__linux__` | +| Microchip | `tpm_io_microchip.c` | `WOLFTPM_MICROCHIP_HARMONY` | +| QNX | `tpm_io_qnx.c` | `__QNX__` | +| ST Cube HAL | `tpm_io_st.c` | `WOLFSSL_STM32_CUBEMX` | +| wolfHAL | `tpm_io_wolfhal.c` | `WOLFTPM_WOLFHAL` | +| Xilinx | `tpm_io_xilinx.c` | `__XILINX__` | + +## wolfHAL + +`WOLFTPM_WOLFHAL` または `--enable-wolfhal` で有効化します。wolfHAL のヘッダーがインクルードパス上にある必要があります。 + +この HAL はプラットフォーム選択チェーンの最後に配置されているため、他のプラットフォームマクロが定義されていない場合にのみ使用されます。たとえば、CubeMX のヘッダーが存在する STM32 ターゲット向けにビルドすると、代わりに `tpm_io_st.c` が選択されます。 + +### ボード定義 + +wolfTPM はボード定義を同梱していません。`tpm_io_wolfhal.c` は `"board.h"` をインクルードするため、アプリケーション側でインクルードパス上に用意する必要があります。wolfHAL のプロジェクトにはすでに存在するため、ほとんどの場合は、以下の TPM 固有のエントリを追加するだけで済みます。 + +SPI の場合: + +| マクロ | 型 | 説明 | +| ----- | ---- | ----------- | +| `BOARD_SPI_DEV` | `whal_Spi*` | TPM が接続されている SPI インスタンス | +| `BOARD_SPI_COM_CFG` | `whal_Spi_ComCfg*` | SPI セッションパラメータ | +| `BOARD_GPIO_DEV` | `whal_Gpio*` | チップセレクトを駆動する GPIO インスタンス | +| `BOARD_CS_PIN` | ピン番号 | チップセレクトピン (アクティブローで駆動) | + +I2C の場合 (`--enable-i2c` が設定する `WOLFTPM_ADV_IO` も必要): + +| マクロ | 型 | 説明 | +| ----- | ---- | ----------- | +| `BOARD_I2C_DEV` | `whal_I2c*` | TPM が接続されている I2C インスタンス | +| `BOARD_I2C_COM_CFG` | `whal_I2c_ComCfg*` | TPM のターゲットアドレスを含む I2C セッションパラメータ | + +TPM のターゲットアドレスは `BOARD_I2C_COM_CFG` の `addr` フィールドに設定します。ほとんどの TPM 2.0 I2C デバイスは `0x2e` を使用します。他の I2C HAL が使用する `TPM2_I2C_ADDR` マクロはここでは効果がないため、定義するとコンパイルエラーになります。 + +TPM 2.0 の I2C デバイスは、ウェイクアップに約 80 us かかり、準備ができるまで NAK を返すため、各転送は最大 `TPM_I2C_TRIES` 回 (デフォルトは 10) 再試行されます。この回数を変更するには `TPM_I2C_TRIES` を定義します。 + +エントリが不足している場合は、必要なマクロ名を示すメッセージとともにコンパイル時に報告されます。選択したバスで必要なマクロのみがチェックされます。 + +既存の wolfHAL `board.h` への追加例: + +```c +/* TPM on SPI1, chip select on PA15 */ +extern whal_Spi_ComCfg g_tpmSpiComCfg; +#define BOARD_SPI_COM_CFG (&g_tpmSpiComCfg) +#define BOARD_CS_PIN 15 +``` + +I2C の場合は、セッション設定に TPM アドレスを含めます。 + +```c +/* board.c */ +whal_I2c_ComCfg g_tpmI2cComCfg = { + .freq = 400000, /* Hz */ + .addr = 0x2e, /* TPM target address */ + .addrSz = 7, /* bits */ +}; + +/* board.h */ +extern whal_I2c_ComCfg g_tpmI2cComCfg; +#define BOARD_I2C_COM_CFG (&g_tpmI2cComCfg) +``` + +## HAL IO コールバック関数 + +HAL コールバック関数のプロトタイプ: + +```c +#ifdef WOLFTPM_ADV_IO +typedef int (*TPM2HalIoCb)(struct TPM2_CTX*, INT32 isRead, UINT32 addr, + BYTE* xferBuf, UINT16 xferSz, void* userCtx); +#else +typedef int (*TPM2HalIoCb)(struct TPM2_CTX*, const BYTE* txBuf, BYTE* rxBuf, + UINT16 xferSz, void* userCtx); +#endif +``` + +関数定義の例: + +```c +#ifdef WOLFTPM_ADV_IO +int TPM2_IoCb(TPM2_CTX*, int isRead, word32 addr, byte* buf, word16 size, + void* userCtx); +#else +int TPM2_IoCb(TPM2_CTX* ctx, const byte* txBuf, byte* rxBuf, + word16 xferSz, void* userCtx); +#endif +``` + +## 追加のビルドオプション + +* `WOLFTPM_CHECK_WAIT_STATE`: SPI トランザクション中のウェイトステートのチェックを有効にします。ほとんどの TPM 2.0 チップで必要で、コマンドによって通常 0 から 2 ウェイトサイクルのみが必要です。ウェイトステートが発生しないことを保証しているのは Infineon の TPM のみです。 +* `WOLFTPM_ADV_IO`: TIS レジスタと読み書きフラグを含む拡張 IO コールバックモードを有効にします。I2C には必須ですが、SPI でも使用できます。 +* `WOLFTPM_DEBUG_IO`: IO のログ出力を有効にします (サンプル HAL を使用している場合)。 +* `WOLFTPM_HAL_RESET`: サンプル HAL における TPM ハードウェアリセット (nRST) 制御を有効にするオプションです (`--enable-hal-reset`)。Linux では、`TPM2_IoCb_Reset(&dev->ctx, userCtx)` が GPIO キャラクタデバイス (raw GPIO v2 uAPI、libgpiod 不要) を通じて nRST (アクティブロー) にパルスを出力します。 + +## TPM リセット (nRST) HAL マクロ + +これらは `WOLFTPM_HAL_RESET` が設定されている場合に適用されます。 + +* `WOLFTPM_RESET_GPIOCHIP`: GPIO キャラクタデバイス。デフォルト: `/dev/gpiochip0`。 +* `WOLFTPM_RESET_LINE`: nRST に接続されている GPIO ライン。デフォルト: ST33 は `24` (GPIO24、Pi ピン 18)、Nuvoton は `4` (GPIO4)。`--enable-hal-reset=` でも設定できます。 +* `WOLFTPM_RESET_HOLD_US` と `WOLFTPM_RESET_SETTLE_US`: リセット保持時間とリセット後の安定待ち時間 (マイクロ秒単位)。デフォルト: `300000` と `1000000`。 + +## 追加のコンパイラマクロ + +* `TPM2_SPI_DEV_PATH`: Linux IO コールバックがオープンするデバイス文字列。デフォルト: `"/dev/spidev0."`。 +* `TPM2_SPI_DEV_CS`: 使用するチップセレクト番号の文字列。デフォルト: `"0"`。 + +これらは configure 時に設定できます。 + +```sh +./configure CPPFLAGS="-DTPM2_SPI_DEV_PATH=\"/dev/spidev0.\" -DTPM2_SPI_DEV_CS=\"0\"" +``` + +自動検出では、検索するデバイスパスとして `TPM2_SPI_DEV_PATH[0..4]` を使用します。 + +## 関連項目 + +* [サポート対象ハードウェア](supported-hardware.md) +* [TPM 2.0 概要](tpm2-overview.md) diff --git a/docs/ja/index.md b/docs/ja/index.md new file mode 100644 index 00000000..1a8db747 --- /dev/null +++ b/docs/ja/index.md @@ -0,0 +1,74 @@ +# wolfTPM + +組み込み用途向けに設計されたポータブルな TPM 2.0 プロジェクトです。このマニュアルでは、wolfTPM のビルド、ハードウェアに合わせた設定、ネイティブ API とラッパー API の使い方、ファームウェア TPM (fwTPM)、およびポスト量子暗号と SPDM 機能の実行方法を説明します。 + +## プロジェクトの特長 + +* 仕様に準拠したすべての TPM 2.0 API を提供します。 +* 鍵の生成とロード、RSA 暗号化/復号、ECC 署名/検証、ECDH、NV、ハッシュ/HMAC、AES、シーリング/アンシーリング、アテステーション、PCR Extend/Quote、セキュアなルートオブトラストを簡単に扱うためのラッパーを提供します。 +* TPM 2.0 に準拠したあらゆるモジュールに対応します。動作確認済みのモジュールは、Infineon SLB9670、SLB9672、SLB9673、STMicroelectronics ST33KTPM2XSPI、ST33KTPM2I、ST33TPHF2XSPI、ST33TPHF2XI2C、Microchip ATTPM20、Nations Technologies/NSING Z32H330、NS350、Nuvoton NPCT650、NPCT750、および SealSQ QVault TPM (シリコンとして初めてポスト量子の ML-DSA/ML-KEM に対応した TPM) です。 +* wolfTPM は、TPM Interface Specification (TIS) を使用して、SPI またはメモリマップド I/O 領域経由で通信します。 +* Linux では、wolfTPM は実行時にカーネルの TPM ドライバ (`/dev/tpmX`) と直接の SPI アクセスを自動検出します。`./configure && make` だけで、どちらのインターフェースでも動作します。 +* wolfTPM は、Linux の TPM カーネルインターフェース (`/dev/tpmX`) を使って、SPI、I2C、さらには LPC バス上の物理 TPM とも通信できます。 +* Raspberry Pi (Linux)、MMIO、CubeMX を使用する STM32、Atmel ASF、Xilinx、QNX、Infineon TriCore、wolfHAL、Barebox の各プラットフォームに対応します。 +* 設計上、さまざまなプラットフォームへ容易に移植できます。 + * 組み込み用途向けに設計されたネイティブ C コード。 + * ハードウェア SPI インターフェース用の単一の IO コールバック。 + * 外部依存なし。 + * コンパクトなコードサイズと最小限のメモリ使用量。 +* 次のサンプルコードを含みます。 + * ほとんどの TPM2 ネイティブ API + * すべての TPM2 ラッパー API + * PKCS 7 + * 証明書署名要求 (CSR) + * TLS クライアント + * TLS サーバー + * TPM の不揮発性メモリの使用 + * アテステーション (activate と make credential) + * TPM アルゴリズムと TLS のベンチマーク + * 鍵の生成 (プライマリ、RSA/ECC、対称鍵)、ロード、およびフラッシュ (NV メモリ) への保存 + * RSA 鍵または外部署名ポリシーによるデータのシーリングとアンシーリング + * 署名付き時刻の取得と時刻の設定 + * PCR の読み取り/リセット + * GPIO の設定、読み取り、書き込み + * Endorsement Key/証明書の取得と検証 +* AES-CFB または XOR を使用したパラメータ暗号化に対応します。 +* ソルト付きの非バウンド認証セッションに対応します。 +* HMAC セッションに対応します。 +* Endorsement 証明書 (EK Credential Profile) の読み取りに対応します。 +* 個別の TPM チップを持たない組み込みプラットフォーム向けに、ポータブルなファームウェア TPM 2.0 実装 (fwTPM。fTPM / swtpm とも呼ばれます) を含みます。[fwTPM の概要](fwtpm/overview.md)を参照してください。 +* TPM 2.0 Library Specification v1.85 による**ポスト量子暗号のサポート**: ML-DSA (FIPS 204) 署名と ML-KEM (FIPS 203) 鍵カプセル化に対応し、`--enable-v185` (v1.85 全体) または、より軽量な `--enable-pqc` (ML-DSA / ML-KEM のみ) で有効にします。操作ごとの絞り込みは `--enable-mldsa`/`--enable-mlkem` で行えます。ML-DSA と ML-KEM を備えた wolfCrypt に対して `--enable-fwtpm` をビルドすると自動検出されます。クライアントライブラリと fwTPM サーバーの両方が、v1.85 で追加された 8 つの PQC コマンドを実装しています。[ポスト量子暗号](post-quantum.md)を参照してください。 +* TCG SPDM-over-TPM バインディング上の **SPDM アテステーションのサポート** (DMTF DSP0274): TCG 証明書ハンドシェイクと DSP0274 の事前共有鍵 (PSK) ハンドシェイクに対応し、`--enable-spdm` で有効にします。fwTPM サーバーには SPDM 1.3 レスポンダが含まれているため、個別のシリコンなしでも CI でスタック全体をエンドツーエンドに検証できます。[SPDM アテステーション](spdm.md)を参照してください。 + +## 規格と機能 + +| 分野 | 状況 | 有効化フラグ | ページ | +| --- | --- | --- | --- | +| TPM 2.0 仕様 | TPM 2.0 コマンドセット用のネイティブ API と、一般的な操作用のラッパー | 常にビルドされます | [API リファレンス](api-reference.md) | +| TCG TPM 2.0 Library Specification リビジョン 1.85 | ポスト量子コマンドをクライアントライブラリと fwTPM サーバーに実装 | `--enable-v185` (v1.85 全体) | [ビルドオプション](build-options.md) | +| ポスト量子: ML-DSA (FIPS 204) と ML-KEM (FIPS 203) | クライアントライブラリと fwTPM サーバー。SealSQ QVault はシリコンで対応 | `--enable-pqc` (ML-DSA / ML-KEM のみ)、`--enable-mldsa`、`--enable-mlkem` | [ポスト量子暗号](post-quantum.md) | +| SPDM アテステーション (TCG 証明書ハンドシェイクと DSP0274 PSK ハンドシェイク) | クライアントライブラリ。fwTPM には SPDM 1.3 レスポンダも含まれます | `--enable-spdm` | [SPDM アテステーション](spdm.md) | +| パラメータ暗号化 (AES-CFB または XOR) | ソルト付き非バウンドセッションおよび HMAC セッションとあわせて対応 | 実行時にセッションごとに設定 | [API リファレンス](api-reference.md) | +| EK Credential Profile | Endorsement 証明書の読み取り (`examples/endorsement/get_ek_certs`) | 常にビルドされます | [はじめに](getting-started.md) | +| デバイス ID (IAK / IDevID) | ST33KTPM で検証済み。既定の鍵は、NV 内の SHA2-384 を用いた ECDSA SECP384R1 | `WOLFTPM_MFG_IDENTITY` | [対応ハードウェア](supported-hardware.md) | +| ファームウェア TPM (fwTPM / fTPM / swtpm) | wolfCrypt 上に構築されたポータブルな TPM 2.0 サーバー | `--enable-fwtpm` | [fwTPM の概要](fwtpm/overview.md) | + +## ドキュメントマップ + +* [はじめに](getting-started.md): インストール後の最初の手順。 +* [ビルド](building.md): ソースからの wolfTPM のビルド。 +* [ビルドオプション](build-options.md): configure フラグと、それらが設定する define。 +* [対応ハードウェア](supported-hardware.md): 動作確認済みの TPM モジュールとプラットフォーム。 +* [TPM 2.0 の概要](tpm2-overview.md): 階層、PCR、デバイス識別。 +* [プロジェクト構成](project-structure.md): ソースツリーの構成。 +* [ポスト量子暗号](post-quantum.md): ML-DSA と ML-KEM のサポート。 +* [SPDM アテステーション](spdm.md): SPDM ハンドシェイクとレスポンダ。 +* [fwTPM の概要](fwtpm/overview.md): ファームウェア TPM サーバー。 +* [API リファレンス](api-reference.md): ネイティブ API とラッパー API。 + +## 関連項目 + +* [はじめに](getting-started.md) +* [ビルドオプション](build-options.md) +* [対応ハードウェア](supported-hardware.md) +* [fwTPM の概要](fwtpm/overview.md) diff --git a/docs/ja/key-management.md b/docs/ja/key-management.md new file mode 100644 index 00000000..fff70323 --- /dev/null +++ b/docs/ja/key-management.md @@ -0,0 +1,146 @@ +# 鍵管理 + +wolfTPM には、TPM 鍵の作成、鍵ブロブとしてのディスクへの保存、外部鍵のインポート、一時的な TPM ハンドルへの再ロードを行うサンプルプログラムが含まれています。このページでは、鍵生成サンプルの流れを説明し、`examples/keygen/` のプログラムと `examples/wrap/` のラッパーユーティリティを一覧にします。 + +## 鍵生成の概要 + +`keygen` サンプルは、ストレージ鍵 (SRK) の配下に TPM 鍵を作成し、鍵ブロブをディスクに書き出します。`keyload` サンプルはそのブロブを読み込み、一時的な TPM ハンドルにロードします。 + +```sh +$ ./examples/keygen/keygen keyblob.bin -rsa +TPM2.0 Key generation example +Loading SRK: Storage 0x81000200 (282 bytes) +Creating new RSA key... +Created new key (pub 280, priv 222 bytes) +Wrote 840 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 840 bytes from keyblob.bin +Loaded key to 0x80000001 + + +$ ./examples/keygen/keygen keyblob.bin -ecc +TPM2.0 Key generation example +Loading SRK: Storage 0x81000200 (282 bytes) +Creating new ECC key... +Created new key (pub 88, priv 126 bytes) +Wrote 744 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 744 bytes from keyblob.bin +Loaded key to 0x80000001 +``` + +対称鍵と keyed hash 鍵も同じ流れで扱えます。 + +```sh +$ ./examples/keygen/keygen -sym=aescfb128 +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: SYMCIPHER + aescfb mode, 128 keybits + Template: Default + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Symmetric template +Creating new SYMCIPHER key... +Created new key (pub 50, priv 142 bytes) +Wrote 198 bytes to keyblob.bin + +$ ./examples/keygen/keyload +TPM2.0 Key load example + Key Blob: keyblob.bin + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 198 bytes from keyblob.bin +Reading the private part of the key +Loaded key to 0x80000001 + +$ ./examples/keygen/keygen -keyedhash +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: KEYEDHASH + Template: Default + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Keyed Hash template +Creating new KEYEDHASH key... +TPM2_Create key: pub 48, priv 158 +Public Area (size 48): + Type: KEYEDHASH (0x8), name: SHA256 (0xB), objAttr: 0x40460, authPolicy sz: 0 + Keyed Hash: scheme: HMAC (0x5), scheme hash: SHA256 (0xB), unique size 32 +TPM2_Load Key Handle 0x80000001 +New key created and loaded (pub 48, priv 158 bytes) +Wrote 212 bytes to keyblob.bin +``` + +ファイル名を指定しない場合は、デフォルトの `keyblob.bin` が使用されます。このため、`keygen` と `keyload` は追加のパラメータなしで実行でき、手早いデモに適しています。`keygen` が対応するアルゴリズムとオプションの一覧は、いずれかの `--help` スイッチで確認できます。 + +`keyimport` サンプルは、秘密鍵を TPM 鍵ブロブとしてラップし、ディスクに保存します。その後 `keyload` でロードできます。 + +```sh +$ ./examples/keygen/keyimport keyblob.bin -rsa +TPM2.0 Key import example +Loading SRK: Storage 0x81000200 (282 bytes) +Imported key (pub 278, priv 222 bytes) +Wrote 840 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 840 bytes from keyblob.bin +Loaded key to 0x80000001 + + +$ ./examples/keygen/keyimport keyblob.bin -ecc +TPM2.0 Key Import example +Loading SRK: Storage 0x81000200 (282 bytes) +Imported key (pub 86, priv 126 bytes) +Wrote 744 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 744 bytes from keyblob.bin +Loaded key to 0x80000001 +``` + +`keyload` が受け取る引数は、保存された鍵のファイル名だけです。RSA か ECC かといったスキームは鍵ブロブの中に保存されているため、鍵の種類を指定する必要はありません。 + +鍵の作成時に認可値を保護するには、`keygen` に `-aes` または `-xor` を追加します。[サンプルの概要](examples-overview.md)を参照してください。 + +## プログラム (examples/keygen/) + +| プログラム | 説明 | +| --- | --- | +| `create_primary.c` | プライマリ鍵を作成して保存します。IAK や IDevID など、エンドースメント階層の鍵も扱います。 | +| `keygen.c` | SRK の配下に新しい RSA、ECC、対称鍵、または keyed hash 鍵を作成し、鍵ブロブをディスクに書き出します。 | +| `keyload.c` | ディスクから鍵ブロブを読み込み、一時的な TPM ハンドルにロードします。 | +| `keyimport.c` | 既存の秘密鍵を TPM 鍵ブロブとしてインポートし、ディスクに書き出します。 | +| `external_import.c` | 外部の秘密鍵(サンプルに組み込み済み)を SRK の配下にインポートします。`-rsa` または `-ecc` で SRK の種類を指定し、`-load` で保存済みの `keyblob.bin` を第 3 階層の鍵にロードします。 | +| `ecdh.c` | TPM 鍵を使った ECDH 鍵共有を行い、共有秘密を生成します。 | + +## ラッパーユーティリティ (examples/wrap/) + +| プログラム | 説明 | +| --- | --- | +| `wrap_test.c` | `wolfTPM2_*` ラッパー API を実行して動作を確認します。 | +| `caps.c` | TPM のケイパビリティを読み取って表示します。 | +| `getrandom.c` | TPM の RNG から乱数バイトを取得します。 | +| `hash.c` | TPM のハッシュシーケンスでメッセージをハッシュします。 | +| `hmac.c` | 永続的な TPM HMAC 鍵で HMAC を計算します。鍵が見つからない場合は作成します。 | +| `encrypt_decrypt.c` | TPM 鍵による対称鍵の暗号化と復号の往復テストです。 | + +## NV への鍵の保存 + +鍵やシークレットは TPM の NV メモリに保存することもでき、必要に応じて認可値を暗号化できます。[シーリングと NVRAM](sealing-and-nvram.md)を参照してください。 + +## 関連項目 + +* [サンプルの概要](examples-overview.md) +* [シーリングと NVRAM](sealing-and-nvram.md) +* [アテステーション](attestation.md) diff --git a/docs/ja/management-and-gpio.md b/docs/ja/management-and-gpio.md new file mode 100644 index 00000000..f0bd084f --- /dev/null +++ b/docs/ja/management-and-gpio.md @@ -0,0 +1,137 @@ +# 管理ユーティリティと GPIO + +このページでは、`examples/management/` にある小規模な TPM 管理ユーティリティと、`examples/gpio/` にある GPIO 制御のサンプルを説明します。 + +## 管理ユーティリティ + +| プログラム | 目的 | +|---------|---------| +| `da_check.c` | ディクショナリアタック (DA) ロックアウトのチェック。DA で保護されたキーと noDA キーを使用し、不正な認可を繰り返してロックアウト状態に入り、ロックアウトリセットで復旧します。 | +| `flush.c` | トランジェントハンドルと永続ハンドルをフラッシュします。ハンドル (例: `0x80000000`) を指定して実行するとそのオブジェクトを解放し、パラメータなしで実行すると一般的なトランジェントオブジェクト (トランジェントキー、ポリシーセッション、HMAC セッション) をフラッシュします。 | +| `tpmclear.c` | `TPM2_Clear` を実行して階層をクリアします。 | + +```sh +./examples/management/da_check +./examples/management/flush [handle] +./examples/management/tpmclear +``` + +!!! warning + `tpmclear` は TPM をクリアします。クリアされた階層配下のキーとデータは失われます。 + +## GPIO 制御 + +一部の TPM 2.0 モジュールには、開発者が利用できる追加の I/O 機能と GPIO があります。この追加 GPIO を使って、セキュリティイベントやシステム状態を他のサブシステムに通知できます。 + +!!! note + GPIO 制御のサンプルがサポートするのは、ST33 および NPCT75x TPM 2.0 モジュールのみです。 + +`examples/gpio/` には 3 つのプログラムがあります。 + +| プログラム | 目的 | +|---------|---------| +| `gpio_config.c` | GPIO を設定します。 | +| `gpio_set.c` | 設定済みの GPIO を High または Low に設定します。 | +| `gpio_read.c` | 設定済みの GPIO のレベルを読み取ります。 | + +すべてのサンプルにヘルプオプション `-h` があります。`gpio_config -h` を実行すると GPIO のモードを確認できます。パラメータを指定しない場合はデモ用の使い方で実行されます。GPIO は物理世界と相互作用するため、オプションは慎重に選択してください。 + +### GPIO の設定 (ST33) + +ST33 は 6 つのモードをサポートします。`gpio_config` のヘルプ出力は次のとおりです。 + +```sh +$ ./examples/gpio/gpio_config -h +Expected usage: +./examples/gpio/gpio_config [num] [mode] +* num is a GPIO number between 0-3 (default 0) +* mode is a number selecting the GPIO mode between 0-6 (default 3): + 0. standard - reset to the GPIO's default mode + 1. floating - input in floating configuration. + 2. pullup - input with pull up enabled + 3. pulldown - input with pull down enabled + 4. opendrain - output in open drain configuration + 5. pushpull - output in push pull configuration + 6. unconfigure - delete the NV index for the selected GPIO +Example usage, without parameters, configures GPIO0 as input with a pull down. +``` + +GPIO を出力として設定します。 + +```sh +$ ./examples/gpio/gpio_config 0 5 +GPIO num is: 0 +GPIO mode is: 5 +Example how to use extra GPIO on a TPM 2.0 modules +Trying to configure GPIO0... +TPM2_GPIO_Config success +NV Index for GPIO access created +``` + +GPIO をプルダウン付きの入力として設定します (モード 3)。 + +```sh +$ ./examples/gpio/gpio_config 0 3 +GPIO num is: 0 +GPIO mode is: 3 +Demo how to use extra GPIO on a TPM 2.0 modules +Trying to configure GPIO0... +TPM2_GPIO_Config success +NV Index for GPIO access created +``` + +### GPIO の設定 (NPCT75xx) + +NPCT75x は 3 つの出力モードをサポートし、入力モードはありません。`gpio_config` のヘルプ出力は次のとおりです。 + +```sh +$ ./examples/gpio/gpio_config -h +Expected usage: +./examples/gpio/gpio_config [num] [mode] +* num is a GPIO number between 3 and 4 (default 3) +* mode is either push-pull, open-drain or open-drain with pull-up + 1. pushpull - output in push pull configuration + 2. opendrain - output in open drain configuration + 3. pullup - output in open drain with pull-up enabled + 4. unconfig - delete NV index for GPIO access +Example usage, without parameters, configures GPIO3 as push-pull output. +``` + +NPCT75x の GPIO 番号は GPIO3 から始まりますが、ST33 は GPIO0 から始まります。 + +```sh +$ ./examples/gpio/gpio_config 4 1 +Example for GPIO configuration of a NPTC7xx TPM 2.0 module +GPIO number: 4 +GPIO mode: 1 +Successfully read the current configuration +Successfully wrote new configuration +NV Index for GPIO access created +``` + +### GPIO の使用方法 + +GPIO の設定を切り替える手順は次のとおりです。 + +- ST33 の場合、`gpio_config` は既存の NV インデックスを削除するため、新しい GPIO 設定を選択できます。 +- NPCT75xx の場合、`gpio_config` は作成済みの NV インデックスを削除せずに任意の GPIO を再設定できます。 + +設定後、GPIO を設定および読み取ります。 + +```sh +$ ./examples/gpio/gpio_set 0 -high +GPIO0 set to high level + +$ ./examples/gpio/gpio_set 0 -low +GPIO0 set to low level + +$ ./examples/gpio/gpio_read 0 +GPIO0 is Low +``` + +## 関連項目 + +- [Sealing and NVRAM](sealing-and-nvram.md) +- [TLS and certificates](tls-and-certificates.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/ja/post-quantum.md b/docs/ja/post-quantum.md new file mode 100644 index 00000000..c6ec9d1f --- /dev/null +++ b/docs/ja/post-quantum.md @@ -0,0 +1,286 @@ +# ポスト量子暗号 + +wolfTPM は、TCG TPM 2.0 Library Specification v1.85 で追加されたポスト量子暗号アルゴリズムをサポートしています。クライアントライブラリは、v1.85 の新しいコマンドをマーシャリングして TPM に送信します。対象がツリー内のファームウェア TPM の場合、そのサーバーが wolfCrypt の FIPS 203 (ML-KEM) モジュールおよび FIPS 204 (ML-DSA) モジュールでアルゴリズムを実行します。対象が SEALSQ QVault などのハードウェア TPM の場合は、デバイスがチップ上で実行します。このページでは、サポートされるアルゴリズム、ビルド方法、および `examples/pqc` に含まれる PQC サンプルについて説明します。 + +## 概要 + +サポートされるアルゴリズム: + +| アルゴリズム | 規格 | パラメータセット | +|---|---|---| +| ML-DSA (署名) | FIPS 204 | ML-DSA-44 / 65 / 87 | +| HashML-DSA (プリハッシュ署名) | FIPS 204 | 呼び出し側ハッシュ付きの ML-DSA-44 / 65 / 87 | +| ML-KEM (鍵カプセル化) | FIPS 203 | ML-KEM-512 / 768 / 1024 | + +wolfTPM は SEALSQ QVault TPM をサポートしています。SEALSQ は、これを v1.85 の PQC アルゴリズムをシリコンに搭載した最初の TPM 2.0 デバイスと位置付けています。SEALSQ は QVault TPM-185 のエンジニアリングサンプルを提供可能としているため、現在の量産および認証の状況については SEALSQ に確認してください。同じ PQC API は、ツリー内の fwTPM サーバーに対しても動作するため、CI やハードウェアが存在しない場合に便利です。QVault TPM シリコンにおける ML-DSA と ML-KEM の実測性能については、このページの末尾にあるベンチマークのセクションを参照してください。 + +## ビルド + +### wolfSSL + +wolfSSL は wolfCrypt で ML-DSA と ML-KEM を提供します。 + +```sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \ + --enable-mldsa --enable-mlkem \ + --enable-harden CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +``` + +後述の PQC TLS 1.3 デモでは、`--enable-tls-mlkem-standalone` も追加してください。スタンドアロンの `ML_KEM_*` TLS グループにはこのスタンドアロンオプションが必要です。これがない場合、wolfSSL はハイブリッドグループのみを提供し、`wolfSSL_UseKeyShare` はクライアントのデフォルトを拒否します。`gen_pqc_certs` ツールには証明書生成が必要ですが、これは `--enable-wolftpm` がすでに有効にしています。また `--enable-wolftpm` は、TLS サーバーが使用する crypto コールバックと秘密鍵 ID のサポートも提供します。`--enable-pkcallbacks` は別の wolfSSL オプションであるため、そのまま指定してください。このデモには wolfSSL 5.9.4-stable 以降が必要です。 + +### fwTPM (ソフトウェア TPM) + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-pqc +make +``` + +`--enable-swtpm` は、以下のサンプルが接続する `127.0.0.1:2321` の mssim ソケットトランスポートを使って `fwtpm_server` をビルドします。Linux の x86_64 と AArch64 ではソケットトランスポートがすでにデフォルトであるため、このフラグを指定することで、どのプラットフォームでもソケットサーバーを確実に利用できます。fwTPM サーバーは v1.85 のコマンドセット全体を使用するため、configure は `--enable-pqc` を `--enable-v185` に引き上げます。両方の PQC フラグを省略しても、wolfCrypt に ML-DSA と ML-KEM が含まれている場合、configure は v1.85 を自動的に有効にします。明示的に無効にするには `--disable-pqc` を指定してください。 + +### ハードウェア TPM: SEALSQ QVault + +SEALSQ QVault は、現在 v1.85 PQC でサポートされているハードウェア TPM です。 + +```sh +./configure --enable-sealsq --enable-pqc +make +``` + +Linux では、カーネルの TPM ドライバーを使用するために `--enable-devtpm` を追加します。プロセス間でトランジェントハンドルを受け渡すサンプルでは、`CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm0"'` も追加してください。デフォルトの `/dev/tpmrm0` は、プロセスがデバイスを閉じるとそれらのハンドルを仮想化して破棄します。シングルクォートで囲んだ `CFLAGS` の値の内側にある二重引用符は、そのまま記述してください。 + +`--enable-pqc` は、ハードウェア向けに軽量な ML-DSA と ML-KEM のサブセット (`WOLFTPM_PQC`) をビルドします。v1.85 のコマンドセット全体を使用するには `--enable-v185` (`WOLFTPM_V185`) を使用してください。 + +SHA-1 を使用しない TPM サンプルの例: + +```sh +./examples/pqc/pqc_ctrl --caps --algs +./examples/pqc/pqc_ctrl --mldsa=65 --mlkem=768 +./examples/wrap/hash "wolfTPM" -sha256 +``` + +### PQC フットプリントの削減 + +呼び出す操作だけをコンパイルする (使用しないコードパスが除外され、バイナリが小さくなる) には、wolfSSL のフラグに合わせて指定します。 + +```sh +# ML-DSA verify-only + ML-KEM encapsulate-only (no sign, no decapsulate) +./configure --enable-pqc --enable-mldsa=verify-only --enable-mlkem=enc +``` + +| フラグ | 値 | 除外されるもの | +|------|--------|-------| +| `--enable-mldsa` | `all` (デフォルト) / `sign-only` / `verify-only` / `no` | 選択されていない ML-DSA 操作 | +| `--enable-mlkem` | `all` (デフォルト) / `enc` / `dec` / `no` | 選択されていない ML-KEM 操作 | +| `--disable-hash-mldsa` | なし | プリハッシュ ML-DSA 鍵のサポート | + +これらは `WOLFTPM_NO_MLDSA_SIGN`、`WOLFTPM_NO_MLKEM_DECAP` などの define に対応しており、組み込み開発者は autotools を使わずに `CFLAGS` で直接渡すこともできます。既存の `--enable-v185` ビルドには影響しません (すべての操作がデフォルトで有効です)。両方のアルゴリズムを無効にする (`--enable-mldsa=no --enable-mlkem=no`) と configure エラーになります。ポスト量子暗号のサポートを一切含めずにビルドするには `--disable-pqc` を使用してください。削減はコードパスを除外してバイナリを小さくしますが、公開されている TPM2B バッファの最大サイズは小さくなりません。これらは最大の v1.85 パラメータセットに合わせたサイズのままです。 + +同じフラグは fwTPM サーバーの削減にも使えます。`--enable-fwtpm --enable-mldsa=verify-only` は、ML-DSA の署名コマンドのハンドラー、ディスパッチエントリー、暗号処理をコンパイルから除外します。ML-KEM は別に制御され、デフォルトの `all` のままです。したがって、PQC の対象が ML-DSA の verify のみであるサーバーをビルドするには、`--enable-mlkem=no` も指定してください。fwTPM は常に v1.85 仕様の全体をビルドするため、これらの削減は `WOLFTPM_V185` の上に適用されます。 + +!!! note + 削減を行っても、サンプルがアロケーションフリーになるわけではありません。サンプルは引き続き `XMALLOC` で署名バッファと暗号文バッファを確保します。fwTPM には別に `WOLFTPM2_NO_HEAP` オプションがあり、すべてのバッファをスタックに移しますが、その代わりスタック使用量が大幅に増えます。詳細は [fwTPM のビルド](fwtpm/building.md) を参照してください。 + +## サンプルの実行 + +```sh +make check +``` + +上記の fwTPM ビルドでは、`make check` は PQC のカバレッジを含むソフトウェア TPM のテストスイートを実行します。 + +- `tests/fwtpm_unit.test`: 30 件以上のインプロセス PQC ハンドラーテスト +- `tests/fwtpm_check.sh`: サーバーを起動したうえで、`tests/unit.test` (mssim ソケット経由の PQC ラッパーテスト。ML-DSA Sign/Verify Sequence、ML-KEM Encap/Decap、EncryptSecret ML-KEM など) と `examples/run_examples.sh` を実行します。ソケットトランスポートが有効で tpm2-tools がインストールされている場合は、tpm2-tools スイートも実行します +- `tests/fwtpm_da_retry.sh`: ディクショナリアタックのリトライ確認 (`-DFWTPM_DA_USED_RETRY` を指定したビルドが必要) + +`make check` は `tests/pqc_mssim_e2e.sh` を実行しません。PQC に絞った高速なエンドツーエンドの確認には、このスクリプトを直接実行してください。 + +```sh +./tests/pqc_mssim_e2e.sh +``` + +fwTPM ビルドでは、`fwtpm_server` を別のターミナルで一度だけ起動し、以下の個別サンプル (TLS デモを含む) を実行している間は起動したままにしてください。サーバーは `127.0.0.1:2321` で待ち受けます。SEALSQ ビルドでは、設定済みのハードウェアトランスポートを使用します。以下の `--clear` フラグは、起動前に fwTPM の NV 状態ファイルを削除し、サンプルをクリーンな TPM で実行できるようにします。使い捨てのテスト用インスタンスでのみ使用し、既存の fwTPM の永続状態を保持したい場合は省略してください。 + +```sh +# separate terminal; leave this running +./src/fwtpm/fwtpm_server --clear +``` + +fwTPM サーバーの PQC 内部 (8 つの v1.85 コマンド、プライマリ鍵の導出、バッファ定数、仕様解釈上の判断) については、[docs/FWTPM.md](fwtpm/overview.md) を参照してください。 + +## サンプル + +### pqc_ctrl + +`pqc_ctrl` は、PQC TPM (SEALSQ QVault TPM または fwTPM) を操作して検証するための単一の CLI です。各コマンドは TPM に対して操作を実行します。すべての鍵操作は最初にトランジェントオブジェクトテーブルをフラッシュするため、オブジェクトメモリが小さい TPM (SEALSQ QVault TPM など) でも、コマンドを連続して実行した際に `TPM_RC_OBJECT_MEMORY` が発生しません。 + +```sh +./examples/pqc/pqc_ctrl # --all (default) +./examples/pqc/pqc_ctrl --caps --algs # identify + list supported algorithms +./examples/pqc/pqc_ctrl --mldsa=87 # ML-DSA-87 sign/verify +./examples/pqc/pqc_ctrl --mlkem=1024 # ML-KEM-1024 encap/decap +./examples/pqc/pqc_ctrl --selftest --getrandom=32 --pcrread=0 +``` + +| コマンド | 説明 | +|---|---| +| `--caps` | 製造元、ベンダー文字列、ファームウェア、FIPS モード | +| `--algs` | TPM がサポート対象として報告するアルゴリズムの一覧 | +| `--selftest` | `TPM2_SelfTest` | +| `--getrandom[=N]` | N バイトの乱数 (デフォルトは 16) | +| `--pcrread[=idx]` | PCR の読み取り (SHA-256 バンク、なければ SHA-384 にフォールバック) | +| `--pcrextend=idx` | テスト用ダイジェストで PCR を拡張 (インデックスの明示が必須) | +| `--flush` | 操作の合間に、ロード済みのすべてのトランジェントオブジェクトをフラッシュ | +| `--clear` | `TPM2_Clear`。新しい Storage プライマリシードをインストールし、Storage オブジェクトと Endorsement オブジェクトおよび非プラットフォームの NV を削除し、オーナー、エンドースメント、ロックアウトの auth をリセットします | +| `--mldsa[=44/65/87]` | Pure ML-DSA の署名/検証 (デフォルトは 65) | +| `--hash-mldsa[=44/65/87]` | HashML-DSA (SHA-256 プリハッシュ) の署名/検証 | +| `--mlkem[=512/768/1024]` | ML-KEM のカプセル化/デカプセル化 | +| `--all` | caps + algs + selftest + getrandom + pcrread + すべての PQC セット | + +コマンドは左から右へ順に実行されるため、連結できます。機能する `pqc_ctrl` は、削減されていない PQC 構成からのみビルドされます。つまり、ラッパー、ML-DSA の両方の操作、ML-KEM の両方の操作、および HashML-DSA がすべて必要です。`--enable-v185` (または `--enable-pqc`) でビルドしてください。`--enable-mldsa=verify-only` のように削減したビルドでは、CLI がコンパイルから除外されます。SEALSQ のデバイスを対象にするには `--enable-sealsq` を、fwTPM を対象にするには `--enable-fwtpm --enable-swtpm` を指定してください。 + +`pqc_ctrl.sh` は、デバイスがすべてのパラメータセットをサポートしている場合に、コマンドセット全体を合否判定付きのスイートとして実行します (`examples/spdm/spdm_test.sh` に倣っています)。永続的な状態変更 (PCR 16 の拡張と `TPM2_Clear`) は `PQC_CTRL_CLEAR=1` によるオプトインです。デフォルトの実行でも、ロード済みのトランジェントオブジェクトはフラッシュされ、すべての鍵操作でトランジェントオブジェクトテーブルがフラッシュされるため、トランジェント TPM ハンドルを有効なまま保つ必要があるワークロードと並行して実行しないでください。 + +```sh +./examples/pqc/pqc_ctrl.sh +PQC_CTRL_CLEAR=1 ./examples/pqc/pqc_ctrl.sh # also extend PCR 16 and run TPM2_Clear +``` + +!!! warning + `PQC_CTRL_CLEAR=1` は 1 つではなく 2 つの処理を行います。まず PCR 16 を拡張します。これは PCR をリセットしない限り元に戻せません。次に `TPM2_Clear` を実行します。`TPM2_Clear` は新しい Storage プライマリシードをインストールするため、古いシードで保護されていたすべての鍵ブロブと封印済みオブジェクトは以後恒久的に使用できなくなり、ファイルのバックアップがあっても復元できません。使い捨てのテスト用 TPM でのみ使用してください。 + +### pqc_mssim_e2e + +mssim ソケット経由のエンドツーエンドのクライアントテストです。次の 4 つのチェックを順に実行します。 + +1. ML-KEM-768 の `CreatePrimary`、`Encapsulate`、`Decapsulate`。暗号文が 1088 バイトであること、および 2 つの共有秘密がバイト単位で一致することを検証します。 +2. HashML-DSA-65 (SHA-256) の `CreatePrimary`、`SignDigest`、`VerifyDigestSignature`。署名が 3309 バイトであること、および検証チケットのタグが `TPM_ST_DIGEST_VERIFIED` であることを検証します。 +3. ML-KEM の `MakeCredential` と `ActivateCredential` のラウンドトリップ。 +4. ML-DSA の `Quote`。 + +```sh +./examples/pqc/pqc_mssim_e2e +``` + +### mlkem_encap + +ML-KEM カプセル化のラウンドトリップです。ML-KEM のプライマリ鍵を作成して `Encapsulate` を実行し、生成された暗号文を `Decapsulate` して、共有秘密が一致することを確認します。 + +```sh +./examples/pqc/mlkem_encap # default: ML-KEM-768 +./examples/pqc/mlkem_encap -mlkem=512 +./examples/pqc/mlkem_encap -mlkem=1024 +``` + +### mldsa_sign + +Pure ML-DSA の署名と検証のラウンドトリップです。ML-DSA のプライマリ鍵を作成し、`SignSequenceStart` と `SignSequenceComplete` で固定メッセージに署名します。Pure ML-DSA のシーケンスはストリーミング可能であり、メッセージを `SequenceUpdate` 経由で渡すこともできますが、このサンプルでは署名時にメッセージ全体を Complete のバッファで渡します。続いて `VerifySequenceStart`、`VerifySequenceUpdate`、`VerifySequenceComplete` で検証します。返された検証チケットのタグが `TPM_ST_MESSAGE_VERIFIED` であることを検証します。 + +```sh +./examples/pqc/mldsa_sign # default: ML-DSA-65 +./examples/pqc/mldsa_sign -mldsa=44 +./examples/pqc/mldsa_sign -mldsa=87 +``` + +### keygen と keyload による PQC 鍵 + +`examples/keygen/keygen` は、`-rsa`、`-ecc`、`-sym`、`-keyedhash` に加えて、v1.85 の PQC オプションを受け付けます。 + +```sh +./examples/keygen/keygen keyblob.bin -mldsa=65 # Pure ML-DSA +./examples/keygen/keygen keyblob.bin -hash_mldsa=65 # SHA-256 pre-hash +./examples/keygen/keygen keyblob.bin -mlkem=768 # ML-KEM +``` + +パラメータセット: + +- `-mldsa=44|65|87` (デフォルトは 65) +- `-hash_mldsa=44|65|87` (デフォルトは 65、SHA-256 プリハッシュ) +- `-mlkem=512|768|1024` (デフォルトは 768) + +生成されたブロブが `TPM2_Create` と `TPM2_Load` を経由してラウンドトリップできることは、読み込み直すことで確認できます。 + +```sh +./examples/keygen/keyload keyblob.bin +``` + +読み込みに成功すると、トランジェント鍵ハンドルが表示されます。完全なマトリクス (3 種類のバリアント × 3 つのパラメータセットで 9 通りの鍵構成。それぞれを keygen と keyload で実行) は、`config.h` で v1.85 が検出された場合に `examples/run_examples.sh` によって実行されます。この汎用スイートは、それぞれ固有の TPM 要件を持つ非 PQC の操作もカバーします。 + +### パラメータ暗号化のための PQC 鍵 + +ポスト量子暗号のプライマリ鍵は、TPM 2.0 のパラメータ暗号化セッションの鍵として使用できます。ML-KEM (復号可能) はセッションソルト鍵として、ML-DSA (署名のみ) はセッションバインド鍵として使用されます。このセッションは、RSA や ECC のソルト付きセッションと同様に、コマンドの最初のサイズ付きパラメータを保護します。サンプルが必要とする RSA や ECC のストレージ鍵 (たとえば作成される子鍵の親) は変更されません。 + +!!! note + パラメータ暗号化の機密性は、バインドセッションがバインドエンティティの authValue から導出するセッション鍵によって得られます (TPM 2.0 Library Part 1、Salted Session)。署名専用の ML-DSA 鍵はソルトを交換できず、サンプルのバインド authValue は公開された定数であるため、ML-DSA によるバインドだけではセッションのバインドは得られても、バス観測者に対する機密性は得られません。宣伝されている暗号化を実質的なものにするため、ヘルパーはトランジェント SRK も作成し、ML-DSA セッションの非対称ソルトとして使用します。機密性は暗号化されたソルトから得られ、ML-DSA 鍵はバインドを提供します。バインドセッションのみで機密性を確保する実運用の構成では、authValue が秘密であり、平文で送信されていないバインドエンティティを使用する必要があります。 + +`wrap_test`、`pcr/quote`、`nvram/store`、`nvram/counter` は、`-mlkem[=512|768|1024]` と `-mldsa[=44|65|87]` を受け付けます。`keygen` では、`-mlkem` と `-mldsa` オプションがすでに子鍵のアルゴリズムを選択するため、`-paramkey=mlkem[=...]` と `-paramkey=mldsa[=...]` を使用します。 + +```sh +./examples/wrap/wrap_test -aes -mlkem=768 +./examples/pcr/quote 16 quote.blob -ecc -xor -mldsa=65 +./examples/nvram/counter -aes -mldsa=65 +./examples/keygen/keygen keyblob.bin -ecc -aes -paramkey=mlkem=768 +``` + +ML-KEM は制限付き復号 (ソルト) 鍵であり、対称アルゴリズムの定義が必要です。サンプルのヘルパーは AES-128-CFB を設定します。これは、対称アルゴリズムを持たない制限付き鍵を TPM が `TPM_RC_SYMMETRIC` で拒否するためです。 + +### ML-DSA プライマリ鍵を用いた create_primary + +`examples/keygen/create_primary` は ML-DSA プライマリ鍵を作成できます。 + +```sh +./examples/keygen/create_primary -mldsa # default ML-DSA-65 +./examples/keygen/create_primary -mldsa=87 -oh +``` + +### ポスト量子 TLS 1.3 (ML-KEM と TPM ML-DSA) + +これは、サーバーの ML-DSA アイデンティティ鍵が TPM 内にある、完全な TLS 1.3 ハンドシェイクです。サーバーは wolfTPM の crypto コールバックを介して、TPM 内で CertificateVerify に署名します。QVault などのハードウェア TPM では、この署名はチップ上で行われます。以下のコマンドはソフトウェアの fwTPM を使用します。クライアントは ML-KEM 鍵交換を行い、ソフトウェア CA に対してサーバーを検証します。 + +これには、デバイス鍵 (秘密鍵が TPM 内にある) に対して `wc_MlDsaKey_SignCtx` を crypto コールバックにルーティングする wolfSSL が必要です。この変更は wolfSSL 5.9.4-stable 以降に含まれています。開発スナップショットを使用する場合は、wolfSSL のコミット `6b0c832284286dbaec8e5ab35581ff470e90826b` が含まれている必要があります。以下のコマンドは、先ほど起動した `fwtpm_server` を再利用します。 + +!!! warning + これはデモです。アイデンティティ鍵は認証なし (空の auth) の決定論的な TPM プライマリ鍵であり、`gen_pqc_certs` とサーバーの双方がオーナー階層から再現できます。プライマリ鍵の鍵素材は、階層シードと作成時の入力から導出され、オブジェクトの auth 値はその導出を変えません。そのため、空でない auth 値やポリシーを追加するだけでは、オーナー階層配下で `CreatePrimary` を認可できる別の呼び出し元が同じ鍵を再作成することを防げません。実運用では、プロビジョニング済みの子オブジェクトまたは永続的なアイデンティティオブジェクトと、管理された階層の認可を組み合わせることを推奨します。クライアントはサーバーのチェーンをデモ CA に対して検証しますが、証明書をホスト名にバインドしません。そのため、デモはデフォルトの localhost に接続し、`-h=` を渡しません。`-h=` を指定すると、`wolfSSL_check_domain_name` を含む厳格な検証が有効になり、このリーフ証明書はそれを満たせません。実運用では、一致する subjectAltName を持つリーフ証明書を発行する必要があります。 + +関与するプログラムは 3 つです。 + +- `examples/pqc/gen_pqc_certs` は、ソフトウェアの ML-DSA CA と、サブジェクト鍵が TPM の ML-DSA 鍵であるデバイスのリーフ証明書を作成します。 +- `examples/tls/tls_server -mldsa` はその TPM 鍵を再作成し、TLS 1.3 を提供します。 +- `examples/tls/tls_client -mldsa` は接続し、ML-KEM 鍵交換を行い、CA を検証します。 + +```sh +# the fwtpm_server from "Running the examples" is already listening on 127.0.0.1:2321 + +# 1. certificate chain bound to the TPM key (-mldsa must match the server) +./examples/pqc/gen_pqc_certs -mldsa=65 + +# 2. server (same -mldsa as gen_pqc_certs) +./examples/tls/tls_server -p=11111 -mldsa=65 & + +# 3. client (choose the ML-KEM group) +./examples/tls/tls_client -p=11111 -mldsa -group=ML_KEM_768 +``` + +オプション: + +- `gen_pqc_certs -mldsa=44/65/87`: ML-DSA パラメータセット。 +- `tls_server -p= -mldsa=44/65/87`。 +- `tls_client -h= -p= -group=`。`` は `ML_KEM_512/768/1024`、またはハイブリッドの `SECP256R1MLKEM768` / `X25519MLKEM768` です (ハイブリッドには、対応する古典曲線が wolfSSL で有効になっている必要があります)。 + +ワンショットのエンドツーエンドテストは 3 つすべてを駆動し、ML-KEM グループ、TPM 署名による ML-DSA 認証、CA の検証を検証します。 + +```sh +ENABLE_PQC_TLS=1 ./examples/run_examples.sh # includes the PQC TLS matrix +``` + +## ベンチマーク + +`examples/bench/bench` で取得した、SEALSQ QVault TPM シリコン上での ML-DSA と ML-KEM のレイテンシ実測値 (鍵生成、署名、検証、カプセル化、デカプセル化) は、[benchmarks.md](benchmarks.md) に掲載されています。鍵生成は一度だけのプロビジョニングコストです。ML-DSA と ECDSA の数値を比較する前に、それらをどのように取得したかを同ページで確認してください。 + +## 関連項目 + +- [benchmarks.md](benchmarks.md) +- [FWTPM.md](fwtpm/overview.md) +- [DEVTPM.md](system-interfaces.md) +- [spdm.md](spdm.md) diff --git a/docs/ja/project-structure.md b/docs/ja/project-structure.md new file mode 100644 index 00000000..5207840e --- /dev/null +++ b/docs/ja/project-structure.md @@ -0,0 +1,75 @@ +# プロジェクト構成 + +このページでは、wolfTPM ソースツリーのトップレベルディレクトリとそれぞれの目的を一覧にし、ファームウェアTPM と SPDM のサブディレクトリ、およびライブラリのヘッダについて補足します。 + +## ソースツリー + +``` +wolfTPM/ + src/ TPM 2.0 core library and wrappers + fwtpm/ firmware TPM (fwTPM) server + spdm/ SPDM responder and vendor adapters + wolftpm/ public headers + fwtpm/ fwTPM headers + spdm/ SPDM headers + examples/ example applications + hal/ tpm_io_* IO callback backends + tests/ unit and API tests + IDE/ IDE and board projects + docs/ this manual and the Doxyfile + certs/ example keys and certificates + cmake/ CMake support files + m4/ autoconf macros + scripts/ test and helper scripts + tools/ documentation and SBOM tooling + wrapper/ language wrappers + zephyr/ Zephyr module +``` + +## ディレクトリの目的 + +| ディレクトリ | 目的 | +| --- | --- | +| `src/` | TPM 2.0 コア (`tpm2.c`、`tpm2_packet.c`、`tpm2_tis.c`、`tpm2_param_enc.c`、`tpm2_crypto.c`、`tpm2_asn.c`) とラッパー API (`tpm2_wrap.c`)。 | +| `src/fwtpm/` | ファームウェアTPM サーバー (`fwtpm_server`): コマンド処理、暗号、NV ストレージ、IO。 | +| `src/spdm/` | SPDM レスポンダとベンダーアダプタ。 | +| `wolftpm/` | `tpm2.h`、`tpm2_wrap.h`、`tpm2_types.h` を含む公開ヘッダ。 | +| `wolftpm/fwtpm/` | fwTPM サーバー用の公開ヘッダ。 | +| `wolftpm/spdm/` | SPDM 用の公開ヘッダ (`spdm.h`、`spdm_tcg.h`、`spdm_psk.h`、`spdm_responder.h`、およびベンダーヘッダ)。 | +| `examples/` | ネイティブ API とラッパー API のサンプルアプリケーション。 | +| `hal/` | Atmel、Barebox、Espressif、Infineon、Linux、Microchip、MMIO、QNX、ST、U-Boot、wolfHAL、Xilinx、Zephyr、fwTPM 向けの IO コールバックバックエンド (`tpm_io_*`)。 | +| `tests/` | ユニットテストと API テスト。 | +| `IDE/` | STM32CUBE、Espressif、QNX、IAR-EWARM、VisualStudio 向けのプロジェクト。 | +| `docs/` | このマニュアルと Doxygen 設定 (`Doxyfile`)。 | +| `certs/` | サンプルとテストで使用するサンプル鍵と証明書。 | +| `cmake/` | CMake サポートファイル。 | +| `m4/` | Autoconf マクロ。 | +| `scripts/` | テスト用およびヘルパースクリプト。 | +| `tools/` | ドキュメント用ツールと SBOM ジェネレータ (`tools/sbom`)。 | +| `wrapper/` | 言語ラッパー: `rust` と `CSharp`。 | +| `zephyr/` | Zephyr 統合。 | + +## ライブラリの配置 + +wolfTPM のヘッダファイルは次の場所にあります。 + +| ライブラリ | ヘッダの場所 | +| --- | --- | +| wolfTPM | `wolftpm/` | +| wolfSSL | `wolfssl/` | +| wolfCrypt | `wolfssl/wolfcrypt` | + +wolfTPM から include すべき汎用ヘッダを次に示します。 + +```c +#include +``` + +wolfTPM に付属するすべてのサンプルアプリケーションは、`hal/` にある `tpm_io.h` ヘッダを include します。`tpm_io.c` ファイルは、Linux カーネル、STM32 CubeMX HAL、または Atmel/Microchip ASF でサンプルアプリケーションをテストおよび実行するために必要な、サンプル用 HAL IO コールバックを設定します。このリファレンスは容易に変更でき、カスタムの IO コールバックや別のコールバックを必要に応じて追加または削除できます。 + +## 関連項目 + +* [ビルド](building.md) +* [ビルドオプション](build-options.md) +* [fwTPM の概要](fwtpm/overview.md) +* [SPDM アテステーション](spdm.md) diff --git a/docs/ja/release-notes.md b/docs/ja/release-notes.md new file mode 100644 index 00000000..37e50beb --- /dev/null +++ b/docs/ja/release-notes.md @@ -0,0 +1,109 @@ +# リリースノート + +このページでは、wolfTPM の最近のリリースを追跡します。リポジトリの ChangeLog から、Unreleased セクションと直近 2 つのリリースを転載しています。最初のリリースまでの完全な履歴は、リポジトリ最上位の [ChangeLog.md](https://github.com/wolfSSL/wolfTPM/blob/master/ChangeLog.md) にあります。 + +## Unreleased + +* TPM が割り当てる PCR バンクを変更するための `wolfTPM2_AllocatePCRBanks` を追加しました。 + - バンクの確認と再プロビジョニングを行う `examples/pcr/allocate` を追加しました。 + - fwTPM が、TPM 2.0 Part 3 22.5 に従って次回の `Startup(CLEAR)` で適用すべき割り当てを即座に適用していた問題、PCR バンクが 1 つも残らない選択を受け入れていた問題、`pcrSelect` ビットマップを無視していた問題、既存の NV ファイルに対する再起動後に割り当て済みバンクが報告されなかった問題を修正しました。 + +## wolfTPM Release 4.2.0 (Sep 14, 2026) + +**Summary** + +fwTPM (ファームウェア TPM) における TCG TPM 2.0 v1.85 仕様への準拠、ポスト量子暗号サポートの拡充、新しいプラットフォームバックエンドを中心とした、機能追加およびメンテナンスリリースです。主な内容は次のとおりです。fwTPM の v1.85 準拠に関する幅広い修正 (コマンド属性、PolicyAuthorize、コンテキスト Blob の認証、NV 認可、チケット HMAC の順序) と SPDM レスポンダの修正。ポスト量子 TLS 1.3 向けの ML-DSA 認証と SealSQ QVault ポスト量子 TPM のサポート。wolfHAL の I2C/SPI バックエンドと NVIDIA Jetson Orin OP-TEE fwTPM のサポート。ST33 ファームウェアアップデートの修正。トランスポートおよび NV/ハッシュの性能改善。広範なセキュリティ強化 (Coverity、静的解析、ネガティブテスト)。 + +**Detail** + +* ファームウェア TPM (fwTPM) の TCG v1.85 仕様準拠 + - コマンドコードのマスキングとベンダービットのリターンコードの修正 (PR #556) + - 認証エントリ処理の修正 (PR #566) + - PolicyAuthorize の準拠修正、および keySign の name チケットと approvedPolicy に対する応答コードの修正 (PRs #567, #572) + - ContextSave/ContextLoad でオブジェクトのコンテキスト Blob を認証 (PR #568) + - サポートされない LoadExternal の秘密鍵タイプを拒否、作成チケット HMAC の順序を修正、LoadExternal と CreateLoaded で ML-DSA / ML-KEM テンプレートを検証 (PRs #573, #578) + - NV 領域の認可を検証し、v1.85 リビジョンを報告 (PR #575) + - 階層およびポリシー認可の不備と、SPDM レスポンダのバージョンネゴシエーションを修正 (PR #577) + - コマンド属性の報告と、検証済みチケットの HMAC アルゴリズムを修正 (PR #579) + - TCG v1.85 に関する fwTPM と SPDM の追加の準拠修正 (PR #584) +* ポスト量子暗号と TLS + - ポスト量子 TLS 1.3 向けの TPM ベースの ML-DSA 認証。サンプルとテストを含む (PR #559) + - SealSQ QVault ポスト量子 TPM のサポート (PR #570) + - fwTPM における ML-KEM クレデンシャルのアクティベーションと ML-DSA クォート (PR #592) +* 新しいプラットフォームと HAL のサポート + - `--enable-wolfhal` とアプリケーション提供の `board.h` で有効化される wolfHAL の I2C および SPI バックエンド (PR #562) + - Linux TPM カーネルドライバ経由で `/dev/tpmrm0` として利用する、NVIDIA Jetson Orin (Tegra234) の OP-TEE ファームウェア TPM (PR #576) + - fwTPM におけるコマンドグループ単位のより細かいゲーティングマクロ (PR #574) + - ファームウェアアップグレード向けの、呼び出し元が指定するポリシー認可 (PR #560) +* ST33 ファームウェアアップデート + - Generation 1 のマニフェストサイズを修正し、サイズ超過のコマンドを拒否 (PR #583) + - TPM のコマンドセットから ST33 のフィールドアップグレードコマンドを選択 (PR #586) +* 性能 + - トランスポート接続を再利用し、NV 書き込みとハッシュキャッシュのオーバーヘッドを削減 (PR #563) +* セキュリティ強化 (Coverity、静的解析、入力検証) + - ネガティブテストとともに、crypto コールバック、ASN.1 解析、パラメータ暗号化、マーシャリングを強化 (PR #551) + - TPM2 応答の復号パラメータサイズに上限を設け、プライマリキーの認証値をゼロ化し、マーシャリング/インポートのテストカバレッジを拡充 (PR #555) + - fwTPM のプロパティパスにおける、汚染された PCR 選択のコピーを保護 (PR #558) + - fwTPM の応答バッファオーバーフローと、SPDM クリアフレームによるコマンドバイパスを修正 (PR #561) + - wolfTPM2 の PCR/ハッシュラッパーの検証を強化 (PR #554) + - TPM の入力検証とメモリ処理を強化 (PR #565) + - P521 プライマリ導出における wolfCrypt の参照カウント競合と、ポリシーセッション認可のバイパスを修正 (PR #571) + - PCR ポリシーの境界チェックを強化 (PR #581) + - wolfTPM の検証とデータ処理を強化 (PR #582) + - fwTPM のプロトコル処理と SPDM 認証を強化 (PR #588) + - fwTPM の状態変更をトランザクション化し、PolicyPCR と秘密 Blob のラッピングを強化 (PR #593) + - TPM の境界および構成パスにわたる Coverity の追加修正。fwTPM の子 Blob コピーの上限設定、公開名バッファ確保のガード、アンシールした出力ファイルの権限制限を含む (PRs #591, #595, #603, #605) + - fwTPM の鍵導出とコマンド検証を強化 (PR #596) + - TPM2 コアの鍵インポート解析と応答処理を修正し、コアのゼロ化と堅牢性を改善 (PRs #597, #600) + - サンプル、SPI 転送、SPDM バージョン解析におけるエラー処理と秘密情報のゼロ化を強化 (PRs #598, #599, #604) + - 切り詰められた fwTPM の Rewrap 入力を拒否、空ポリシーのオブジェクトに対するポリシーセッションにバインドされた認可を要求、keyed-hash の秘密全体を公開名にバインド、公開領域の解析でオーバーフロー時に失敗、TIS ロケーリティの戻り値を正規化、共有コマンドバッファに残ったリクエストバイトをクリア (PR #608) +* ビルド修正 + - OPENSSL_COEXIST の wolfSSL で AES_BLOCK_SIZE が未宣言になる問題を修正 (PR #552) + - TIS ロックありで wolfCrypt なしというエッジケースのビルドを修正 (PR #564) + - `--disable-wolfcrypt` と `--enable-pqc` を併用したビルドを修正 (PR #606) + - 期限切れの wolfSSL サンプル CA 証明書を更新し、更新スクリプトを追加 (PR #601) +* ドキュメントとライセンス + - コントリビューションガイダンス (CONTRIBUTING.md) を追加 (PR #569) + - ベースとなる GPLv3 ライセンスに対する GPLv2 例外: Cisco Systems, Inc. の U-Boot と組み合わせた wolfTPM は GPLv2 でライセンスできます (PR #557) + +## wolfTPM Release 4.1.0 (Jul 10, 2026) + +**Summary** + +TPM ロケーリティ制御とポスト量子暗号サポートの拡充を中心とした機能追加リリースです。主な内容は次のとおりです。実行時のロケーリティ選択 (`wolfTPM2_SetLocality`)、修正された fwTPM の PCR ごとのロケーリティ強制テーブル、オプションの GPIO nRST リセット HAL。きめ細かなビルドマクロを備えた、ファームウェア TPM への TPM 2.0 v1.85 ポスト量子暗号 (ML-DSA / ML-KEM) サポートの導入。fwTPM のディクショナリアタック対策の強化、`TPM_RC_RETRY` の透過的な処理、fwTPM 向けの SPDM セキュアトランスポート。FIPS 140-3 機能の報告。フリースタンディング (libc なし) ビルドのサポート。EU サイバーレジリエンス法 (CRA) への準拠に向けた SBOM (CycloneDX / SPDX) の生成。広範なセキュリティ強化 (Coverity、CodeQL)。 + +**Detail** + +* 実行時の TPM ロケーリティ制御 (PR #546) + - 新しい `wolfTPM2_SetLocality(dev, locality)` により、ロケーリティ 0-4 を実行時に選択できます。`examples/pcr/reset` は `-loc=n` フラグを受け付けます。組み込みの TIS/SPI ドライバ (プリエンプトしないチップ向けの解放とリトライを含む) と、ソケットおよび TIS/SHM 経由の fwTPM で動作します。ロケーリティを選択できない環境 (I2C、Linux カーネルドライバ、Windows TBS) では `NOT_COMPILED_IN` を返します + - fwTPM の PCR ごとのロケーリティ強制を、単一の信頼できる情報源となるテーブル (TCG PC Client プロファイル) に置き換えました。リセットマップを修正し、欠けていた PCR extend のチェックを追加し、適切な `RESET_L*`/`EXTEND_L*`/`DRTM_RESET` ビットマップを報告します。動作の変更: DRTM の PCR 17-22 はロケーリティ 0 から extend できなくなりました (`TPM_RC_LOCALITY` を返します) + - `TPM_CAP_ALGS`/`TPM_CAP_COMMANDS` のページングがプロパティカーソルを尊重するよう修正し、`moreData` に従うクライアントが先へ進めるようにしました + - オプションのハードウェアリセット HAL: `--enable-hal-reset[=LINE]` は `TPM2_IoCb_Reset()` を追加し、Linux GPIO キャラクタデバイス経由で nRST ラインにパルスを送ります (デフォルトは ST33 が GPIO24、Nuvoton が GPIO4) +* fwTPM における TPM 2.0 v1.85 ポスト量子暗号 (PQC) サポート: ML-DSA の署名/検証、ML-KEM のカプセル化/デカプセル化、および TCG Phase B に沿ったシード処理。PQC の CI とファズのカバレッジを含む (PR #445) + - フットプリントを削減するための、きめ細かなビルドマクロ: `WOLFTPM_PQC` (新しい軽量な `--enable-pqc`)、アルゴリズムごとの `WOLFTPM_MLDSA`/`WOLFTPM_MLKEM`、操作ごとのゲート、および `--enable-mldsa[=...]` / `--enable-mlkem[=...]` / `--disable-hash-mldsa` (PRs #527, #533) + - wolfSSL v5.8.0 以上という PQC の下限バージョンと、上流の変更を検知する CI。サンプルにおける ML-DSA の `TPM2_CreateLoaded` プライマリと PQC パラメータ暗号化。新しい `_ex` のセッション/OAEP/PQC ハッシュ用ラッパー (PRs #501, #509, #531, #539, #520) +* TCG 仕様に沿った fwTPM のディクショナリアタック (DA) 対策の強化 (PR #541): オブジェクトでの `noDA` の尊重、非正常シャットダウン時のペナルティとともに `failedTries` を永続化、`recoveryTime`/`lockoutRecovery` による自己回復、`TPM2_GetCapability` による DA プロパティの報告。`wolfTPM2_DictionaryAttackLockReset`/`wolfTPM2_DictionaryAttackParameters`、`examples/management/da_check` サンプル、`tests/fwtpm_da_retry.sh` ハーネスを追加 +* 一時的にビジー状態を報告する TPM 向けの、オプションの `TPM_RC_RETRY` 透過処理。`TPM2_SetCommandRetries` または `-DWOLFTPM_MAX_RETRIES=N` で有効化し、`WOLFTPM_NO_RETRY` でコンパイル時に除外できます (PR #537) +* SPDM セキュアトランスポートの fwTPM への拡張 (PR #510)、および FIPS 140-3 機能の報告 (PR #502) +* fwTPM のセッション、ポリシー、NV の修正: コマンドポート再接続をまたいだ一時的な状態の保持、パスワード認証応答での `continueSession` の設定、PolicyAuthorize のゼロチケット処理、ライトワンスフラッシュ向けポートの追記専用 NV ジャーナル (PRs #518, #530, #517, #540) +* 新しいサンプルとオプション: 暗号プリミティブのサンプル (getrandom、hash、AES、ECDH)、`WOLFTPM2_ECC_DEFAULT_CURVE` オプション (ZD 21780)、native_test における ECC P-384 のカバレッジ (PRs #532, #519, #492) +* Nations NS350 のサンプルスイートの修正: RSA-4096 のバッファサイズと、保存済みキータイプからの SRK アルゴリズム選択 (PR #494) +* フリースタンディングビルドのサポート: `WOLFTPM_NO_STD_HEADERS` により、ベアメタル向けの統合で `tpm2_types.h` から標準 C ヘッダーを除外します。`freestanding-build.yml` の CI ジョブも追加 (PR #549) +* EU サイバーレジリエンス法 (CRA) への準拠に向けたソフトウェア部品表 (SBOM) の生成: 新しい `make sbom` / `install-sbom` の autotools ターゲットと CMake の `sbom` ターゲットにより、ビルドされたライブラリ向けの CycloneDX および SPDX ドキュメントを出力し、wolfSSL を依存関係として記録します (PR #536) +* セキュリティ強化: 自動セキュリティレビュー (TPM2 パケットパーサーとマーシャリングの境界/範囲外アクセスの修正、秘密情報のゼロ化、ポリシー/チケットのバイパス修正)、fwTPM の PCR/シード/ハッシュ/シールの各パスにわたる Coverity の修正、CodeQL/Semgrep/Copilot のレビューゲート、`TPM2_ASN_RsaUnpadPkcsv15` におけるヒープ範囲外読み取りの修正 (PRs #496, #503, #511, #512, #518, #523, #535, #545, #547, #548, #543, #542, #544, #538, #513, #514, #524, #528, #507, #516) +* CI とビルドの改善: CMake のテストケースの拡充、GHCR コンテナイメージ、夜間ファジング、wolfSSL の最新安定版の自動解決、事前スモークテスト (PRs #495, #534, #522, #525, #508, #526, #521) +* バグ修正 + - wolfSSL PR 10604 に対応するため、wolfCrypt の crypto コールバックが `ALREADY_E` を伝播するよう修正 (PR #546) + - crypto コールバックとともに wolfCrypt の DRBG が使用されるようにし、HW RNG を備えた TPM では `TPM2_StirRandom` を TCG 準拠の何もしない処理にしました (PRs #498, #493) + - StartAuth のセッションノンスに TPM の RNG を使用する際の注意事項を追加 (ZD 21476, PR #478) + + +## 全履歴 + +これより古いリリースはここでは繰り返しません。すべてのリリースについては、リポジトリのルートにある `ChangeLog.md` を参照してください。 + +## 関連項目 + +- [テストと CI](testing.md) +- [SBOM とコンプライアンス](sbom-and-compliance.md) +- [API リファレンス](api-reference.md) diff --git a/docs/ja/rust-wrapper.md b/docs/ja/rust-wrapper.md new file mode 100644 index 00000000..15889f2a --- /dev/null +++ b/docs/ja/rust-wrapper.md @@ -0,0 +1,261 @@ +# Rust ラッパー + +`wolftpm` クレートは、wolfTPM 向けの安全な Rust バインディングを提供します。生の FFI は bindgen で生成され、`sys` モジュールに格納されています。クレートのそれ以外の部分は安全な API です。関数は `Result` を返し、TPM ハンドルはスコープを外れると解放され、すべての `unsafe` はクレート内部に閉じ込められています。このクレートは wolfTPM のソースツリー内の `wrapper/rust/wolftpm` にあります。 + +## 要件 + +- Rust と Cargo (stable、rustc 1.81 以降)。 +- ビルド済みの wolfTPM C ライブラリ (`libwolftpm`) とその依存先である wolfSSL (`libwolfssl`)。このクレートはビルド済みライブラリをリンクします。C コード自体はビルドしません。 +- テストにはソフトウェア TPM が必要です。wolfTPM 独自の `fwtpm_server`、または他の TPM エミュレータやソフトウェア TPM を使用できます。[fwTPM](fwtpm/overview.md) と [SWTPM](system-interfaces.md) を参照してください。 + +## ステップ 1: C ライブラリをビルドする + +wolfTPM リポジトリのルートで次を実行します。 + +```sh +./autogen.sh +./configure --enable-swtpm --enable-fwtpm +make +``` + +これにより `src/.libs/libwolftpm` が生成されます。`--enable-fwtpm` を指定すると、ソフトウェア TPM サーバー `src/fwtpm/fwtpm_server` もビルドされます。 + +## ステップ 2: クレートをビルドする + +```sh +cd wrapper/rust/wolftpm +cargo build +``` + +ビルドは次の順序でライブラリを探します。 + +1. `WOLFTPM_PREFIX` または `WOLFSSL_PREFIX` が設定されている場合は、インストール済みコピーの `$PREFIX/include` と `$PREFIX/lib` を使用します。 +2. それ以外の場合はツリー内のビルドを使用します。ヘッダーはリポジトリのルートから、ライブラリは `src/.libs` から取得します。wolfSSL は `pkg-config`、次にローカルの `./wolfssl`、あるいは隣接する `../wolfssl` チェックアウトの順に探されます。 + +共有ライブラリが優先されます。共有ライブラリが存在しない場合は静的ライブラリが使用されます。 + +このライブラリは `no_std` であり、所有する鍵、blob、出力バッファのために `alloc` を使用します。ベアメタルアプリケーションはグローバルアロケータを提供する必要があります。ビルドスクリプトは、FFI バインディングの生成時に、`riscv32imac-unknown-none-elf` のような Rust のクロスコンパイルターゲットを clang のターゲット表記に変換します。 + +`wrapper/rust` ディレクトリには、一般的な作業用の Makefile もあります。C ライブラリのビルド後、`make -C wrapper/rust` でクレートのビルド、lint、ドキュメント生成を行い、`make -C wrapper/rust test` でテストを実行します (ソフトウェア TPM が `localhost:2321` で待ち受けている必要があります)。 + +## ステップ 3: テストを実行する + +統合テストはソケット経由でソフトウェア TPM と通信します。これらは `swtpm-tests` フィーチャーの背後にあるため、通常の `cargo test` では実行中のサーバーは不要です。 + +ポート 2321 でサーバーを起動します (リポジトリのルートから)。 + +```sh +./src/fwtpm/fwtpm_server --clear --port 2321 --platform-port 2322 & +``` + +サーバーに対してテストを実行します。 + +```sh +cd wrapper/rust/wolftpm +TPM2_SWTPM_HOST=localhost TPM2_SWTPM_PORT=2321 \ + cargo test --features swtpm-tests -- --test-threads=1 +``` + +ソフトウェア TPM は一度に 1 つのクライアントしか処理しないため、`--test-threads=1` を使用してください。 + +署名テストなど、単一のテストファイルを実行するには次のようにします。 + +```sh +cargo test --features swtpm-tests --test sign -- --test-threads=1 +``` + +既定のホストとポートは `localhost:2321` であるため、サーバーがそのアドレスにある場合は環境変数を省略できます。 + +## テストの検証内容 + +`tests/` 配下の各ファイルは、ソフトウェア TPM に対して 1 つの領域を検証します。 + +| ファイル | 検証内容 | +| --- | --- | +| `tests/smoke.rs` | 乱数バイト列が取得ごとに異なること、およびプライマリ鍵がロードされること。 | +| `tests/keys.rs` | 子鍵の作成とロード、blob のラウンドトリップ、短い auth の blob のラウンドトリップ、および auth で保護された親鍵。 | +| `tests/sign.rs` | ダイジェストへの署名と検証、および改ざんされた署名の拒否。 | +| `tests/seal.rs` | 秘密情報のシールとアンシール、および誤った auth での失敗。 | +| `tests/seal_pcr.rs` | PCR にバインドされたシールとアンシール、PCR 変更後にアンシールが失敗すること、および無効な PCR 選択の拒否。 | +| `tests/nv.rs` | NV インデックスの定義、書き込みと読み出し、その後の削除。 | +| `tests/pcr.rs` | PCR の読み出し、拡張、および値が変化したことの確認。 | +| `tests/certify.rs` | アテステーション鍵 (ECC と RSA) による別の鍵の certify。 | +| `tests/quote.rs` | ECC および RSA の AIK による PCR の quote、および不正な PCR 選択の拒否。 | +| `tests/credential.rs` | MakeCredential から ActivateCredential へのラウンドトリップ。 | +| `tests/ek.rs` | エンドースメント鍵の作成と、その公開部分のエクスポート。 | +| `tests/persist.rs` | 鍵の永続化、読み戻し、および evict。 | +| `tests/rsa.rs` | RSA-OAEP の暗号化と復号、および明示的な OAEP-SHA1 のラウンドトリップ。 | +| `tests/hmac.rs` | 生の鍵による HMAC、および TPM 常駐の keyed-hash 鍵による HMAC。 | +| `tests/caps.rs` | セルフテストとケイパビリティの問い合わせ。 | +| `tests/ecdh.rs` | ECDH の生成と、同じ共有秘密の復元。 | +| `tests/symmetric.rs` | AES-CFB の暗号化と復号のラウンドトリップ。 | +| `tests/import.rs` | 外部の RSA および ECC 秘密鍵のインポート。 | + +## テスト出力の例 + +``` +running 2 tests +test certify_with_ecc_aik ... ok +test certify_with_rsa_aik ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 4 tests +test create_and_load_child ... ok +test key_blob_roundtrip_then_load ... ok +test key_blob_roundtrip_preserves_short_auth ... ok +test auth_protected_parent_loads_child ... ok +test result: ok. 4 passed; 0 failed; 0 ignored + +running 2 tests +test sign_then_verify ... ok +test verify_rejects_tampered_signature ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 2 tests +test rsa_oaep_roundtrip ... ok +test rsa_oaep_sha1_roundtrip ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 1 test +test make_and_activate_credential ... ok +test result: ok. 1 passed; 0 failed; 0 ignored +``` + +## ステップ 4: サンプルを実行する + +サンプルは 2 つあります。1 つ目は最小構成です。 + +```sh +cargo run --example create_primary +``` + +これはソフトウェア TPM を開き、乱数バイト列を読み出し、RSA と ECC のストレージルートキーを作成します。 + +2 つ目は API 全体を一度に実行します。 + +```sh +cargo run --example full_flow +``` + +期待される出力は次のとおりです。乱数バイト列とハンドル値は実行ごとに異なります。 + +``` +device connected to software TPM +get_random a91b37b1838d002453f1632ba2c0adbc +create_primary ECC SRK handle 0x80000000 +create_and_load signing key handle 0x80000001 +sign/verify 64 byte signature, verified +seal/unseal recovered "my secret" +key blob 257 bytes, reloaded as handle 0x80000002 +pcr read/extend PCR16 000000000000.. -> debb3e7acfff.. +nv define/rw 32 bytes at index 0x01500100 +certify 157 byte attestation +done all operations succeeded +``` + +wolfTPM C ライブラリがデバッグ出力付きでビルドされている場合は、ライブラリからの詳細な TPM2_* トレースも表示されます。通常のビルドでは上記の行のみが出力されます。 + +## ラッパーの使い方 + +```rust +use wolftpm::{Device, HashAlg, Hierarchy, KeyAlg, KeyBlob, Template}; + +fn main() -> Result<(), wolftpm::TpmError> { + // Connect to a software TPM. Use Device::open() for the platform default. + let dev = Device::open_swtpm()?; + + // Random bytes from the TPM. + let mut nonce = [0u8; 32]; + dev.get_random(&mut nonce)?; + + // Storage root key under the owner hierarchy. + let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?; + + // Signing key under the SRK, then sign and verify a digest. + let signer = dev.create_and_load(&srk, &Template::signing(KeyAlg::EccP256)?, None)?; + let digest = [0x11u8; 32]; + let sig = signer.sign_hash(&digest)?; + signer.verify_hash(&digest, &sig)?; + + // Seal a secret to the TPM and read it back. + let sealed = dev.seal(&srk, b"my secret", None)?; + let _secret = dev.unseal(sealed, &srk, None)?; + + // Persist a key as bytes, then load it again. Scope the reloaded key so it + // releases its TPM handle before more transient objects are created below + // (many TPMs allow only three transient objects at once). + let bytes = { + let blob = dev.create_key(&srk, &Template::signing(KeyAlg::EccP256)?, None)?; + blob.to_bytes()? + }; + { + let restored = KeyBlob::from_bytes(&dev, &bytes)?; + let _loaded = restored.load(&srk, None)?; + } + + // Read and extend a PCR. + let _value = dev.pcr_read(16, HashAlg::Sha256)?; + dev.pcr_extend(16, HashAlg::Sha256, &[0xAB; 32])?; + + // Define, write, read, and delete an NV index. + let mut slot = dev.nv_create(0x0150_0100, 32, None)?; + dev.nv_write(&mut slot, b"metadata", 0)?; + let mut buf = [0u8; 32]; + dev.nv_read(&mut slot, &mut buf, 0)?; + dev.nv_delete(0x0150_0100)?; + + // Attest that a key lives in this TPM, signed by an attestation key. + let aik = dev.create_and_load(&srk, &Template::attestation(KeyAlg::EccP256)?, None)?; + let _attestation = dev.certify(&signer, &aik, &nonce)?; + + Ok(()) +} +``` + +鍵とデバイスは、ドロップ時に TPM ハンドルを自動的に解放します。 + +## クレートが対応する範囲 + +- デバイスのオープンとクリーンアップ、TPM 乱数、セルフテスト、およびケイパビリティの問い合わせ。 +- プライマリ鍵と子鍵。ストレージ、署名、アテステーション、EK、RSA 復号、keyed-hash HMAC、対称 AES、ECDH の各鍵用テンプレート。 +- 永続化のための鍵 blob のシリアライズとロード、および外部 RSA / ECC 鍵のインポート。 +- 永続鍵ハンドル: 保存、読み戻し、および evict。 +- 署名と検証。 +- RSA-OAEP の暗号化と復号 (明示的なラベルハッシュを含む。Microsoft エンロールメントとの相互運用には SHA-1)。 +- 対称 AES-CFB の暗号化と復号。 +- ECDH 鍵共有。 +- HMAC (生の鍵を使う場合と、TPM 常駐の keyed-hash 鍵を使う場合の両方)。 +- シールとアンシール (通常のものと、PCR ポリシーにバインドされたもの)。 +- PCR の読み出しと拡張。 +- NV の定義、書き込み、読み出し、削除、および証明書の読み出し (EK 証明書)。 +- アテステーション: 鍵の certify と PCR の quote。 +- クレデンシャルのアクティベーション: MakeCredential と ActivateCredential。 + +復元された秘密情報 (unseal、RSA 復号、ECDH、AES 復号、クレデンシャルのアクティベーション) は `Secret` で返され、ドロップ時にそのバッファがゼロ化されます。 + +## トランスポートのセキュリティ + +TPM トランスポートの機密性を確保するには、秘密情報を扱う操作の前に `Device::start_encrypted_session` でパラメータ暗号化セッションを開始します。 + +```rust +let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?; +let _session = dev.start_encrypted_session(&srk)?; // salted HMAC + AES-CFB +let sealed = dev.seal(&srk, b"secret", None)?; // command param encrypted +let plain = dev.unseal(sealed, &srk, None)?; // response param encrypted +``` + +セッションが有効な間、そのソルト付き HMAC セッションが auth スロット 1 を占有するため、wolfTPM は seal/unseal、RSA と AES の暗号化/復号、HMAC、NV、ECDH、鍵の作成/ロードにおける機微なコマンドパラメータとレスポンスパラメータを暗号化します。同時に許可されるセッションは 1 つのみです。アテステーションコマンド (certify、quote、activate_credential) は同じ auth スロットを必要とするため、セッションがアクティブな間は拒否されます。これらを呼び出す前にセッションをドロップしてください。 + +!!! warning + セッションがない場合、パラメータは平文のままトランスポートを流れます。セッションを使用するか、リモートの `TPM2_SWTPM_HOST` や観測可能な物理バスではなく、信頼できるローカルトランスポート (Linux カーネルデバイスやローカルソケット) 上で実行してください。 + +## ライセンス + +wolfTPM と同じく、GPLv3 または wolfSSL の商用ライセンスです。 + +## 関連項目 + +- [fwTPM](fwtpm/overview.md) +- [SWTPM](system-interfaces.md) +- [Build Options](build-options.md) +- [C# Wrapper](csharp-wrapper.md) diff --git a/docs/ja/sbom-and-compliance.md b/docs/ja/sbom-and-compliance.md new file mode 100644 index 00000000..9faef7e7 --- /dev/null +++ b/docs/ja/sbom-and-compliance.md @@ -0,0 +1,105 @@ +# SBOM とコンプライアンス + +wolfTPM は、EU サイバーレジリエンス法 (CRA) への準拠を支援するため、ソフトウェア部品表 (SBOM) を生成できます。このページでは、その生成方法とジェネレータの構成を説明します。 + +## SBOM と EU CRA コンプライアンス + +wolfTPM は CycloneDX 1.6 および SPDX 2.3 形式で SBOM を生成します。ジェネレータは `tools/sbom/` にベンダリングされた wolfGlass のスナップショットで、`tools/sbom/.wolfglass-rev` で固定されています。SBOM には、設定されたビルドオプション (`wolftpm/options.h` から取得)、ビルドされた `libwolftpm` ライブラリ成果物 (共有または静的、ELF、Mach-O、PE) のハッシュ、および依存関係としての wolfSSL が記録されるため、脆弱性スキャナーは wolfSSL のアドバイザリを wolfTPM のデプロイメントに関連付けることができます。 + +出力は再現可能です。`SOURCE_DATE_EPOCH` を設定する (または最後のコミット時刻が使用される git チェックアウトからビルドする) と、繰り返し実行しても出力はバイト単位で同一になります。 + +autotools の場合: + +```sh +make sbom +``` + +これには `python3` と `pyspdxtools` (`pip install spdx-tools`) が必要です。ジェネレータはツリーに同梱されているため、`make sbom` に別途 wolfSSL のチェックアウトは必要ありません。このビルドがリンクした wolfSSL を pkg-config が認識できない場合は、`WOLFSSL_DIR=/path/to/wolfssl` を渡すと、依存関係のバージョンが `wolfssl/version.h` から読み取られます。`SBOM_WOLFSSL_VERSION` を指定すると、この検出結果を上書きできます。 + +CMake ビルドでも同じターゲットを利用できます。`WOLFSSL_DIR` は任意で、意味は同じです。 + +```sh +cmake -B build . +cmake --build build --target sbom +``` + +出力ファイルは次のとおりです。 + +- `wolftpm-.cdx.json` +- `wolftpm-.spdx.json` +- `wolftpm-.spdx` + +任意の上書き設定: + +| 変数 | 目的 | +|---|---| +| `SBOM_LICENSE_OVERRIDE` | `COPYING` から解析されたライセンスの代わりに使用する SPDX 式 (例: 商用ライセンス利用者向けの `LicenseRef-wolfSSL-Commercial`)。デフォルトは、ファイルごとのヘッダーに記載されたライセンスである `GPL-3.0-or-later` です。 | +| `SBOM_LICENSE_TEXT` | `SBOM_LICENSE_OVERRIDE` で使用する `LicenseRef-*` のライセンス本文へのパス (SPDX 2.3 で必須)。 | +| `SBOM_WOLFSSL_VERSION` | wolfSSL 依存関係として記録されるバージョン。未設定の場合は `WOLFSSL_DIR/wolfssl/version.h` (または wolfSSL の `pkg-config` エントリ) から自動検出されます。 | + +生成されたファイルをインストールするには: + +```sh +make install-sbom # installs to $(datadir)/doc/wolftpm/ +make uninstall-sbom +``` + +CRA に関するさらなるガイダンスは [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md) を参照してください。 + +## ジェネレータの内部構成 + +wolfGlass のうち、ベンダリング可能なのは `share/` セットのみです。`tools/wolfglass-sync` スクリプトは、これらのファイルを、固定用ファイル (`VERSION` と `.wolfglass-rev`) とともに、製品内の `tools/sbom/` にコピーします。コピーするのはファイルであり、`share/` フォルダ名ではありません。 + +### 内容 + +| ファイル | 役割 | +|---|---| +| `sbom-driver.py` | 製品に依存しない SBOM エンジン (Python)。 | +| `sbom-driver` | `sbom-driver.py` を実行する薄いシェルラッパー。 | +| `validate_sbom.py` | CI 向けの構造バリデータ (`--name-prefix`)。 | +| `frontends/compdb_sbom.py` | 任意の `compile_commands.json` に対するエクストラクタ。 | +| `frontends/iar_sbom.py` | IAR Embedded Workbench の `.ewp` に対するエクストラクタ。 | +| `frontends/zephyr_sbom.py` | Zephyr モジュールの `CMakeLists.txt` に対するエクストラクタ。 | +| `build/sbom.mk` | 共有のプレーン Make フラグメントと `wolfglass_sbom_rule` マクロ。 | +| `build/sbom.cmake` | 共有の CMake ヘルパー: `wolfglass_add_sbom()`。 | +| `gen-sbom` | ベンダリングされた SBOM ジェネレータ。 | +| `sbom.am` | 共有の autotools フラグメント。 | + +### ドライバの契約 + +すべてのフロントエンドは、コンポジション入力とコンフィグ入力を生成し、ドライバに渡します。 + +コンポジション (少なくとも 1 つ): + +- `--srcs-file PATH`: 成果物にコンパイルされるソースファイル (tier E)。 +- `--lib PATH`: ハッシュ対象のビルド済みライブラリ (tier R/L/S)。 +- `--no-artifact-hash`: 成果物をビルド済みのまま記録し、再ハッシュしません。FIPS キャニスターやカーネルモジュールでは `--lib` と併用します。認証済み成果物の代わりにソースリストを使用してはいけません。 + +コンフィグ (いずれか 1 つを選択): + +- `--cflags="..."`: 生の CFLAGS。ドライバはホストコンパイラを通して `-D` トークンを展開します。先頭がダッシュの値がフラグとして解釈されないよう、`=` 形式を使用してください。 +- `--options-h PATH`: 事前展開済みのフラットな `#define` ヘッダー。そのまま使用されます。 +- `--user-settings PATH`: ジェネレータが取り込む `user_settings.h`。 +- `--source-only`: ビルド設定マクロなし (例: Kconfig 駆動のビルド)。 + +依存関係 (リンカーとバインディング向け): `--dep-wolfssl`、`--dep-openssl`、`--dep-version` は、ジェネレータが対応している場合にのみ受け渡されます。 + +ドライバはホストコンパイラでマクロを取得するため、SBOM はツールチェーンをまたいで再現可能です。`--no-scrub` を指定しない限り、取得したマクロからホストの絶対パスを除去します。 + +共有ドライバは製品に依存せず、デフォルトではベンダリングされた `share/gen-sbom` を呼び出します。そのコピーを上書きしたい場合にのみ `--gen-sbom` を指定してください。 + +### マニフェストの契約 + +製品はロジックをコピーしません。自身を記述します。 + +- **Make:** `SBOM_NAME`、`SBOM_SRCS`、`SBOM_CFLAGS`、およびバージョン (`SBOM_VERSION`、または `SBOM_VERSION_FILE` と `SBOM_VERSION_MACRO`) を設定し、`include tools/sbom/build/sbom.mk` します。2 つ目のターゲットには `$(eval $(call wolfglass_sbom_rule,,))` をインスタンス化します。製品の構成が `user_settings.h` にある場合は、`SBOM_SETTINGS_H` も設定します (そのヘッダーが CFLAGS にまだ含まれていないパスを必要とする場合は `SBOM_INCLUDE_DIRS` も設定)。`SBOM_CFLAGS` だけでは、文字どおりの `-D` の集合のみが記録され、そこから派生するものは記録されません。ゲートされたヘッダーでは、SBOM が誰もビルドしていない構成を記述してしまうことになります。 +- **CMake:** `include(tools/sbom/build/sbom.cmake)` し、`NAME`、`VERSION_FILE`、`VERSION_MACRO`、`TARGETS`、`DEFS`、`LICENSE` を指定して `wolfglass_add_sbom()` を呼び出します。`SBOM_GEN` が正式なジェネレータ上書き用の変数です。`GEN_SBOM` は互換性のため、従来のエイリアスとして残されています。 +- **Autotools:** `SBOM_*` 変数を設定し、`include tools/sbom/sbom.am` します。 + +製品に残すのは、真に製品固有の知識のみです。具体的には、ルーティング用スクリプト、モジュールエクストラクタ、HAL ソースセレクタです。 + +## 関連項目 + +- [テストと CI](testing.md) +- [リリースノート](release-notes.md) +- [API リファレンス](api-reference.md) diff --git a/docs/ja/sealing-and-nvram.md b/docs/ja/sealing-and-nvram.md new file mode 100644 index 00000000..9b6d7610 --- /dev/null +++ b/docs/ja/sealing-and-nvram.md @@ -0,0 +1,350 @@ +# シーリングと NVRAM + +TPM 2.0 は、安全な保管庫として機能します。このページでは、キーまたは PCR 値に対するシークレットのシーリング、TPM の不揮発性メモリ (NVRAM) へのキーとデータの保存、およびその両方を使用したセキュアブートのルートオブトラストのサンプルを説明します。すべてのサンプルは他の wolfTPM サンプルと一緒にビルドされ、wolfTPM ソースツリーのルートから実行します。 + +## シールとアンシールの概要 + +TPM 2.0 は、標準的な Seal/Unseal の手順でシークレットを保護できます。シールは、TPM 2.0 のキーに対して、または PCR 値のセットに対して作成できます。 + +!!! note + キーにシールされるシークレットデータの最大サイズは 128 バイトです。 + +最もシンプルなサンプルのペアは `seal/seal` と `seal/unseal` です。パラメータなしで実行すると、デモ用の使い方が表示されます。 + +### TPM 2.0 キーへのデータのシール + +`seal` サンプルは、新しく生成した TPM 2.0 キーにデータを安全に保存します。このキーが TPM にロードされた場合にのみ、シークレットデータを読み戻すことができます。 + +シークレットメッセージのシールとアンシールの出力例: + +```sh +$ ./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 +``` + +アンシールに成功すると、データは新しいファイルに保存されます。ファイル名を指定しない場合、`unseal` ツールはデータを `unseal.bin` に保存します。 + +### 署名付きポリシーによる PCR へのシール + +固定の PCR 値に伴う脆弱性なしにシークレットを PCR にシールするには、外部キーが想定される PCR の状態に署名します。下記の Secure boot root of trust と、次のセクションの `seal_policy_auth` サンプルを参照してください。 + +## シールのサンプル + +`examples/seal/` ディレクトリには、異なる認可ポリシーによる TPM 2.0 のシールとアンシールのサンプルが、最もシンプルなものから最も柔軟なものの順に含まれています。 + +### seal と unseal (パスワードポリシー) + +パスワードベースの認可ポリシーを使用する、最もシンプルなシールとアンシールです。 + +```sh +./examples/seal/seal keyblob.bin mySecretData +./examples/seal/unseal output.bin keyblob.bin +``` + +### seal_pcr (PCR のみのポリシー) + +特定の PCR 値にバインドされたシークレットをシールします。シークレットは、PCR 値がシール時に計測された値と一致する場合にのみアンシールできます。パスワードや署名キーは必要ありません。 + +ユースケース: Static Root of Trust、シークレットを特定のブート状態にバインドする。 + +```sh +# 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 と PCR) + +TPM 内に存在する署名キーと PCR ポリシーを用いた PolicyAuthorize で、シークレットをシールします。署名キーは新しい PCR 値に対してポリシーを再認可できるため、OS アップデートのような認可された変更があってもシークレットを維持できます。 + +ユースケース: 認可されたポリシー更新を伴う柔軟なメジャードブート。 + +!!! note + `authkey.bin` と `sealblob.bin` は一緒に保管する必要があります。署名キーを再生成すると、シールされたブロブはアンシールできなくなります。 + +```sh +# 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 ストレージと PCR ポリシー) + +PCR ポリシーで保護された TPM の NV (不揮発性) メモリにシークレットを保存します。ファイルベースのシールされたブロブとは異なり、シークレットは完全に TPM の内部に存在します。このプログラムは `examples/nvram/seal_nv` にあります。 + +ユースケース: 外部ファイルなしで TPM ハードウェア内に保持する必要があるシークレット。 + +```sh +# 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 +``` + +### テスト + +`seal_test.sh` は、3 つのシールサンプルグループすべてにわたって 28 件のテストを実行します。 + +```sh +bash examples/seal/seal_test.sh +``` + +テストには、正常系 (シールとアンシールのライフサイクル、シークレットの検証)、異常系 (PCR の不一致、auth キーの欠落)、パラメータ暗号化のバリエーション (XOR、AES)、カスタムのファイル名と NV インデックスが含まれます。出力では、色付きの PASS、FAIL、SKIP のマーカーとサマリーが使用されます。詳細な出力は `seal_test.log` に保存されます。 + +| 変数 | デフォルト | 説明 | +|----------|---------|-------------| +| `WOLFCRYPT_ENABLE` | 1 | wolfCrypt のサポートがコンパイルされている | +| `WOLFCRYPT_DEFAULT` | 0 | デフォルト (縮小版) の wolfCrypt 設定を使用している | +| `WOLFCRYPT_ECC` | 1 | ECC のサポートが利用可能 | +| `WOLFCRYPT_RSA` | 1 | RSA のサポートが利用可能 | + +シールのサンプルは、`make check` の間に実行される `examples/run_examples.sh` の一部としてもテストされます。 + +### ポリシーの比較 + +| 機能 | seal (パスワード) | seal_pcr | seal_policy_auth | seal_nv | +|---------|----------------|----------|-----------------|---------| +| 認可 | パスワード | PCR 値 | 署名キー + PCR | PCR 値 | +| 複雑さ | 低 | 低 | 高 | 中 | +| PCR 変更後も維持 | 該当なし | 不可 | 可 (auth キーあり) | 不可 | +| ストレージ | ファイル | ファイル | ファイル (ブロブ + キー) | TPM NV | +| パラメータ暗号化 | 可 | 可 | 可 | 可 | + +## NVRAM へのキーの保存 + +これらのサンプルは、TPM をキーの安全な保管庫として使用する方法を示します。プログラムは 2 つあります。1 つは TPM キーを TPM の NVRAM に保存し、もう 1 つは NVRAM からキーを取り出します。どちらも、MITM 攻撃から保護するためにパラメータ暗号化を使用できます。NV の保存場所はパスワード認可で保護されており、コマンドラインで `-aes` を指定すると、そのパスワードは暗号化された形式で渡されます。 + +サンプルを実行する前に、keygen ツールで `keyblob.bin` が生成されていることを確認してください。キーの種類は RSA、ECC、対称キーのいずれでもかまいません。サンプルは秘密部と公開部を保存します。対称キーの場合、公開部は TPM からのメタデータです。 + +パラメータ暗号化を有効にして RSA キーを保存し、その後読み取る場合の典型的な出力: + +```sh +$ ./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 +``` + +`read` サンプルは、公開部と秘密部の両方が NVRAM に保存されている場合、取り出したキーのロードを試みます。`-aes` スイッチはパラメータ暗号化を有効にします。 + +これらのサンプルは、`-priv` と `-pub` オプションを使用して、秘密部のみ、または公開部のみといった部分的なキー素材でも動作します。パラメータ暗号化なしで、RSA キーペアの秘密部のみを保存する場合の典型的な出力: + +```sh +$ ./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 +``` + +`read` でキーの取り出しに成功すると、NV インデックスは破棄されます。`read` を再度使用するには、先に `store` を再実行してください。 + +### NVRAM プログラム + +すべてのプログラムは `examples/nvram/` にあります。 + +| プログラム | 目的 | +|---------|---------| +| `store.c` | TPM キー (秘密部、公開部、または両方) を NV インデックスに保存します。 | +| `read.c` | NV からキーを読み戻してロードし、NV インデックスを削除することもできます。 | +| `counter.c` | NV カウンターを作成してインクリメントします。 | +| `extend.c` | PolicyOR によるバス保護を示す NV extend のサンプルです。 | +| `policy_nv.c` | データを NV に保存し、TPM2_PolicyNV ベースの認可をテストします。 | +| `seal_nv.c` | PCR ポリシーで保護されたシークレットを NV に保存します (シールのサンプル を参照)。 | + +## セキュアブートのルートオブトラスト + +`examples/boot/` ディレクトリには、wolfBoot などのセキュアブート向けの、TPM ベースのルートオブトラストの設計が含まれています。 + +### セキュアブートの ROT + +公開鍵ベースのルートオブトラストを TPM に保存するための設計: + +1. すべての通信に AES-CFB パラメータ暗号化 (salted および bound) を使用します。 +2. デバイス固有のパラメータからパスワードを導出し、NV をロードする (認証する) ための "auth" として使用します。 +3. NV には公開鍵のハッシュが格納されます (ハッシュは `.config` の設定と一致します)。 +4. wolfBoot は引き続き内部に公開鍵を保持しており、NV が未設定の場合は TPM の NV を書き込みます。 +5. NV はロックされ、プラットフォーム階層の下に作成されます。 + +例: + +```sh +$ ./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 +``` + +### セキュアブートの暗号鍵ストレージ + +脆弱性の問題なしにシークレットを PCR にシールするには、外部キーが PCR の状態に署名します。 + +| ツール | 目的 | +|------|---------| +| `./examples/pcr/policy_sign` | PCR ポリシー用のダイジェストに署名します。署名を出力し、`-outpolicy` を指定すると公開鍵に対する認可ポリシーダイジェストも出力します。 | +| `./examples/boot/secret_seal` | 公開鍵に対する認可ポリシーダイジェストを使用してシークレットをシールします。シークレットを指定しない場合は、ランダムな値が生成されてシールされます。 | +| `./examples/boot/secret_unseal` | 署名付き認可ポリシーと公開鍵を使用してシークレットをアンシールします。 | + +署名付き PCR ポリシーを作成します。 + +```sh +# 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 +``` + +公開鍵に基づく、その署名付きポリシーを使用して、シールされたシークレットを作成します。 + +```sh +# 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 +``` + +アンシール: + +```sh +# 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 +``` + +## 関連項目 + +- [TLS and certificates](tls-and-certificates.md) +- [Management and GPIO](management-and-gpio.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/ja/spdm.md b/docs/ja/spdm.md new file mode 100644 index 00000000..140eef30 --- /dev/null +++ b/docs/ja/spdm.md @@ -0,0 +1,589 @@ +# SPDM アテステーションとセキュアセッション + +wolfTPM には、wolfSSL/wolfCrypt を使用した、Nuvoton NPCT75x および Nations NS350 TPM 向けの SPDM (Security Protocol and Data Model、DMTF DSP0274) サポートが組み込まれています。SPDM は、TCG の SPDM-over-TPM バインディング上でプロトコルバージョン 1.3 をネゴシエートします。両ベンダーとも、セッション確立のためのアイデンティティ鍵モード (ECDHE P-384) をサポートしています。Nations NS350 は、さらに PSK (事前共有鍵) モードもサポートしています。セッションが確立されると、すべての TPM コマンドとレスポンスは、既存の SPI または I2C バス上で AES-256-GCM により暗号化されます。アイデンティティ鍵モードでは、信頼できるプロビジョニング元から得たレスポンダーの P-384 公開鍵が必要です。TCG の交換は生の公開鍵の交換 (GET_PUBK と GIVE_PUB) であり、証明書は交換されません。 + +SPDM のコードは [wolfSPDM](https://github.com/wolfSSL/wolfSPDM) ライブラリにあり、`lib/wolfSPDM` サブモジュールとして含まれ、TPM プロファイルで libwolftpm にコンパイルされます。SPDM を使用するチェックアウトには、再帰的なクローン、または後からの初期化によって、このサブモジュールが存在している必要があります。サブモジュールがない場合、`./configure --enable-spdm` は次のメッセージで停止します: `--enable-spdm needs the wolfSPDM submodule: run git submodule update --init lib/wolfSPDM`。 + +## クイックスタート + +SPDM は `lib/wolfSPDM` サブモジュールにあるため、再帰的にクローンします。 + +```sh +git clone --recursive https://github.com/wolfSSL/wolfTPM.git +git clone https://github.com/wolfSSL/wolfssl.git # sibling checkout +cd wolfTPM +``` + +`--recursive` なしでクローン済みの場合は、チェックアウト内で `git submodule update --init lib/wolfSPDM` を一度実行してください。 + +### Nuvoton NPCT75x + +```sh +# Build wolfSSL (in the sibling checkout, then return here) +cd ../wolfssl && ./autogen.sh && \ +./configure --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp && \ +make && sudo make install && sudo ldconfig && cd - + +# Build wolfTPM (submodule already present from the recursive clone) +./autogen.sh && ./configure --enable-spdm --enable-nuvoton && make + +# Enable SPDM (one-time), then reset the TPM, then connect +./examples/spdm/spdm_ctrl --enable +# reset the TPM now (see "TPM reset pin control" for the gpioset and reset-HAL commands) +RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +./examples/spdm/spdm_ctrl --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +リセットのコマンドとその注意事項については、TPM リセットピン制御のセクションを参照してください。`responder_pubkey.hex` には、プロビジョニング記録から得た、信頼できる生の P-384 X||Y 点 (192 文字の 16 進数) が格納されています。 + +### Nations NS350 + +```sh +# Build wolfSSL (in the sibling checkout, then return here) +cd ../wolfssl && ./autogen.sh && \ +./configure --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp && \ +make && sudo make install && sudo ldconfig && cd - + +# Build wolfTPM (submodule already present from the recursive clone) +./autogen.sh && ./configure --enable-spdm --enable-nations && make + +# Connect (identity key is factory default) +RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +./examples/spdm/spdm_ctrl --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +## 概要と動作の仕組み + +`spdm_ctrl` ツールは、ホストと TPM の間に SPI または I2C 経由で SPDM セキュアセッションを確立し、AES-256-GCM で暗号化されたバス通信を可能にします。実装は Algorithm Set B (SHA-384 と AES-256-GCM) を使用し、アイデンティティ鍵モードではこれに ECDH P-384、ECDSA P-384、HKDF-SHA384 が加わります。セッション確立モードは 2 つサポートされています。 + +SPDM の資格情報を受け付けるサンプルは `spdm_ctrl` と `nv_bind` です。その他の wolfTPM サンプルは、資格情報なしの `wolfTPM2_Init()` を使用しており、TPM が SPDM 専用モードでロックされている間は意図的に `WOLFSPDM_E_BAD_STATE` を返します。それらのサンプルを実行する前に、`spdm_ctrl` でロックを解除してください。 + +サポートされるハードウェア: + +- Nuvoton NPCT75x: アイデンティティ鍵モード (ECDHE P-384) +- Nations NS350: アイデンティティ鍵モードおよび PSK モード + +### アイデンティティ鍵モード (Nuvoton と Nations) + +``` +Host TPM (Nuvoton NPCT75x / Nations NS350) + | | + |--- GET_VERSION ------------------>| (negotiate SPDM version) + |<-- VERSION -----------------------| + | | + |--- GET_CAPABILITIES ------------->| (Nations only) + |<-- CAPABILITIES ------------------| + |--- NEGOTIATE_ALGORITHMS --------->| (Nations only) + |<-- ALGORITHMS --------------------| + | | + |--- GET_PUBK --------------------->| (get TPM's P-384 identity key) + |<-- GET_PUBK response -------------| + | | + |--- KEY_EXCHANGE ----------------->| (ECDHE P-384 key agreement) + |<-- KEY_EXCHANGE_RSP --------------| (+ ECDSA signature and HMAC) + | | + | --- Handshake keys derived --- | + | | + |=== GIVE_PUB =====================>| (encrypted: host's P-384 key) + |<== GIVE_PUB response =============| + | | + |=== FINISH =======================>| (encrypted: signature + HMAC) + |<== FINISH_RSP ====================| + | | + | --- App data keys derived --- | + | | + |=== TPM2_CMD (AES-256-GCM) =======>| (every command encrypted) + |<== TPM2_RSP (AES-256-GCM) ========| +``` + +Nuvoton アダプターは GET_CAPABILITIES と NEGOTIATE_ALGORITHMS を省略します。Nations アダプターは VERSION の後にこれらを送信します。ハンドシェイクでは、鍵合意に ECDH P-384、署名に ECDSA P-384、鍵導出に HKDF-SHA384、認証に HMAC-SHA384 を使用します。PSK の鍵合意には P-384 は含まれません。ハンドシェイク後、すべての TPM コマンドは SPDM の `VENDOR_DEFINED_REQUEST("TPM2_CMD")` メッセージでラップされ、AES-256-GCM で暗号化されます。TPM のレスポンスは `VENDOR_DEFINED_RESPONSE` メッセージで返されます。セキュアレコードは、リクエストとレスポンスそれぞれに独立した 64 ビットのシーケンス番号を持ち、リプレイ攻撃を防ぐためにメッセージごとにインクリメントされます。 + +### PSK モード (Nations のみ) + +PSK モードは、ECDHE 鍵交換を対称の事前共有鍵に置き換えます。データ転送には同じ AES-256-GCM 暗号化が使用されます。リクエスターは GET_VERSION から直接 PSK_EXCHANGE に進み、このフローではケイパビリティとアルゴリズムのネゴシエーションは不要です。 + +``` +Host TPM (Nations NS350) + | | + |--- GET_VERSION ------------------>| (negotiate SPDM version) + |<-- VERSION -----------------------| + | | + |--- PSK_EXCHANGE ----------------->| (session key from PSK) + |<-- PSK_EXCHANGE_RSP --------------| (+ HMAC proof) + | | + | --- Handshake keys derived --- | (Salt_0 = 0xFF * H for PSK mode) + | | + |=== PSK_FINISH ===================>| (encrypted: requester HMAC) + |<== PSK_FINISH_RSP ================| + | | + | --- App data keys derived --- | + | | + |=== TPM2_CMD (AES-256-GCM) =======>| (every command encrypted) + |<== TPM2_RSP (AES-256-GCM) ========| +``` + +NS350 では、PSK モードとアイデンティティ鍵モードは排他的です。アイデンティティ鍵は工場出荷時にプロビジョニングされており、PSK を使用する前に解除する必要があります。PSK ライフサイクルのセクションを参照してください。 + +### SPDM 専用モード (暗号化バスの強制) + +SPDM 専用モードは、TPM コマンドを暗号化された SPDM チャネル経由に強制します。唯一の例外は平文の `TPM2_GetCapability` で、これはサポート対象のシリコンに合わせて、ロック中も fwTPM レスポンダーが意図的に許可しています。両ベンダーが SPDM 専用モードをサポートしています。典型的なライフサイクルは次のとおりです。 + +``` +1. Enable SPDM (one-time, persists across resets) +2. Connect (handshake, derives session keys) +3. Lock SPDM-only (TPM rejects cleartext commands except GetCapability) +4. Reset (TPM enters SPDM-only enforcement) +5. Initialize with the trusted key or PSK and run commands (all encrypted) +6. Unlock (connect + unlock in one session) +7. Reset (TPM back to normal cleartext mode) +``` + +アプリケーションが `wolfTPM2_InitWithSpdmKey()` を通じてレスポンダー鍵を提供した後、wolfTPM はレスポンダーを認証して暗号化セッションを確立します。起動プローブが成功した場合、すでに初期化済みであった場合、または想定される `TPM_RC_DISABLED` の結果となった場合は、処理を継続します。ファームウェアアップグレード状態などのその他の起動失敗は、SPDM 接続が試みられる前に返されます。詳細は Auto-SPDM のセクションを参照してください。 + +リセット方法はベンダーによって異なります。 + +- Nuvoton: GPIO 4 によるリセット (TPM リセットピン制御を参照) +- Nations: テストハーネスで使用される NS350 のドーターボードでは GPIO 4 が TPM_RST に配線されているため、同じ GPIO リセットが適用されます。お使いのボードで配線されていない場合は、完全な電源の入れ直しを行ってください。 + +## ビルド + +### 1. wolfSPDM サブモジュールを含めてクローンする + +クイックスタートのセクションを参照してください。SPDM は `lib/wolfSPDM` サブモジュールからビルドされるため、wolfTPM を再帰的にクローンするか、既存のチェックアウトで `git submodule update --init lib/wolfSPDM` を実行してください。 + +### 2. wolfSSL + +Nuvoton と Nations は同じ wolfSSL フラグを使用します。これらは SPDM Algorithm Set B のための暗号処理を提供します。wolfSSL 5.8.0 以降が必要で、wolfSPDM の configure チェックがこれを強制します。このチェックは `lib/wolfSPDM` サブモジュール内にあります。 + +```sh +cd ../wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-ecc --enable-sha384 \ + --enable-aesgcm --enable-hkdf --enable-sp +make +sudo make install && sudo ldconfig +cd - # back to the wolfTPM checkout +``` + +### 3. wolfTPM + +```sh +./autogen.sh +./configure --enable-spdm --enable-nuvoton # Nuvoton +# or +./configure --enable-spdm --enable-nations # Nations +make +``` + +`--enable-spdm` に加えて、少なくとも 1 つのハンドシェイクモードを指定してビルドします。TCG の生の公開鍵ハンドシェイクには `--enable-tcg`、PSK ハンドシェイクには `--enable-psk` です。ベンダー固有のワイヤフォーマットアダプター (`--enable-nuvoton`、`--enable-nations`) は任意です。 + +### wolfTPM の SPDM プロファイル + +`--enable-spdm` は `WOLFTPM_SPDM` を定義し、これにより wolfSPDM の `WOLFSPDM_PROFILE_TPM` が自動的に選択されます。TPM のバインディングは TCG SPDM Binding であるため、このプロファイルは TCG に特化した軽量ビルドです。以下の汎用 DSP0274 リクエスター機能は、自動的にコンパイルから除外されます。Nations アダプターは、`spdm_tcg.c` 内にある独自の TCG 固有の GET_CAPABILITIES および NEGOTIATE_ALGORITHMS の実装を引き続き使用します。 + +- DMTF 標準のリクエスター機能: `GET_CAPABILITIES`、`NEGOTIATE_ALGORITHMS`、`GET_DIGESTS`、`GET_CERTIFICATE`、および証明書チェーンの検証 +- 測定 (measurements)、チャレンジ、チャンキング (これらは証明書フローに付随します) +- ハートビートと鍵更新 +- MCTP アプリケーションデータ API (セキュアメッセージは TCG の 16 バイトパディングを使用します) + +wolfTPM の `configure` には `--disable-mctp` オプションはなく、追加しようとしてもいけません。軽量プロファイルは `--enable-spdm` で自動的に適用され、wolfSPDM の下流 CI は、上記の標準リクエスターのシンボルが `libwolftpm` に存在しないことを検証します。 + +このプロファイルは `WOLFSPDM_NO_MCTP` を定義しないため、MCTP のセキュアメッセージフレーミングはコンパイルされたままですが、TCG 専用の TPM がこれを使用することはありません。wolfSPDM を単体で `--disable-mctp` (`--enable-tcg` が必要) を付けてビルドすると、純粋な TCG リクエスター向けにその経路がさらに除去されます。このフラグは wolfSPDM 自身の `configure` のものであり、wolfTPM のものではありません。 + +### configure オプション + +| オプション | 説明 | +|--------|-------------| +| `--enable-spdm` | SPDM サポートを有効化 (必須) | +| `--enable-tcg` | TCG SPDM Binding 仕様のハンドシェイク (fwtpm/nuvoton/nations が有効な場合は自動) | +| `--enable-psk` | DSP0274 PSK ハンドシェイク (`--enable-nations` で自動、`--enable-tcg` が必要) | +| `--enable-fwtpm` | SPDM レスポンダー付きの fwtpm_server をビルド (`--enable-spdm` とハンドシェイクモードが必要、シリコン不要) | +| `--enable-nuvoton` | Nuvoton TPM ハードウェアサポートを有効化 (`--enable-tcg` を自動的に有効化) | +| `--enable-nations` | Nations NS350 ハードウェアサポートを有効化 (`--enable-tcg --enable-psk` を自動的に有効化) | +| `--enable-debug` | 詳細な SPDM トレース付きのデバッグ出力 | +| `--enable-smallstack` | SPDM コンテキストと SPDM リクエストおよびレスポンスのバッファをヒープに確保し、公開メッセージサイズの上限を引き下げます (デフォルト: 呼び出し側が所有するインラインコンテキスト、約 32 KB) | + +`configure` は、次の互換性のない組み合わせを拒否します。 + +- `--enable-nuvoton --disable-tcg` (Nuvoton は TCG SPDM Binding を使用します) +- `--enable-nations --disable-tcg` または `--enable-nations --disable-psk` +- `--enable-psk --disable-tcg` (PSK は TCG のフレーミング上で動作します) + +### fwTPM SPDM レスポンダー (シリコン不要) + +`fwtpm_server` には SPDM 1.3 レスポンダーが含まれており、実際の Nuvoton および Nations のデバイスが使用するのと同じハンドシェイクを駆動します。これにより、実ハードウェアなしで CI 上で TCG と PSK のスタック全体を検証できます。 + +ソケットレスポンダーを有効にしてビルドします。 + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-spdm --enable-tcg --enable-psk --enable-nuvoton --enable-nations +make +``` + +その後、SPDM モードのいずれかで起動します。fwTPM レスポンダーは、空でない最大 64 バイト (16 進数 128 文字) の PSK を受け付けます。64 バイトちょうどという要件は Nations ハードウェアのプロビジョニングに適用されるものであり、このレスポンダーには適用されません。以下の値は `spdm_test.sh` で使用されるテスト用 PSK です。 + +```sh +SPDM_PSK=dbc2192291d807742441b963f6712841f7697e2e39c45931f3abc53658c8b9338bd3561cab5d90cf9e493295bb5bd6b2c455e0fd19392e0ce4f3433cbcfc7047 +./src/fwtpm/fwtpm_server --spdm-tcg # TCG raw public key handshake +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" # PSK handshake +``` + +手動で PSK をテストする場合は、同じ `SPDM_PSK` の値をリクエスターに渡します。たとえば `spdm_ctrl --psk "$SPDM_PSK"` のようにします。 + +エンドツーエンドでテストします。 + +```sh +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-tcg +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-psk +``` + +レスポンダーのモードとエンドツーエンドのテストスクリプトについては、[fwtpm/spdm.md](fwtpm/spdm.md) を参照してください。 + +### デュアルベンダービルドでのベンダー選択 + +`--enable-nuvoton` と `--enable-nations` の両方がコンパイルされている場合、`spdm_ctrl` は任意のランタイムフラグでベンダーアダプターを選択します。 + +```sh +./examples/spdm/spdm_ctrl --vendor=nuvoton \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect +./examples/spdm/spdm_ctrl --vendor=nations \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +単一ベンダーのビルドは、バイナリにコンパイルされたアダプターのみを受け付け、利用できない `--vendor=` の値を拒否します。 + +## 使い方と制御コマンド + +### 初回セットアップ + +管理コマンド (有効化、無効化、アイデンティティ鍵の設定と解除) は空のプラットフォーム認可を使用し、`--tpm-clear` はデフォルトの空のロックアウト認可を使用します。`spdm_ctrl` には異なる階層シークレットを指定するオプションがないため、これらのコマンドは、空でない認可でプロビジョニングされた TPM では動作しません。 + +Nuvoton: + +```sh +# Enable SPDM on the TPM (persists across resets) +./examples/spdm/spdm_ctrl --enable + +# Reset the TPM (see TPM reset pin control) + +# Verify SPDM is enabled +./examples/spdm/spdm_ctrl --status +``` + +Nations: アイデンティティ鍵モードが工場出荷時のデフォルトであるため、セットアップは不要です。以前に解除した場合は、次のコマンドで復元します。 + +```sh +./examples/spdm/spdm_ctrl --identity-key-set +``` + +### セッションの確立 + +アイデンティティ鍵モード (両ベンダー): + +```sh +# Establish SPDM session (VERSION, GET_PUBK, KEY_EXCHANGE, GIVE_PUB, FINISH; +# Nations also sends GET_CAPABILITIES and NEGOTIATE_ALGORITHMS) +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect + +# Query SPDM status +./examples/spdm/spdm_ctrl --status +``` + +`--responder-pubkey` は、信頼できる生の P-384 X||Y 点を 192 文字の 16 進数で受け取ります。デバイスのプロビジョニング記録、または認証されたその他の製造元チャネルから入手してください。ここでの例では、これらの値をシェル変数に読み込んでいます。たとえば `RESPONDER_PUBKEY="$(cat responder_pubkey.hex)"` のようにします。レスポンダーの公開鍵はシークレットではありませんが、トラストアンカーであるため、改ざんから保護してください。PSK と ClearAuth はシークレットです。これらのファイルは、所有者のみが読み取れるようにしてください (`chmod 600`)。シークレットをコマンドライン引数として渡すと (たとえば `--psk`)、`/proc//cmdline` を通じてホスト上の他のユーザーに露出します。これらのサンプル CLI はデモ用ツールであるため、共有マシンでは実際のシークレットを適切に取り扱ってください。 + +!!! warning + `--get-pubkey` は認証なしの探索であり、それ単体で信頼を確立するために使用してはいけません。 + +PSK モード (Nations) では、先に PSK をプロビジョニングする必要があります。PSK ライフサイクルのセクションを参照してください。以下のコマンドでは、`PSK_HEX` は 128 文字の 16 進数で表した 64 バイトの PSK を、`CLEARAUTH_HEX` は 64 文字の 16 進数で表した 32 バイトの ClearAuth を保持します。いずれも、自分だけが読み取れるファイルから読み込みます。 + +```sh +# Establish PSK session (VERSION, PSK_EXCHANGE, PSK_FINISH) +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" +``` + +### SPDM 専用モードのロックとロック解除 + +ロックにはアクティブな SPDM セッションが必要です。ロック後、強制を有効にするにはリセットが必要です。 + +Nuvoton (アイデンティティ鍵): + +```sh +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM (see TPM reset pin control) + +# Unlock +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM again +``` + +Nations (アイデンティティ鍵): + +```sh +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM (GPIO 4 on the tested board, otherwise a power cycle) + +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM again +``` + +Nations (PSK モード): + +```sh +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" --lock +# Reset the TPM + +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" --unlock +# Reset the TPM again +``` + +### PSK ライフサイクル (Nations) + +NS350 では、PSK モードとアイデンティティ鍵モードは排他的です。アイデンティティ鍵はデフォルトでプロビジョニングされており、PSK を使用する前に解除する必要があります。 + +```sh +# 1. Unset identity key (enables PSK mode) +./examples/spdm/spdm_ctrl --identity-key-unset + +# 2. Provision PSK (64-byte PSK + 32-byte ClearAuth) +# The demo computes SHA-384(ClearAuth) and sends PSK(64)+Digest(48) = 112 bytes +./examples/spdm/spdm_ctrl --psk-set "$PSK_HEX" "$CLEARAUTH_HEX" + +# 3. Establish PSK session +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" + +# 4. Clear PSK (sends raw 32-byte ClearAuth; TPM verifies SHA-384 internally) +./examples/spdm/spdm_ctrl --psk-clear "$CLEARAUTH_HEX" + +# 5. Restore identity key (factory default) +./examples/spdm/spdm_ctrl --identity-key-set +``` + +!!! warning + ClearAuth は正確に 32 バイトでなければなりません。PSK_SET はその SHA-384 ダイジェスト (48 バイト) を保存します。PSK_CLEAR は生の 32 バイトを送信し、TPM が検証のために SHA-384 を計算します。`spdm_ctrl` は、長さが誤った ClearAuth を拒否します。 + +### コマンドリファレンス + +`spdm_ctrl` のすべてのオプション (受け付けられるオプションは、コンパイルされているベンダーアダプターによって異なります): + +| オプション | ベンダー | 説明 | +|--------|--------|-------------| +| `--enable` | Nuvoton | NTC2_PreConfig 経由で SPDM を有効化 (一度だけ、永続、リセットが必要) | +| `--disable` | Nuvoton | NTC2_PreConfig 経由で SPDM を無効化 (リセットが必要) | +| `--identity-key-set` | Nations | SPDM アイデンティティ鍵をプロビジョニング (工場出荷時のデフォルト) | +| `--identity-key-unset` | Nations | プロビジョニング済みのアイデンティティ鍵を削除 (PSK の前に必要) | +| `--vendor=nuvoton\|nations` | 両方 | アイデンティティ/ベンダーアダプターを明示的に選択 | +| `--get-pubkey` | 両方 | 認証せずに TPM のアイデンティティ鍵を探索 | +| `--responder-pubkey` *hex* | 両方 | 信頼できる生の P-384 X\|\|Y レスポンダー鍵を固定 (192 文字の 16 進数) | +| `--connect` | 両方 | アイデンティティ鍵 SPDM セッションを確立 (ECDH P-384 ハンドシェイク) | +| `--caps` | 両方 | 現在のトランスポート経由で TPM のケイパビリティを読み取る | +| `--status` | 両方 | SPDM の状態を照会 | +| `--session-info` | 両方 | TPM から見た SPDM セッションを表示 (`TPM_CAP_SPDM_SESSION_INFO`) | +| `--policy-nv` | 両方 | `TPM2_PolicyTransportSPDM` で保護された NV インデックスを定義し、セッション経由で書き込みと読み取りを行う | +| `--lock` | 両方 | SPDM 専用モードをロック (アクティブなセッションが必要: `--connect`、または Nations PSK では `--psk`) | +| `--unlock` | 両方 | SPDM 専用モードのロックを解除 (アクティブなセッションが必要: `--connect`、または Nations PSK では `--psk`) | +| `--psk` *hex* | Nations | PSK セッションを確立 (64 バイトの PSK) | +| `--psk-set` *psk* *clearauth* | Nations | PSK をプロビジョニング (64 バイトの PSK、32 バイトの ClearAuth) | +| `--psk-clear` *clearauth* | Nations | PSK をクリア (32 バイトの ClearAuth) | +| `--caps184` | Nations | TPM 184 ベンダープロパティと SPDM セッション情報を照会 | +| `--tpm-clear` | 両方 | 現在のトランスポート経由で `TPM2_Clear` を送信 (`TPM_RH_LOCKOUT` で認可、デフォルトは空のロックアウト認可) | + +### 使用例 + +```sh +# One-time setup: enable SPDM + reset TPM +./examples/spdm/spdm_ctrl --enable +# Reset the TPM (see "TPM reset pin control" below) + +# Query SPDM status +./examples/spdm/spdm_ctrl --status + +# Discover TPM identity key (unauthenticated; do not use as its own trust source) +./examples/spdm/spdm_ctrl --get-pubkey + +# Establish SPDM session with a key from trusted provisioning records +./examples/spdm/spdm_ctrl \ + --vendor=nuvoton --responder-pubkey "$RESPONDER_PUBKEY" --connect + +# Lock SPDM-only mode (connect + lock in one session) +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM + +# Unlock SPDM-only mode +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM +``` + +### nv_bind + +`nv_bind` サンプルは、`--policy-nv` の考え方に焦点を当てた、自己完結型のバージョンです。`authPolicy` が `TPM2_PolicyTransportSPDM` である NV インデックスをプロビジョニングし、SPDM-PSK セッション経由でシークレットを保存したうえで、通常の (SPDM ではない) 接続経由での同一の読み取りが `TPM_RC_CHANNEL` で拒否されることを示します。 + +レスポンダーを別のターミナルで起動してリッスンさせたままにし、別のターミナルから `nv_bind` を実行します。`--clear` は fwTPM の NV 状態ファイルを削除するため、使い捨てのインスタンスを使用してください。 + +```sh +# terminal 1: responder +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" --clear +``` + +```sh +# terminal 2: once the responder is listening +./examples/spdm/nv_bind --psk "$SPDM_PSK" +``` + +fwTPM は起動のたびに新しい SPDM アイデンティティ鍵を生成するため、fwTPM 上では `tpmKeyName` にバインドされたポリシーはそのサーバーの存続期間中のみ有効です。ハードウェア TPM は永続的なアイデンティティ鍵を保持しているため、そのようなバインドは持続的です。PSK セッションでは、非対称鍵による認証が行われないため、空の鍵名が報告されます。 + +### TPM リセットピン制御 + +SPDM の有効化/無効化および SPDM 専用モードの変更を反映するには、TPM のリセットが必要です。ホストから制御可能なリセットピンを使うのが最も簡単ですが、TPM の電源レールをサイクルさせる方法でも可能です。 + +!!! warning + カスタムハードウェア設計では、TPM のリセットピンをホストが制御できる GPIO に配線するか、TPM の電源レールを切り替え可能にしてください。TPM をリセットまたは電源サイクルする手段がない場合、SPDM モードの変更を適用できず、SPDM 専用モードからの回復もできません。 + +リセットラインはボードごとに異なります。Raspberry Pi では、Nuvoton は GPIO4 を、ST33KTPM は GPIO24 (ピン 18) を使用します。テスト済みの NS350 ドーターボードでも GPIO4 が TPM_RST に配線されています。切り替える前に配線を確認してください。 + +libgpiod 1.x では、`gpioset` はラインを駆動し、デフォルトモードでは終了時にリクエストを解放します (チップは位置引数です)。以下のパルスは、ボードのプルレジスタが保持している間だけ各レベルを保持します。`spdm_test.sh` は、テスト済みのボードでこの動作に依存しています。 + +```sh +gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 +``` + +libgpiod 2.x では、チップは `--chip` で指定し、`gpioset` はプロセスが実行されている間だけラインを保持します。単純な `&&` の連鎖では、各 `gpioset` が終了するたびにラインが解放されます。一方、`--daemonize` はその逆で、デーモンが終了されるまでリクエストとラインのレベルを保持し続けるため、リセットピンが確保されたままになり、後続のリセットを妨げる可能性があります。どちらも、きれいな有限のパルスにはなりません。タイミングを指定したパルスには、`gpioset --toggle` を使用してください (gpioset のマニュアルを参照)。1 つのプロセスがラインを Low にし、待機し、High にし、待機してから終了します。解放後のレベルはプルレジスタに依存するため、事前にお使いのボードでこの手順を確認してください。ST33 の場合は、4 の代わりにライン 24 を使用します。繰り返し可能な自動化には、後述の wolfTPM のリセット HAL を使用することを推奨します。 + +wolfTPM は、コードからリセットを駆動することもできます。`--enable-hal-reset` を付けてビルドし、`TPM2_IoCb_Reset(ctx, userCtx)` を呼び出します。この関数は `TPM2_CTX*` と `void*` を受け取ります。デフォルトのラインは、ST33 が GPIO24、Nuvoton が GPIO4 です。Nations のビルドも、ライン 4 を明示的に指定しない限り、デフォルトは GPIO24 です。ソースツリーの `hal/README.md` を参照してください。 + +## TCG SPDM ベンダーコマンド + +Nuvoton と Nations の TPM は、どちらも TCG の "TPM Communication over SPDM Secure Session" バインディングを実装していますが、Nuvoton のフローでは、Nations のフローが行う GET_CAPABILITIES と NEGOTIATE_ALGORITHMS のネゴシエーションが省略されます (アイデンティティ鍵モードを参照)。このバインディングは、各メッセージを SPDM の `VENDOR_DEFINED_REQUEST` (リクエストコード `0xFE`) として運び、`VENDOR_DEFINED_RESPONSE` (レスポンスコード `0x7E`) で応答します。`StandardID=0x0001` (TCG) が使用されます。メッセージ内のベンダーコード (VdCode) は 8 バイトの ASCII 文字列です。 + +公開されている TCG の表では、`GET_PUBK`、`GIVE_PUB`、`TPM2_CMD`、および任意のロカリティ固有の `TPM2CMD0` から `TPM2CMD4` までの値が定義されています。`GET_STS_`、`SPDMONLY`、`PSK_SET_`、`PSK_CLR_` は実装またはベンダーによる拡張であり、TCG が定義したコマンドではありません。2 つのベンダーアダプターにおけるベンダー拡張の正確なワイヤ形式の詳細は `lib/wolfSPDM` サブモジュール内にあります。 + +| VdCode | コマンド | 定義元 | ベンダー | 説明 | +|--------|---------|------------|--------|-------------| +| `GET_PUBK` | Get Public Key | TCG | 両方 | TPM の SPDM-Identity P-384 公開鍵を取得 | +| `GIVE_PUB` | Give Public Key | TCG | 両方 | ホストの P-384 公開鍵を TPM に送信 | +| `TPM2_CMD` | TPM Command | TCG | 両方 | TPM コマンドを SPDM セキュアメッセージでラップ | +| `GET_STS_` | Get Status | ベンダー拡張 | 両方 | SPDM の状態を照会 | +| `SPDMONLY` | SPDM-Only Mode | ベンダー拡張 | 両方 | SPDM 専用の強制をロック/ロック解除 | +| `PSK_SET_` | PSK Set | ベンダー拡張 | Nations | 事前共有鍵をプロビジョニング (64 バイトの PSK + SHA-384 ダイジェスト) | +| `PSK_CLR_` | PSK Clear | ベンダー拡張 | Nations | プロビジョニング済みの PSK をクリア (ClearAuth が必要) | + +## ベンダー固有の事項 + +### Nuvoton NPCT75x + +- 有効化/無効化: SPDM は `NTC2_PreConfig` ベンダーコマンド (`--enable` / `--disable`) で有効化されます。これはリセットをまたいで永続します。 +- GPIO リセット: Nuvoton のドーターボードでは GPIO 4 が TPM_RST に配線されています。GPIO リセットにより、残存している SPDM 状態がクリアされます。コマンドについては TPM リセットピン制御を参照してください。 + +### Nations NS350 + +- モード切り替え: アイデンティティ鍵モードと PSK モードは排他的です。アイデンティティ鍵は工場出荷時にプロビジョニングされています。PSK をプロビジョニングする前に `--identity-key-unset` を使用し、復元するには `--identity-key-set` を使用します。 +- リセット: ハードウェアでテスト済みのハーネス (`spdm_test.sh`) は、NS350 のドーターボードでは GPIO 4 が TPM_RST に配線されているものとして扱い、Nations の状態を正規化する際にこれを使用します。アイデンティティ鍵と PSK は NV に保存され、リセット後も保持されます。お使いのボードでこのラインが配線されていない場合は、完全な電源の入れ直しが必要です。`sudo reboot` では 3.3V レールが通電したままであるためです。 +- ケイパビリティの照会: SPDM セッション情報を含む TPM 184 ベンダープロパティを照会するには、`--caps184` を使用します。 +- ClearAuth: 正確に 32 バイトでなければなりません。`PSK_SET` はその SHA-384 ダイジェスト (48 バイト) を保存します。`PSK_CLEAR` は生の 32 バイトを送信し、TPM が検証のために SHA-384 を計算します。 + +!!! note + 一部の NS350 ファームウェアバージョンでは、鍵が存在していても `--status` が "Identity Key: not provisioned" と報告することがあります。決定的なテストは `--connect` コマンドです。ECDHE ハンドシェイクが成功すれば、アイデンティティ鍵はプロビジョニングされています。 + +Nations の PSK 操作は、ベンダー固有のエラーコードを返すことがあります。たとえば、PSK がすでにプロビジョニング済み、PSK がプロビジョニングされていない、SPDM セッションの内部エラー、ClearAuth が保存されたダイジェストと一致しない、などです。正確な数値はファームウェア固有であり、Nations の公開資料やソースツリーでは定義されていません。ここに固定の表を載せるのではなく、お使いのファームウェアリビジョンに対応する Nations の統合ガイドから入手してください。 + +### Auto-SPDM + +アイデンティティモードでは信頼できるレスポンダー鍵を指定して `wolfTPM2_InitWithSpdmKey()` を、PSK モードではプロビジョニング済みの PSK を指定して `wolfTPM2_InitWithSpdmPsk()` を呼び出します。どちらのエントリーポイントも、すでに SPDM 専用モードでロックされている TPM から回復します。アイデンティティモードの初期化手順は次のとおりです。 + +1. `TPM2_Startup` が、TPM がすでに SPDM 専用モードであるかどうかを調べます。 +2. 呼び出し側が提供したレスポンダー鍵が、トラストアンカーとしてインストールされます。 +3. 検出されたレスポンダー鍵が、その信頼された鍵と比較されます。 +4. SPDM セッションが常に確立されます (P-384 鍵生成とハンドシェイク)。 +5. プローブが `TPM_RC_DISABLED` を返した場合、`TPM2_Startup` が安全にリトライされます。 +6. 以降のすべてのコマンドは、SPDM の暗号化チャネルを通ります。 + +デュアルベンダービルドでは、`wolfTPM2_InitWithSpdmKey()` は TPM の DID/VID からアイデンティティアダプターを選択します。DID/VID を公開しないトランスポートでは、`WOLFSPDM_MODE_NUVOTON` または `WOLFSPDM_MODE_NATIONS` を指定して `wolfTPM2_InitWithSpdmKey_ex()` を呼び出す必要があります。自動モードは、推測せずにフェイルクローズします。 + +資格情報なしの `wolfTPM2_Init()` は、いずれかの SPDM 専用モードを検出するとフェイルクローズします。即時のセキュアチャネルを必要としない通常モードの TPM では、アイデンティティモードのアプリケーションは代わりに `wolfTPM2_SpdmInit()`、`wolfTPM2_SpdmSetResponderPubKey()`、続いてベンダー固有の接続関数を呼び出すことができます。 + +`TPM2_SendCommand` (認証なしのコマンド) と `TPM2_SendCommandAuth` (PCR 操作、鍵作成、署名などの認証セッション付きコマンド) の両方が、セッションがアクティブな場合にインターセプトされ、SPDM 経由でルーティングされます。 + +### メモリモード + +- デフォルト: ヒープ割り当てなし。SPDM コンテキストは約 32 KB の、呼び出し側が所有するインラインコンテキストです。必ずしも静的記憶域期間のストレージではなく、呼び出し側が配置した場所に存在します。 +- スモールスタック (`--enable-smallstack`): wolfSPDM コンテキストと SPDM リクエストおよびレスポンスのバッファは `XMALLOC` で確保されます。TPM レスポンスバッファや TIS I/O バッファなど、一部のコマンドごとのバッファはスタックに残ります。また、3 つの公開メッセージサイズの上限が引き下げられるため、サイズが大きすぎるコマンドやレスポンスは `BUFFER_E` を返すことがあります。スタックが小さいプラットフォームで有用です。ペイロードのサイズは引き下げられた上限に合わせてください。 + +`wolfSPDM_New()` は、wolfSPDM が `WOLFSPDM_DYNAMIC_MEMORY` 付きでビルドされた場合にのみ存在します。それ以外の場合は、呼び出し側が提供するストレージに対して `wolfSPDM_InitStatic()` または `wolfSPDM_Init()` を使用してください。 + +## wolfSPDM API + +| 関数 | 説明 | +|----------|-------------| +| `wolfSPDM_InitStatic()` | 呼び出し側が提供するバッファ内でコンテキストを初期化 (静的モード) | +| `wolfSPDM_New()` | ヒープ上にコンテキストを確保して初期化 (`WOLFSPDM_DYNAMIC_MEMORY` の場合のみ) | +| `wolfSPDM_Init()` | 事前に確保されたコンテキストを初期化 | +| `wolfSPDM_Free()` | コンテキストを解放 (リソースを解放し、動的な場合のみヒープを解放) | +| `wolfSPDM_GetCtxSize()` | 実行時に `sizeof(WOLFSPDM_CTX)` を返す | +| `wolfSPDM_SetIO()` | トランスポート I/O コールバックを設定 | +| `wolfSPDM_SetResponderPubKey()` | 信頼できるレスポンダーの P-384 鍵を固定 (アイデンティティモード) | +| `wolfSPDM_SetPSK()` | 事前共有鍵を設定 (PSK モード) | +| `wolfSPDM_SetMode()` | ベンダー/ハンドシェイクモードを選択 | +| `wolfSPDM_SetRequesterKeyPair()` | GIVE_PUB と FINISH に使用するホストの P-384 鍵ペアを設定 | +| `wolfSPDM_SetDebug()` | デバッグ出力の有効化/無効化 | +| `wolfSPDM_Connect()` | SPDM ハンドシェイク全体 | +| `wolfSPDM_IsConnected()` | セッション状態を確認 | +| `wolfSPDM_Disconnect()` | セッションを終了 | +| `wolfSPDM_SecuredExchange()` | 暗号化/送信/受信/復号を 1 回の呼び出しで実行 | + +## トラブルシューティング + +### セッションの中断後にハンドシェイクが失敗する + +TPM 上に SPDM の状態が残っていると、次のハンドシェイクが失敗することがあります。TPM をリセットしてください。 + +- Nuvoton: Nuvoton のドーターボードでは GPIO 4 が TPM_RST に配線されているため、GPIO リセットで状態がクリアされます。コマンドについては TPM リセットピン制御を参照してください。 +- Nations NS350: テスト済みのドーターボードでも GPIO 4 が TPM_RST に配線されているため、同じ GPIO リセットが適用されます。お使いのボードで配線されていない場合は、完全な電源の入れ直しを行ってください。3.3V レールが通電したままであるため、`sudo reboot` では不十分です。 + +### SPDM エラーコード + +| コード | 名前 | 説明 | +|------|------|-------------| +| 0x01 | InvalidRequest | メッセージ形式が不正 | +| 0x04 | UnexpectedRequest | メッセージの順序が不正 | +| 0x05 | Unspecified | 未指定のエラー | +| 0x06 | DecryptError | 復号または MAC 検証に失敗 | +| 0x07 | UnsupportedRequest | リクエストが未サポート、または形式が拒否された | +| 0x41 | MajorVersionMismatch | SPDM のメジャーバージョンの不一致 | + +## 標準 SPDM のサポート + +ツリー内の TPM プロファイルがカバーするのは、TCG SPDM バインディングのみです。DMTF の spdm-emu エミュレーターとのセッション、測定 (measurements)、チャレンジ認証、ハートビート、鍵更新を含む標準 SPDM プロトコルのサポートには、スタンドアロンの [wolfSPDM](https://github.com/wolfSSL/wolfSPDM) ライブラリを使用してください。これらの機能は wolfTPM の対象外です。 + +## 自動テスト + +`spdm_test.sh` は、SPDM のセットアップライフサイクル全体を実行します。 + +```sh +# Nuvoton (identity key, includes GPIO resets between tests) +SPDM_RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +export SPDM_RESPONDER_PUBKEY +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nuvoton + +# Nations (identity key; the harness also uses GPIO 4 to normalize state) +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations + +# Nations (PSK, full lifecycle: provision, connect, clear, restore) +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations-psk +``` + +アイデンティティモードのハードウェアでの実行には、信頼できるプロビジョニング元 (デバイスのプロビジョニング記録) から得た `SPDM_RESPONDER_PUBKEY` が必要です。PSK の実行ではこれを使用しません。一方、`fwtpm-tcg` テストは、テストハーネスが作成したオーナー専用のサーバーログから新しく生成された公開鍵を読み取り、同じ固定用インターフェースを通じて渡します。このローカルでのブートストラップは、ハードウェアのプロビジョニング手段ではありません。 + +SPDM をサポートするハードウェア TPM の本番利用については、support@wolfssl.com までお問い合わせください。 + +## 関連項目 + +- [fwtpm/spdm.md](fwtpm/spdm.md) +- [post-quantum.md](post-quantum.md) +- [FWTPM.md](fwtpm/overview.md) +- [DEVTPM.md](system-interfaces.md) diff --git a/docs/ja/stm32cube.md b/docs/ja/stm32cube.md new file mode 100644 index 00000000..05278722 --- /dev/null +++ b/docs/ja/stm32cube.md @@ -0,0 +1,27 @@ +# STM32CubeIDE + +wolfTPM は STM32 Cube Pack の `I-CUBE-wolfTPM.pack` として提供されており、https://www.wolfssl.com/files/ide/I-CUBE-wolfTPM.pack からダウンロードできます。このパックは、wolfCrypt ライブラリへの依存がオプションですが、推奨されています。ファイルは wolfTPM のソースツリー内の `IDE/STM32CUBE` にあります。 + +!!! note + このページは短く、後日拡充される予定です。 + +## セットアップ + +1. wolfSSL の STM32Cube ガイド https://github.com/wolfSSL/wolfssl/blob/master/IDE/STM32Cube/README.md に従って、ST プロジェクトに wolfCrypt ライブラリをセットアップします。wolfTPM のユニットテストを実行するには、エントリ関数の名前を `wolfCryptDemo` ではなく `wolfTPMTest` にします。 +2. wolfSSL パックと同じ方法で、CubeMX を使用して wolfTPM Cube Pack をインストールします。 +3. プロジェクトの `.ioc` ファイルを開き、`Software Packs` ドロップダウンメニューから `Select Components` をクリックします。`wolfTPM` パックを展開し、すべてのコンポーネントにチェックを入れます。 +4. `.ioc` ファイルの `Software Packs` 設定カテゴリで wolfTPM パックをクリックし、チェックボックスをオンにしてライブラリを有効にします。 +5. `Connectivity` カテゴリで、プロジェクトで使用する SPI を見つけて有効にします。 +6. `Software Packs` 設定カテゴリで wolfTPM パックを開き、`Enable wolfCrypt` パラメータを True に設定します。 +7. 変更を保存し、コード生成を確認するプロンプトには yes と答えます。 +8. プロジェクトをビルドし、ターゲット上でユニットテストを実行します。 + +## 注意事項 + +テスト出力を確認できるように、`printf` を UART にリダイレクトしてください。wolfSSL ガイドの [STM32 printf changes](https://github.com/wolfSSL/wolfssl/tree/master/IDE/STM32Cube#stm32-printf) を参照してください。 + +## 関連項目 + +- [Building](building.md): ベアメタルのビルドオプションについて +- [System Interfaces](system-interfaces.md): STM32H5 上での UART 経由 SWTPM の例について +- [Embedded Integrations](embedded-integrations.md) diff --git a/docs/ja/supported-hardware.md b/docs/ja/supported-hardware.md new file mode 100644 index 00000000..7ad6371d --- /dev/null +++ b/docs/ja/supported-hardware.md @@ -0,0 +1,199 @@ +# サポート対象ハードウェア + +wolfTPM は、単一の HAL I/O コールバックを通じて SPI または I2C 経由で TPM 2.0 パーツと通信するか、オペレーティングシステムのドライバー経由でシステム TPM と通信します。このページでは、wolfTPM が HAL バックエンドを備えているプラットフォーム、テスト済みのハードウェア、各パーツに対応する configure フラグ、ベンダーごとのビルド手順を示します。 + +## プラットフォーム + +ハードウェアのサンプルは、Linux の `spidev` インターフェースを使用して Raspberry Pi 上で実行されることが最も多くなっています。これはサンプルのプラットフォームであり、必須条件ではありません。Linux HAL はベンダーごとにデフォルトの SPI チップセレクトを選択します。Infineon のビルドは `/dev/spidev0.1` を使用し、Microchip、ST、Nuvoton、Nations Technologies、SEALSQ のビルドは `/dev/spidev0.0` を使用します。配線が異なる場合は、`TPM2_SPI_DEV_PATH` と `TPM2_SPI_DEV_CS` でデバイスを上書きしてください。 + +ハードウェアバス (SPI または I2C) とのインターフェースには、wolfTPM は単一の HAL コールバックを使用します。このコールバックは、`TPM2_Init` または `wolfTPM2_Init` の呼び出し時の初期化中に渡します。コールバックモデルについては [HAL IO Callback](hal-io-callback.md) を参照してください。 + +`hal` ディレクトリには、次の HAL 実装例が用意されています。 + +* Atmel ASF (`tpm_io_atmel.c`) +* Barebox (`tpm_io_barebox.c`) +* Espressif ESP-IDF (`tpm_io_espressif.c`) +* Firmware TPM (`tpm_io_fwtpm.c`) +* Infineon TriCore and PSoC/CyHAL (`tpm_io_infineon.c`) +* Linux SPI and I2C (`tpm_io_linux.c`) +* Memory-mapped I/O (`tpm_io_mmio.c`) +* Microchip Harmony (`tpm_io_microchip.c`) +* QNX (`tpm_io_qnx.c`) +* STM32 CubeMX (`tpm_io_st.c`) +* U-Boot (`tpm_io_uboot.c`) +* wolfHAL (`tpm_io_wolfhal.c`) +* Xilinx (`tpm_io_xilinx.c`) +* Zephyr (`tpm_io_zephyr.c`) + +拡張 I/O オプション (`--enable-advio` または `WOLFTPM_ADV_IO`) は、レジスタアドレスと読み書きフラグを I/O コールバックのパラメータとして追加します。これは I2C サポートに必須であり、`--enable-i2c` を指定すると有効になります。 + +## テスト済みハードウェア + +wolfTPM は次のハードウェアでテストされています。 + +* Infineon OPTIGA(TM) Trusted Platform Module 2.0 SLB9670 (SPI)、SLB9672 (SPI)、SLB9673 (I2C)。 + * [LetsTrust](https://letstrust.de) は TPM 開発ボードのベンダーです。 +* STMicroelectronics ST33KTPM2XSPI、ST33KTPM2I、ST33TPHF2XSPI (SPI)、ST33TPHF2XI2C (I2C)。 +* Microchip ATTPM20 モジュール。 +* Nuvoton NPCT650 および NPCT750 TPM 2.0 モジュール。 +* Nations Technologies Z32H330 および NS350 TPM 2.0 モジュール。 +* SEALSQ QVault TPM 2.0 モジュール (SPI、ポスト量子 ML-DSA および ML-KEM)。 +* NVIDIA Jetson Orin (Tegra234) ファームウェア TPM: OP-TEE トラステッドアプリケーションとして動作する TPM 2.0 で、バスではなく Linux カーネルドライバー経由でアクセスします。[System Interfaces](system-interfaces.md) を参照してください。 + +ファームウェアアップデータは ST33KTPM2A ファームウェアラインも認識しますが、このパーツはテスト済みリストには含まれていません。 + +デバイスの識別情報は 2 段階で出力されます。バスに直接接続している場合、まず TIS レジスタから読み取った `TPM2: Caps ... Did ... Vid ... Rid` の行が出力されます。続いて `Mfg ...` の行が、製造元、ベンダー文字列、ファームウェアバージョン、認証フラグを報告します。ファームウェア TPM には TIS レジスタがないため、2 行目のみが出力されます。テスト済みの各モジュールの出力例については [TPM 2.0 Overview](tpm2-overview.md) を参照してください。 + +## サポートされるパーツ + +| Vendor | Part(s) | Bus | configure flag | Notes | +| ------ | ------- | --- | -------------- | ----- | +| Infineon | SLB9670 | SPI | `--enable-infineon=slb9670` | ライブラリのデフォルト SPI クロックは 43 MHz です。AES のキーサイズは 128 ビットに制限されます。 | +| Infineon | SLB9672 | SPI | `--enable-infineon` | SPI のデフォルトです。ライブラリのデフォルト SPI クロックは 33 MHz です。ファームウェアアップグレードをサポートします。 | +| Infineon | SLB9673 | I2C | `--enable-infineon=slb9673 --enable-i2c --enable-advio` | I2C 専用のため、SPI クロックは適用されません。 | +| STMicroelectronics | ST33KTPM2XSPI, ST33TPHF2XSPI | SPI | `--enable-st33` | ライブラリのデフォルト SPI クロックは 33 MHz です。ウェイトステートが必要です。 | +| STMicroelectronics | ST33KTPM2I, ST33TPHF2XI2C | I2C | `--enable-st33 --enable-i2c` | ウェイトステートが必要です。ファームウェアアップグレードのサポートはデフォルトで有効です。 | +| Microchip | ATTPM20 | SPI | `--enable-microchip` | ライブラリのデフォルト SPI クロックは 33 MHz です。ウェイトステートが必要です。 | +| Nuvoton | NPCT650, NPCT750 | SPI | `--enable-nuvoton` | ライブラリのデフォルト SPI クロックは 43 MHz です。ウェイトステートが必要です。 | +| Nations Technologies | Z32H330, NS350 | SPI | `--enable-nations` | ウェイトステートが必要です (`WOLFTPM_CHECK_WAIT_STATE`、Nations ビルドでは有効)。 | +| SEALSQ | QVault TPM 2.0 | SPI | `--enable-sealsq` | ライブラリのデフォルト SPI クロックは 33 MHz です。ウェイトステートが必要です。ポスト量子コマンドには `--enable-pqc` または `--enable-v185` も必要です。 | +| NVIDIA | Jetson Orin (Tegra234) firmware TPM | None (kernel driver) | `--enable-autodetect` or `--enable-devtpm` | `/dev/tpmrm0` 経由でアクセスし、存在しない場合は `/dev/tpm0` にフォールバックします。バスのフラグはありません。 | + +この表の SPI クロックは `wolftpm/tpm2_types.h` にあるライブラリのデフォルト値であり、各パーツの電気的な上限ではありません。パーツの上限はベンダーのデータシートで定められており、これより低い場合も高い場合もあります。 + +* **Infineon SLB9670:** 43 MHz が許容されるのは、3.3 V で SCLK エッジが十分に高速な場合のみです。1.8 V の場合やエッジが遅い場合は、上限が低くなります。 +* **Infineon SLB9672:** データシートでは、公称 33 MHz、最大 34.65 MHz とされています。 +* **STMicroelectronics:** ST33KTPM2X は最大 66 MHz、ST33KTPM2I は最大 48 MHz、ST33TPHF2XSPI は最大 33 MHz をサポートします。wolfTPM はすべての ST パーツで 33 MHz を使用します。 +* **Microchip ATTPM20:** 定格は 36 MHz ですが、高い周波数で問題が発生するため、wolfTPM は 33 MHz を使用します。 +* **SEALSQ QVault:** データシートは概要で 33 MHz、タイミング表で 36 MHz を記載しています。wolfTPM は保守的な 33 MHz を使用します。 + +!!! note + 上記のパーツの上限はベンダーのデータシートに基づくものであり、このリポジトリ内のコードとは照合していません。お使いのパーツの最新のデータシートで確認してください。 + +SPI クロックを変更するには、ビルド時に `TPM2_SPI_MAX_HZ` を定義します。例: `CFLAGS="-DTPM2_SPI_MAX_HZ=20000000"`。選択したベンダーのデフォルト値は `wolftpm/tpm2_types.h` で設定されています。Linux 上の I2C ビルドのデフォルトは 400 kHz (`TPM2_I2C_HZ`) です。 + +## Autodetect とカーネルデバイス + +ベンダーフラグを指定しない場合、`--enable-autodetect` がデフォルトで有効になります。これは実行時にモジュールを検出します。autodetect では、wolfTPM はウェイトステートの確認を有効にし、サポート対象パーツの中で最も低いデフォルト値である 33 MHz に SPI クロックを制限します。この制限は、wolfTPM が直接 SPI アクセスにフォールバックし、`/dev/spidev0.0` から `/dev/spidev0.4` までを試行する場合に適用されます。 + +Linux では、autodetect と `--enable-devtpm` はまずカーネルの TPM デバイスを試行します。ドライバーは `/dev/tpmrm0` (リソースマネージャー、カーネル 5.12 以降) を開き、存在しない場合は `/dev/tpm0` にフォールバックします。リソースマネージャーのみを使用するには `WOLFTPM_USE_TPMRM` を定義し、特定のデバイスに固定するには `TPM2_LINUX_DEV` を設定します。[System Interfaces](system-interfaces.md) を参照してください。 + +## ベンダー別ビルド + +すべてのビルドは、リポジトリのクローンから始まります。 + +```sh +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +``` + +### Infineon + +SLB9670 または SLB9672 (SPI) と SLB9673 (I2C) をサポートします。次のいずれかを選択してください。 + +SPI 上の SLB9672 (`--enable-infineon` のデフォルト): + +```sh +./autogen.sh +./configure --enable-infineon +make +``` + +SPI 上の SLB9670: + +```sh +./autogen.sh +./configure --enable-infineon=slb9670 +make +``` + +I2C 上の SLB9673: + +```sh +./autogen.sh +./configure --enable-infineon=slb9673 --enable-i2c --enable-advio +make +``` + +### STMicroelectronics ST33 + +SPI パーツ (ST33KTPM2XSPI、ST33TPHF2XSPI): + +```sh +./autogen.sh +./configure --enable-st33 +make +``` + +I2C パーツ (ST33KTPM2I、ST33TPHF2XI2C): + +```sh +./autogen.sh +./configure --enable-st33 --enable-i2c +make +``` + +ファームウェアアップグレードのサポートはデフォルトで有効 (`--enable-firmware`) であり、`st33_fw_update` サンプルツールがビルドされます。除外するには `--disable-firmware` を指定します。 + +Raspberry Pi の配線: ST33KTPM2X の SPI デバイスは `/dev/spidev0.0` で、nRST (アクティブロー) は GPIO24 (ピン 18) に接続します。Nuvoton は GPIO4 を使用します。必要に応じて、`--enable-hal-reset` と `TPM2_IoCb_Reset()` を使ってコードから nRST を駆動することもできます。[HAL IO Callback](hal-io-callback.md) を参照してください。 + +### Microchip ATTPM20 + +```sh +./autogen.sh +./configure --enable-microchip +make +``` + +### Nuvoton + +```sh +./autogen.sh +./configure --enable-nuvoton +make +``` + +### Nations Technologies + +`--enable-nations` を指定してください。指定しない場合、デフォルトの `./configure` は `WOLFTPM_NATIONS` を定義しないため、Nations の設定とベンダーコマンドはビルドされません。Z32H330 と NS350 がテスト済みのモジュールです。NS350 Raspberry Pi TPM 2.0 モジュールは `/dev/spidev0.0` を使用します。ウェイトステートが必要であり、Nations ビルドでは `WOLFTPM_CHECK_WAIT_STATE` によって有効になります。 + +```sh +./autogen.sh +./configure --enable-nations +make +``` + +### SEALSQ QVault + +通常の TPM コマンドには `--enable-sealsq` を指定してビルドします。ML-DSA と ML-KEM のコマンドは別途制御されているため、`--enable-pqc` (ポスト量子の軽量サブセット) または `--enable-v185` (完全な v1.85 コマンドセット) も指定してください。これらには、ML-DSA と ML-KEM を有効にした wolfSSL ビルドが必要です。ポスト量子のビルドオプションについては [Post-Quantum Support](post-quantum.md) を参照してください。 + +```sh +./autogen.sh +./configure --enable-sealsq --enable-pqc +make +``` + +### Espressif ESP-IDF + +ESP-IDF コンポーネントには wolfSSL のソースツリーが必要です。CMake が見つけられない場合は、"Could not find wolfssl" というエラーで停止します。wolfSSL のチェックアウトを、`wolfssl`、`wolfssl-master`、または `wolfssl-` という名前の親ディレクトリに配置するか、`WOLFSSL_ROOT` 変数でそのパスを指定してください。代替手段として、wolfSSL ESP Registry のマネージドコンポーネントも利用できます。 + +wolfTPM 固有の設定は、通常 `[project]/components/wolfssl/include` にある wolfSSL の `user_settings.h` ファイルにあります。 + +```sh +git clone https://github.com/wolfSSL/wolfssl.git +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM/IDE/Espressif + +# set your path to ESP-IDF, shown here for VisualGDB using v5.2 +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.2 + +. "${WRK_IDF_PATH}/export.sh" +idf.py build +``` + +## 関連項目 + +* [HAL IO コールバック](hal-io-callback.md) +* [システムインターフェース](system-interfaces.md) +* [TPM 2.0 の概要](tpm2-overview.md) +* [ポスト量子サポート](post-quantum.md) diff --git a/docs/ja/system-interfaces.md b/docs/ja/system-interfaces.md new file mode 100644 index 00000000..8b806bd6 --- /dev/null +++ b/docs/ja/system-interfaces.md @@ -0,0 +1,518 @@ +# システムインターフェース + +wolfTPM は、SPI や I2C 経由で TPM チップと直接通信するだけでなく、オペレーティングシステムのインターフェースやソフトウェアシミュレーターを通じて TPM にアクセスすることもできます。このページでは、ソフトウェア TPM シミュレーター (SWTPM)、Linux カーネルデバイス (`/dev/tpmX`)、Windows TBS API の 3 つを説明します。1 回のビルドで有効にできるトランスポートは 1 つだけです。 + +## ソフトウェアシミュレーター (SWTPM) + +wolfTPM は、[TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code](https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code.pdf) のセクション D.3 で定義されたソフトウェア TPM を使用できます。 + +動作を確認済みのソフトウェア TPM 実装: + +* [Official TCG Reference](https://github.com/TrustedComputingGroup/TPM): TCG が管理している仕様のリファレンスコードです。TCG TPM を参照してください。 +* [IBM (ibmswtpm2) / Ken Goldman](https://github.com/kgoldman/ibmswtpm2): IBM が管理しているリファレンスコードのフォークです (公式の TCG コードと 93% 同一)。ibmswtpm2 を参照してください。 +* [Microsoft ms-tpm-20-ref](https://github.com/microsoft/ms-tpm-20-ref): Microsoft が管理しているリファレンスコードのフォークです (公式の TCG コードと 100% 同一)。ms-tpm-20-ref を参照してください。 +* [libtpms/swtpm by Stefan Berger](https://github.com/stefanberger/swtpm): libtpms のフロントエンドインターフェースを使用します。swtpm を参照してください。 + +ソフトウェア TPM のトランスポートは、既定ではソケット接続です。UART もサポートされています。この実装が使用するのは TPM コマンドインターフェース (通常はポート 2321) のみで、プラットフォームインターフェース (通常はポート 2322) はサポートしません。 + +### wolfTPM の SWTPM サポート + +SWTPM のソケットトランスポートを有効にするには、`--enable-swtpm` を使用します。既定では、すべてのソフトウェア TPM シミュレーターが TCP ポート 2321 を使用します。 + +```sh +./configure --enable-swtpm +make +``` + +!!! note + 複数のトランスポートインターフェースを同時に有効にすることはできません。SWTPM のソケットインターフェースを使ってビルドする場合、組み込みの TIS および devtpm (`/dev/tpm0`) インターフェースは利用できません。 + +ビルドオプション: + +* `WOLFTPM_SWTPM`: ソケットトランスポートを使用する (TIS レイヤーなし) +* `TPM2_SWTPM_HOST`: ソケットのホスト (既定は localhost) +* `TPM2_SWTPM_PORT`: ソケットのポート (既定は 2321) + +### wolfTPM の SWTPM UART サポート + +TCP ソケットの代わりに UART シリアル接続で SWTPM プロトコルを使用するには、`--enable-swtpm=uart` を使用します。これは、STM32H5 上の wolfTPM fwTPM サーバーのように、組み込みターゲットで動作するファームウェア TPM (fwTPM) と通信するためのものです。 + +```sh +./configure --enable-swtpm=uart +make +``` + +シリアルデバイスのパスとボーレートは、コンパイル時または実行時に設定できます。 + +```sh +# Runtime override via environment variable +TPM2_SWTPM_HOST=/dev/ttyACM0 ./examples/wrap/caps +``` + +ビルドオプション: + +* `WOLFTPM_SWTPM_UART`: UART シリアルトランスポートを使用する (`--enable-swtpm=uart` により自動的に設定される) +* `TPM2_SWTPM_HOST`: シリアルデバイスのパス (既定は Linux で `/dev/ttyACM0`、macOS で `/dev/cu.usbmodem`)。実行時には環境変数 `TPM2_SWTPM_HOST` で上書きできます。 +* `TPM2_SWTPM_PORT`: ボーレート (既定は 115200) + +UART トランスポートは、ソケットトランスポートと同じ mssim プロトコルを使用します。シリアルポートは 8N1 の raw モード、フロー制御なしで構成されます。ソケットトランスポートと同様に、シリアルポートのファイルディスクリプターはコマンド間で開いたままになります (コマンドごとの再接続は行いません)。どちらのトランスポートも、`wolfTPM2_Cleanup` の際に接続を閉じます。ソケットトランスポートでは、送信または受信に失敗した場合にも接続を閉じ、次のコマンドで再接続します。UART トランスポートは、コマンドごとの `TPM_SESSION_END` の書き込みが失敗した場合にのみ接続を閉じます。 + +#### セキュリティ上の注意: 環境変数による上書き + +環境変数 `TPM2_SWTPM_HOST` は、コンパイル時に指定したシリアルデバイスのパスを上書きする開発用の便宜機能です。信頼できないローカルユーザーが TPM クライアントと環境を共有するシステムでは、攻撃者が TPM の I/O を、自身が制御する PTY などの不正なデバイスにリダイレクトできる可能性があります。本番環境や堅牢化した環境では、次のようにしてください。 + +* プロセス環境で `TPM2_SWTPM_HOST` を未設定にします。 +* シリアルパスを固定するため、コンパイル時の既定値 (ビルド時の `-D` マクロとして `TPM2_SWTPM_HOST` を設定) を使用します。 + +同じ指針は `TPM2_SWTPM_PORT` (ボーレート) にも当てはまります。また、ソケットトランスポートで環境変数を使って TCP ホストをリダイレクトする場合にも当てはまります。 + +#### 例: STM32H5 上の wolfTPM fwTPM + +wolfTPM プロジェクトには、TrustZone をサポートする STM32 Cortex-M33 ターゲット向けのファームウェア TPM サーバーのポートが含まれています。ビルド、書き込み、テストの手順については、[wolftpm-examples/STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) を参照してください。 + +```sh +# Build host client with UART transport +./configure --enable-swtpm=uart +make + +# Run examples against STM32 fwTPM (adjust device path as needed) +export TPM2_SWTPM_HOST=/dev/ttyACM0 +./examples/wrap/caps +./examples/keygen/keygen -ecc +./examples/seal/seal +``` + +### SWTPM の使用 + +#### SWTPM の電源投入と起動 + +TCG TPM と Microsoft ms-tpm-20-ref の実装では、コマンドインターフェースが有効になる前に、プラットフォームインターフェースで電源投入 (power up) とスタートアップのコマンドを実行する必要があります。必要な電源投入とスタートアップを行うには、次のコマンドを使用します。 + +```sh +echo -ne "\x00\x00\x00\x01" | nc 127.0.0.1 2322 +echo -ne "\x00\x00\x00\x0B" | nc 127.0.0.1 2322 +``` + +#### TCG TPM + +```sh +git clone git@github.com:TrustedComputingGroup/TPM.git +cd TPM +cd TPMCmd +./bootstrap +./configure +make +``` + +`./Simulator/src/tpm2-simulator` で実行し、続いて電源オンとセルフテストを実行します。「SWTPM の電源投入と起動」を参照してください。 + +#### ibmswtpm2 + +```sh +git clone https://github.com/kgoldman/ibmswtpm2.git +cd ibmswtpm2/src/ +make +``` + +`./tpm_server` で実行します。 + +!!! note + `-rm` スイッチを使うと、キャッシュファイル NVChip を削除できます。または、NVChip ファイルを削除します (`rm NVChip`)。 + +#### ms-tpm-20-ref + +```sh +git clone https://github.com/microsoft/ms-tpm-20-ref +cd ms-tpm-20-ref/TPMCmd +./bootstrap +./configure +make +``` + +`./Simulator/src/tpm2-simulator` で実行し、続いて電源オンとセルフテストを実行します。「SWTPM の電源投入と起動」を参照してください。 + +#### swtpm + +libtpms をビルドします。 + +```sh +git clone git@github.com:stefanberger/libtpms.git +cd libtpms +./autogen.sh --with-tpm2 --with-openssl --prefix=/usr +make install +``` + +swtpm をビルドします。 + +```sh +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +./autogen.sh +make install +``` + +macOS では、最初に次を実行します。 + +```sh +brew install openssl socat +pip3 install cryptography + +export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" +export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" + +# libtpms had to use --prefix=/usr/local +``` + +swtpm を実行します。 + +```sh +mkdir -p /tmp/myvtpm +swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init +``` + +#### QEMU を使った swtpm + +ここでは、QEMU 内で wolfTPM を使用し、Linux カーネルデバイス `/dev/tpmX` を介して通信する方法を示します。[swtpm](https://github.com/stefanberger/swtpm) をインストールまたはビルドしておく必要があります。簡単なビルド方法を以下に示します。[libtpms](https://github.com/stefanberger/libtpms/wiki#compile-and-install-on-linux) と [swtpm](https://github.com/stefanberger/swtpm/wiki#compile-and-install-on-linux) の手順を参照する必要がある場合もあります。 + +```sh +PREFIX=$PWD/inst +git clone git@github.com:stefanberger/libtpms.git +cd libtpms/ +./autogen.sh --with-openssl --with-tpm2 --prefix=$PREFIX && make install +cd .. +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig/ ./autogen.sh --with-openssl --with-tpm2 \ + --prefix=$PREFIX && \ + make install +cd .. +``` + +基本的な Linux 環境をセットアップします。他のインストールベースを使用することもできます。この手順では、ベースの Linux システムのインストールに時間がかかります。 + +```sh +# download mini install image +curl -O http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/mini.iso +# create qemu image file +qemu-img create -f qcow2 lubuntu.qcow2 5G +# create directory for tpm state and socket +mkdir $PREFIX/mytpm +# start swtpm +$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ + --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & +# start qemu for installation +qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 -cdrom mini.iso +``` + +ベースシステムのインストール後、QEMU を再び起動し、QEMU インスタンス内で wolfSSL と wolfTPM をビルドします。 + +```sh +# start swtpm again +$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ + --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & +# start qemu system to install and run wolfTPM +qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 +``` + +QEMU のターミナルで、wolfTPM をチェックアウトしてビルドします。 + +```sh +sudo apt install automake libtool gcc git make + +# get and build wolfSSL +git clone https://github.com/wolfssl/wolfssl.git +pushd wolfssl +./autogen.sh && \ + ./configure --enable-wolftpm --disable-examples --prefix=$PWD/../inst && \ + make install +popd + +# get and build wolfTPM +git clone https://github.com/wolfssl/wolftpm.git +pushd wolftpm +./autogen.sh && \ + ./configure --enable-devtpm --prefix=$PWD/../inst --enable-debug && \ + make install +sudo make check +popd +``` + +QEMU 内で `sudo ./examples/wrap/wrap` などのサンプルを実行できます。`/dev/tpm0` にアクセスするために `sudo` が必要になる場合があります。 + +### サンプルの実行 + +```sh +./examples/wrap/caps +./examples/pcr/extend +./examples/wrap/wrap_test +``` + +その他のサンプルの使い方については、ソースツリーの `examples/README.md` を参照してください。 + +## Linux カーネルデバイス (/dev/tpmX) + +Linux では、カーネルの TPM ドライバースタックが TPM をキャラクターデバイスとして公開しており、wolfTPM は SPI や I2C を自前で駆動する代わりに、それを直接使用できます。カーネルがすでに TPM を管理している場合には、このトランスポートが適切です。たとえば、カーネルドライバーにバインドされたディスクリートチップ、Windows 形式のファームウェア TPM、NVIDIA Jetson プラットフォームのような TEE 上で動作するファームウェア TPM などです。 + +`--enable-devtpm` を指定すると、TIS レイヤーも HAL IO コールバックも存在しません。`hal/tpm_io.c` は完全にコンパイル対象から除外され、`TPM2_IoCb` は `NULL` になります (`hal/tpm_io.h` を参照)。そのため、`TPM2_Init` と `wolfTPM2_Init` のコールバック引数には `NULL` を渡してください。 + +`--enable-autodetect` を指定した場合はこの限りではありません。TIS/SPI HAL はフォールバックであるため、意図的にコンパイルされたままになり、`TPM2_IoCb` は実在する関数です。これを渡し続けてください。そうしないと、このビルドが提供するはずの SPI フォールバックに到達できなくなります。 + +### 2 つのデバイスノード + +カーネルは、TPM ごとに最大 2 つのノードを提供します。 + +* `/dev/tpm0`: raw デバイスです。同時に 1 ユーザーのみで、リソース管理はありません。送信したものはそのまま TPM に届きます。 +* `/dev/tpmrm0`: カーネル内のリソースマネージャーです (カーネル 4.12 以降、実用的には 5.12 以降)。ハンドルを仮想化し、必要に応じてトランジェントオブジェクトとセッションをスワップイン/スワップアウトし、接続が閉じられると、その接続に属するすべてを解放します。 + +wolfTPM は `/dev/tpmrm0` を優先し、`/dev/tpm0` にフォールバックします。リソースマネージャーの方が望ましい既定値です。TPM が持つトランジェントオブジェクトのスロットは非常に少なく、リソースマネージャーがないと、ハンドルをリークするプログラムが原因で、システム上の他のすべてのプログラムが TPM を使えなくなるおそれがあります。 + +`--enable-devtpm` と `--enable-autodetect` のどちらにも適用されるビルド時の上書き設定: + +* `-DWOLFTPM_USE_TPMRM`: `/dev/tpmrm0` のみを使用し、raw デバイスにはフォールバックしません。 +* `CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm1"'`: 特定のノードを使用します。このマクロは C の文字列リテラルとして直接使用されるため、内側の引用符が必要です。引用符がないとコンパイルできません。 + +### スタートアップ、シャットダウン、共有状態 + +TPM は Linux が動作するずっと前にファームウェアによって起動されており、リソースマネージャー経由では、システム上の他のすべてのプロセスと共有されます。したがって、TPM の再起動やシャットダウンは個々の呼び出し元が決めることではなく、wolfTPM はこのトランスポートでは介入しません。 + +* `wolfTPM2_Init` は、スタートアップとセルフテストのシーケンスを省略します。 +* `wolfTPM2_Reset` と `wolfTPM2_Shutdown` は TPM コマンドを送信せず、`NOT_COMPILED_IN` (-174) を返します。このトランスポートでの `wolfTPM2_SetLocality` と同様です。シャットダウンもスタートアップも要求しない `wolfTPM2_Reset(dev, 0, 0)` は、拒否したものが何もないため、引き続き `TPM_RC_SUCCESS` を返します。ここでの `NOT_COMPILED_IN` は、失敗ではなく「OS が管理している」という意味に捉えてください。 +* `wolfTPM2_SetLocality` は、カーネルがロカリティを管理しているため `NOT_COMPILED_IN` を返します。 + +カーネルがこの点を確実に防いでくれるわけではありません。`/dev/tpmrm0` でのコマンドフィルタリングは、主にハンドルの分離のためのものであり、グローバルな状態変更をブロックするためのものではありません。また、動作はカーネルのバージョンや TPM の実装によって異なります。Jetson OP-TEE fTPM を搭載した Linux 5.15 では、リソースマネージャー経由で送信した `TPM2_Shutdown(TPM_SU_CLEAR)` はそのまま通過して成功を返します。これは wolfTPM からでも `tpm2_shutdown` からでも同じです。つまりこれは、カーネルではなく、ライブラリがコマンドの送信を見送ることで TPM の他の利用者を守っているケースです。 + +TPM のスタートアップ状態を制御する必要がある場合は、`/dev/tpm0` と TPM の排他的な使用、または wolfTPM の TIS ドライバーによる SPI 直接アクセスが必要です。 + +### autodetect ビルドでのネイティブ API の動作 + +`wolfTPM2_*` ラッパーではなく `TPM2_Init` または `TPM2_Init_ex` を直接使用する場合は、次の 2 つの動作に注意が必要です。 + +カーネルデバイスは、渡したコールバックより優先されます。`/dev/tpmrm0` または `/dev/tpm0` が開ければ、すべてのコマンドがそこへルーティングされ、渡した HAL IO コールバックは一切呼び出されません。カーネルにバインドされた TPM とディスクリートの SPI 部品の両方があるホストでは、autodetect 導入前のビルドとは別の TPM と通信することになります。使用したい部品は、`--enable-devtpm`、`--enable-spi`、`--enable-`、または `-DTPM2_LINUX_DEV` で固定してください。 + +初期化でディスクリプターが取得されるようになりました。autodetect ビルドでは `TPM2_Init*` がデバイスを開き、それを閉じるのは `TPM2_Cleanup()` です。クリーンアップを省略していたネイティブの呼び出し元は、以前は何もリークしませんでしたが、現在はコンテキストごとにディスクリプターをリークします。これは、単一のオープンしか許可しない raw の `/dev/tpm0` のみを公開しているホストで最も問題になります。初期化しただけのコンテキストが、その存続期間中ずっと TPM を排他的に保持し、同じプロセス内の 2 つ目のコンテキストは別のトランスポートにフォールスルーします。 + +`TPM2_Init_minimal()` は影響を受けません。IO を一切行わず、デバイスが存在しなくても成功します。 + +### トランジェントハンドルはプロセスをまたいで存続しない + +これは、既存のアプリケーションが動作しなくなる原因として最も可能性が高い違いです。 + +`/dev/tpmrm0` では、カーネルがオープンしたファイル記述ごとに専用のハンドル空間を与えます。トランジェントオブジェクトのハンドルは仮想化され (TPM が割り当てた値と、返される値は異なります)、その空間内のすべてのものは、ファイルディスクリプターが閉じられると解放されます。あるプロセスで作成したトランジェント鍵は、次のプロセスが実行される時点ではすでに存在せず、そのプロセスが出力したハンドル番号は他のプロセスにとって意味を持ちません。 + +リソースマネージャー経由で Jetson fTPM 上にプライマリ鍵を作成すると、次のように返されます。 + +``` +Create Primary Handle: 0x80ffffff +``` + +これは、raw デバイスが報告する `0x80000000` ではありません。その後、別のプロセスからトランジェントハンドルを問い合わせると、リストは空です。 + +```bash +tpm2_getcap handles-transient # no output, the space was torn down +``` + +実際上の帰結は次の 2 つです。 + +* 「鍵を作成して保持し、次のコマンドで使う」というワークフローは、プロセスをまたいでは機能しません。一連の処理を 1 つのプロセス内で行うか、`TPM2_EvictControl` でオブジェクトを永続化して、存続する安定した `0x81xxxxxx` ハンドルを割り当ててください。 +* `0x80000000` のようなトランジェントハンドルをコマンドラインにハードコードして渡すと失敗します。カーネルが TPM に届く前にその参照を拒否し、これはファイルディスクリプター層で起きるため、エラーは `read()` での `errno 22 = Invalid argument` として表面化し、wolfTPM はこれをハンドルエラーではなく `TPM_RC_FAILURE` として報告します。`TPM_RC_FAILURE` が `Failed to read from /dev/tpmrm0 ... errno 22` とともに表示される場合は、TPM を疑う前に、古い、またはプロセスをまたいだトランジェントハンドルを疑ってください。 + +wolfTPM のスクリプト `examples/run_examples.sh` はまさにこの問題に当たります。プロビジョニングのセクションで、あるプロセスが `-keep` を付けて IAK と IDevID のプライマリ鍵を作成し、別のプロセスから `0x80000000` と `0x80000001` を参照します。このブロックは、構造上、リソースマネージャーでは成功しません。その前後の部分は影響を受けません。記述どおりに実行する必要がある場合は、排他アクセスで `/dev/tpm0` を使用してください。 + +### ビルド + +```bash +./autogen.sh +./configure --enable-devtpm +make +``` + +`--enable-devtpm` はカーネルノードのみを使用します。wolfTPM に `/dev/tpmrm0`、次に `/dev/tpm0` を試させ、最後に SPI のプローブにフォールバックさせたい場合は、代わりに `--enable-autodetect` を使用してください。これは、複数のボードで動作させる必要がある 1 つのバイナリに便利です。 + +有効にできるトランスポートは一度に 1 つだけです。`--enable-devtpm` は `--enable-swtpm` および `--enable-winapi` と競合し、複数を指定すると configure は停止します。 + +#### x86_64 および aarch64 の既定動作 + +Linux の x86_64 または aarch64 でオプションなしの `./configure` を実行しても、`/dev/tpmX` と通信するビルドにはなりません。これらのホストでは、ハードウェアなしで `make check` が成功するように、wolfTPM がソフトウェア TPM (swTPM と fwTPM) を自動的に有効にし、`WOLFTPM_SWTPM` が定義されるとカーネルデバイスの autodetect 経路は抑止されます。その結果、TCP ポート 2321 のシミュレーターと通信するビルドになります。 + +ハードウェア経路を明示的に選択すると、この既定動作は再び無効になります: `--enable-autodetect`、`--enable-devtpm`、または任意の `--enable-` です。ソフトウェアの既定値が採用された場合、configure は通知を出力します。ビルドしたバイナリが TPM を見つけられない場合は、configure の出力の末尾を確認してください。 + +これは、ファームウェア TPM を搭載したシングルボードの aarch64 マシンで特に重要です。そこではカーネルデバイスが唯一のトランスポートだからです。 + +### パーミッション + +TPM のキャラクターデバイスは、全ユーザーがアクセスできる設定ではありません。一般的なシステムでは、モードは `0660` で、グループ `tss` が所有しています。 + +``` +crw-rw---- 1 tss root 10, 224 /dev/tpm0 +crw-rw---- 1 tss tss 252, 65536 /dev/tpmrm0 +``` + +wolfTPM は `EACCES` を検出し、そのことを分かりやすく報告します。 + +``` +Permission denied on /dev/tpm0 +Use sudo or add tss group to user. +``` + +対処方法は、ユーザーを所有グループに追加し、新しいログインセッションを開始することです。 + +```bash +sudo usermod -aG tss $USER +``` + +`tss` グループは tpm2-tss によって作成されます。これを提供するディストリビューションでは、このグループがメンバーなしで存在していることがよくあります。そのため、グループが正しく設定されているように見えても、この手順は必須です。 + +独自のグループを使用する場合は、代わりに udev ルールを追加します。 + +1. グループを作成し、ユーザーを追加します。 + + ```bash + sudo addgroup wolftpm + sudo adduser [username] wolftpm + ``` + +2. 次の内容で `/etc/udev/rules.d/wolftpm-udev.rules` を作成します。 + + ``` + KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", GROUP="wolftpm" + ``` + +3. `sudo udevadm control -R` でルールを再読み込みし、再接続または再起動します。 + +### NVIDIA Jetson Orin (Tegra234) ファームウェア TPM + +Jetson Orin プラットフォームには、バス上のディスクリートパッケージではなく、OP-TEE 内のトラステッドアプリケーションとして動作するファームウェアで実装された TPM 2.0 が搭載されています。Linux は `tpm_ftpm_tee` ドライバー経由でこれにアクセスします。このドライバーは TEE インターフェースを介して TA と通信し、通常の TPM チップとして登録されます。wolfTPM から見ると、それは単なる別の `/dev/tpmrm0` です。 + +ビルドする前に、デバイスが存在することを確認します。 + +```bash +lsmod | grep tpm_ftpm_tee +ls -l /dev/tpm* +cat /sys/class/tpm/tpm0/tpm_version_major # expect 2 +``` + +モジュールがない場合は、`sudo modprobe tpm_ftpm_tee` を試し、カーネルが `CONFIG_TCG_FTPM_TEE` を有効にして構成されていることを確認してください。NVIDIA Jetson Linux (L4T) イメージにはこのドライバーが含まれており、起動時に `fTPM Device Provisioning Service` の systemd ユニットが実行されます。その完了は起動ログで確認できます。 + +シリコン ID の fTPM プロビジョニングが有効でないという OP-TEE の起動メッセージは、NVIDIA の別の機能に関するものです。TPM 2.0 デバイスが利用できないという意味ではありません。 + +上記のとおり `--enable-devtpm` または `--enable-autodetect` を指定してビルドし、次のコマンドで確認します。 + +```bash +./examples/wrap/caps +``` + +ファームウェア TPM であるため、ディスクリートの部品とは 2 つの点で違いがあります。まず、TIS バスがないため、`TPM2: Caps/Did/Vid/Rid` の値は存在せず、デバイスは `TPM2_GetCapability` のプロパティのみから識別されます。`--enable-devtpm` では `DEBUG_WOLFTPM` の行は引き続き出力されますが、すべてゼロになります。`--enable-autodetect` では、`wolfTPM2_Init_ex` はカーネルデバイスが開いた時点で、その printf の前に戻るため、この行は完全に出力されません。次に、ファームウェア TPM のアルゴリズムのカバー範囲は、データシートではなくファームウェアのビルドによって決まるため、想定せずに確認してください。操作が存在しない場合、ベンチマークは失敗ではなく未サポートとして報告します。Jetson Orin の fTPM は、ベンチマークが実行するすべての操作をサポートしています。 + +### テスト + +サンプルは、このトランスポートでも変更なしで動作します。 + +```bash +./examples/wrap/caps +./examples/native/native_test +./examples/wrap/wrap_test +./examples/bench/bench +./examples/run_examples.sh +``` + +`run_examples.sh` は、ロカリティテストをサポートしないバックエンドでは、すでにそのテストをスキップします。 + +### CI でのカバレッジ + +`--enable-devtpm` と `--enable-autodetect` はどちらも CI でビルドテストされていますが、GitHub ホストのランナーには `/dev/tpm*` ノードがないため、実行はされていません。このトランスポートの実行時カバレッジには、カーネルドライバーにバインドされた実際の TPM を備えたセルフホストランナーが必要です。 + +## Windows TBS API + +wolfTPM は、Windows ネイティブの TBS (TPM Base Services) を使用するようにビルドできます。Windows TBS インターフェースを使用する場合、NV へのアクセスは既定でブロックされます。TPM の NV ストレージ領域は非常に限られており、満杯になると、鍵ハンドルのロード失敗など、未定義の動作を引き起こす可能性があります。NV 領域は TBS によって管理されません。 + +TPM は、`TPM2_Create` による鍵の作成時に、暗号化された秘密鍵ブロブを返すよう設計されています。これはディスクに安全に保存し、必要なときにロードできます。秘密鍵ブロブの保護に使用される対称暗号鍵は、TPM だけが知っています。`TPM2_Load` で鍵をロードするとトランジェントハンドルが得られ、これを署名、および暗号化と復号に使用できます。 + +`TPM2_CreatePrimary` で作成したプライマリ鍵では、ハンドルが返されます。暗号化された秘密データは返されません。このハンドルは、`TPM2_FlushContext` が呼び出されるまでロードされたままです。 + +`TPM2_Create` による通常の鍵作成では、`TPM2B_PRIVATE outPrivate` が返されます。これは暗号化されたブロブで、保存しておき、`TPM2_Load` でいつでもロードできます。 + +### 制限事項 + +wolfTPM は、TPM 2.0 デバイスを搭載した Windows 10 でテストされています。Windows は TPM 1.2 もサポートしていますが、機能は限定的であり、wolfTPM は TPM 1.2 をサポートしません。 + +TPM 2.0 の有無は、PowerShell を開いて `Get-PnpDevice -Class SecurityDevices` を実行して確認できます。 + +``` +Status Class FriendlyName +------ ----- ------------ +OK SecurityDevices Trusted Platform Module 2.0 +Unknown SecurityDevices Trusted Platform Module 2.0 +``` + +### MSYS2 でのビルド + +MSYS2 を使用してテストしました。 + +```bash +export PREFIX=$PWD/tmp_install + +cd wolfssl +./autogen.sh +./configure --prefix="$PREFIX" --enable-wolftpm +make +make install + +cd wolftpm/ +./autogen.sh +./configure --prefix="$PREFIX" --enable-winapi +make +./examples +``` + +MSYS2 に開発用の基本ツールをインストールするには、`pacman -S base-devel` と `pacman -S mingw-w64-x86_64-toolchain` を使用します。 + +### Linux でのビルド + +[MinGW-w64 Win32 toolchain builds](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds/) の mingw-w32-bin_x86_64-linux_20131221.tar.bz2 を使用してテストしました。 + +ツールを展開し、`PATH` に追加します。 + +```bash +mkdir mingw_tools +cd mingw_tools +tar xjvf ../mingw-w32-bin_x86_64-linux_20131221.tar.bz2 +export PATH=$PWD/bin/:$PWD/i686-w64-mingw32/bin:$PATH +cd .. +``` + +ビルド: + +```bash +export PREFIX=$PWD/tmp_install +export CFLAGS="-DWIN32 -DMINGW -D_WIN32_WINNT=0x0600 -DUSE_WOLF_STRTOK" +export LIBS="-lws2_32" + +cd wolfssl +./autogen.sh +./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-wolftpm +make +make install + +cd ../wolftpm/ +./autogen.sh +./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-winapi +make +cd .. +``` + +### Windows での実行 + +マシン上の TPM の有無と状態を確認するには、`tpm.msc` を実行します。サンプルの実行方法については、ソースツリーの `examples/README.md` を参照してください。 + +## 関連項目 + +- [はじめに](getting-started.md) +- [wolfTPM のビルド](building.md) +- [ビルドオプション](build-options.md) +- [対応ハードウェア](supported-hardware.md) diff --git a/docs/ja/testing.md b/docs/ja/testing.md new file mode 100644 index 00000000..0356c487 --- /dev/null +++ b/docs/ja/testing.md @@ -0,0 +1,88 @@ +# テスト + +このページでは、wolfTPM のテストをローカルで実行する方法と、リポジトリ上で動作する継続的インテグレーション (CI) のワークフローを説明します。 + +## ローカルでのテスト実行 + +メインのテストスイートをビルドして実行します。 + +```sh +./configure +make check +``` + +`make check` は、ユニットテスト、fwTPM テスト、ポスト量子暗号 (PQC) テストを実行します。ユニットテストのソースは次のとおりです。 + +| ファイル | 目的 | +|---|---| +| `tests/unit_tests.c` | wolfTPM ライブラリのユニットテスト | +| `tests/fwtpm_unit_tests.c` | fwTPM コマンドプロセッサのユニットテスト | +| `tests/fwtpm_hal_unit_tests.c` | fwTPM HAL のユニットテスト | + +シェルベースのテストは次のとおりです。 + +| ファイル | 目的 | +|---|---| +| `tests/fwtpm_check.sh` | `make check` が fwTPM テストに使用するエントリポイント | +| `tests/fwtpm_da_retry.sh` | ディクショナリアタックとリトライ処理 | +| `tests/pqc_mssim_e2e.sh` | ポスト量子暗号のエンドツーエンドテスト | + +TPM またはシミュレータに対してサンプルプログラムを実行するには、次を使用します。 + +```sh +./examples/run_examples.sh +``` + +このスクリプトは次の環境変数を読み取ります。 + +| 変数 | 目的 | +|---|---| +| `WOLFSSL_PATH` | サンプルが使用する wolfSSL ビルドへのパス | +| `WOLFCRYPT_ENABLE` | wolfCrypt サポートが組み込まれている場合に設定 | +| `NO_FILESYSTEM` | ファイルシステムを必要とするサンプルをスキップ | +| `ENABLE_DESTRUCTIVE_TESTS` | TPM のクリアなど、TPM の状態を変更するテストも実行 | + +!!! warning + 破壊的テストは TPM を変更します。必要な鍵やデータを保持している TPM では有効にしないでください。 + +## CI ワークフロー + +ワークフローは `.github/workflows/` にあります。表には各ファイルのワークフロー名を示しています。 + +| ファイル | 名前 | +|---|---| +| `_resolve-wolfssl.yml` | Resolve wolfSSL versions | +| `cmake-build.yml` | WolfTPM CMake Build Tests | +| `codeql.yml` | CodeQL | +| `codespell.yml` | Codespell | +| `coverity-scan-fixes.yml` | Coverity Scan master branch | +| `docs-site.yml` | Build manual with documentation tooling | +| `freestanding-build.yml` | Freestanding Build (WOLFTPM_NO_STD_HEADERS) | +| `fuzz.yml` | Fuzz Testing | +| `fwtpm-test.yml` | fwTPM Tests | +| `make-test-swtpm.yml` | WolfTPM Build Tests | +| `multi-compiler.yml` | Multiple Compilers | +| `nightly.yml` | Nightly CI | +| `pqc-build-matrix.yml` | PQC Build Matrix (v1.85 trimming) | +| `pqc-examples.yml` | PQC Examples (v1.85) | +| `publish-ci-image.yml` | Publish wolfTPM CI image | +| `publish-docs-image.yml` | Publish documentation image | +| `release-checks.yml` | Release Checks | +| `rust-test.yml` | WolfTPM Rust Wrapper Tests | +| `sanitizer.yml` | Sanitizer Tests | +| `sbom.yml` | SBOM Test | +| `seal-test.yml` | Seal Test Suite | +| `semgrep.yml` | Semgrep | +| `smoke-test.yml` | Smoke Test | +| `spdm-test.yml` | SPDM Test | +| `win-swtpm-test.yml` | Windows swtpm Transport Test | +| `win-test.yml` | Windows Build Test | +| `wolfhal-build.yml` | wolfHAL Build Tests | +| `wolfssl-versions-pqc.yml` | wolfSSL Version Matrix | +| `zephyr.yml` | Zephyr wolfTPM Tests | + +## 関連項目 + +- [ベンチマーク](benchmarks.md) +- [SBOM とコンプライアンス](sbom-and-compliance.md) +- [リリースノート](release-notes.md) diff --git a/docs/ja/tls-and-certificates.md b/docs/ja/tls-and-certificates.md new file mode 100644 index 00000000..3f23536e --- /dev/null +++ b/docs/ja/tls-and-certificates.md @@ -0,0 +1,241 @@ +# TLS と証明書 + +このページでは、証明書と安全な接続のために TPM キーを活用する wolfTPM のサンプルを説明します。具体的には、証明書署名要求 (CSR) の生成、テスト用証明書への署名、PKCS #7 署名、および秘密鍵を TPM の内部に保持する TLS クライアントとサーバーのプログラムです。 + +PKCS #7 と TLS のサンプルは、`./hal/tpm_io.h` で定義されたハンドルを使用して、テスト用の RSA キーと ECC キーを NV に作成します。以下で説明するように、CSR を生成し、テストスクリプトで署名する必要があります。 + +## CSR + +`csr` サンプル (`examples/csr/csr.c`) は、TPM のキーペアに基づく証明書を作成するための証明書署名要求を生成します。 + +```sh +./examples/csr/csr +``` + +2 つのファイルが作成されます。 + +- `./certs/tpm-rsa-cert.csr` +- `./certs/tpm-ecc-cert.csr` + +オプション: + +| オプション | 説明 | +|--------|-------------| +| `-cert` | CSR ではなく自己署名証明書を作成します。 | +| `-signcb` | `wc_SignCert_cb` コールバックベースの署名を使用します。 | + +出力例 (base64 の本体はここでは短縮しています): + +```sh +./examples/csr/csr +TPM2 CSR Example +Generated/Signed Cert (DER 860, PEM 1236) +-----BEGIN CERTIFICATE REQUEST----- +MIIDWDCCAkACAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP +BgNVBAcMCFBvcnRsYW5kMQ0wCwYDVQQEDARUZXN0MRAwDgYDVQQKDAd3b2xmU1NM +... +l/076ekjTI+7PwzBZIG2F3nOIDUmHwe0lAWdU8h9IoAlM6kS22fh6gZZqQg= +-----END CERTIFICATE REQUEST----- + +Generated/Signed Cert (DER 467, PEM 704) +-----BEGIN CERTIFICATE REQUEST----- +MIIBzzCCAXUCAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP +... +6AIgBm+EU6m5SDsk7BYmxTQAhgJFrelwymOa7m16kAXnFuU= +-----END CERTIFICATE REQUEST----- +``` + +最初の要求は RSA キー用、2 番目は ECC キー用です。 + +!!! note + CSR サンプルには、証明書生成と証明書要求のサポート (`--enable-certgen --enable-certreq`) およびクリプトコールバックを有効にしてビルドした wolfSSL が必要です。 + +## 証明書への署名 + +外部スクリプトが、TPM が生成した CSR からテスト用証明書を生成します。通常は、CSR を信頼できる CA に提供して署名してもらいます。 + +```sh +./certs/certreq.sh +``` + +このスクリプトは、次の X.509 ファイル (.pem 形式も作成されます) を作成します。 + +- `./certs/ca-ecc-cert.der` +- `./certs/ca-rsa-cert.der` +- `./certs/client-rsa-cert.der` +- `./certs/client-ecc-cert.der` +- `./certs/server-rsa-cert.der` +- `./certs/server-ecc-cert.der` + +## PKCS #7 + +`pkcs7` サンプル (`examples/pkcs7/pkcs7.c`) は、TPM ベースのキーを使用して PKCS #7 でデータの署名と検証を行います。次の順序で実行してください。 + +1. `./examples/csr/csr` +2. `./certs/certreq.sh` +3. `./examples/pkcs7/pkcs7` + +結果はコンソールに表示されます。 + +| オプション | 説明 | +|--------|-------------| +| `-ecc` / `-rsa` | ECC キーまたは RSA キーを使用します (デフォルトは RSA)。 | +| `-incert=file` | 使用するキーの証明書。デフォルトは `./certs/client-rsa-cert.der` と `./certs/client-ecc-cert.der` です。 | +| `-out=file` | 署名付きデータと証明書を含む、生成された PKCS #7 ファイルを書き出します。 | + +出力例: + +```sh +./examples/pkcs7/pkcs7 +TPM2 PKCS7 Example +PKCS7 Signed Container 1625 +PKCS7 Container Verified (using TPM) +PKCS7 Container Verified (using software) +``` + +## TLS サンプル + +TLS サンプルは、TPM ベースの ECDHE (ECC 一時鍵) をサポートします。コンパイル時のトグルは次のとおりです。 + +| 定義 | 効果 | +|--------|--------| +| `WOLFTPM2_USE_SW_ECDHE` | ECC 一時鍵の生成と共有シークレットに TPM を使用しないようにします。`CFLAGS="-DWOLFTPM2_USE_SW_ECDHE"` または `#define` で設定します。 | +| `WOLFTPM_USE_SYMMETRIC` | TLS サンプルで、TPM を通じた対称 AES、ハッシュ、HMAC のサポートを有効にします。 | +| `TLS_USE_ECC` | RSA も有効な場合に、wolfSSL で ECC の使用を強制します。 | + +!!! note + TLS サーバーとクライアントを同じマシンで実行するには、`WOLFTPM_TIS_LOCK` (`--enable-tislock`) を指定して wolfTPM をビルドします。これにより、TPM デバイスへの同時アクセス保護が有効になります。 + +プログラムは `examples/tls/` にあります。 + +| プログラム | 目的 | +|---------|---------| +| `tls_client.c` | 相互認証に TPM のキーと証明書を使用する TLS クライアント。 | +| `tls_server.c` | TPM のキーと証明書を使用する TLS サーバー。 | +| `tls_client_notpm.c` | 比較とベンチマークのための、TPM を使用しない TLS クライアント。 | + +### 証明書の生成 + +クライアント証明書とサーバー証明書を生成するには、次を実行する必要があります。 + +1. `./examples/keygen/keygen rsa_test_blob.raw -rsa -t` +2. `./examples/keygen/keygen ecc_test_blob.raw -ecc -t` +3. `./examples/csr/csr` +4. `./certs/certreq.sh` +5. wolfTPM の CA ファイルを wolfSSL の certs ディレクトリにコピーします。 + +```sh +cp ./certs/ca-ecc-cert.pem ../wolfssl/certs/tpm-ca-ecc-cert.pem +cp ./certs/ca-rsa-cert.pem ../wolfssl/certs/tpm-ca-rsa-cert.pem +``` + +`wolf-ca-rsa-cert.pem` と `wolf-ca-ecc-cert.pem` のファイルは、wolfSSL のサンプル証明書から取得します。 + +```sh +cp ../wolfssl/certs/ca-cert.pem ./certs/wolf-ca-rsa-cert.pem +cp ../wolfssl/certs/ca-ecc-cert.pem ./certs/wolf-ca-ecc-cert.pem +``` + +### TLS クライアント + +クライアントは、TLS の相互認証 (クライアント認証) に使用する TPM のキーと証明書を示します。wolfSSL の TLS クライアントは、相互認証が使用されることを示すために公開鍵をロードし、クリプトコールバックが秘密鍵による署名に TPM を使用します。 + +デフォルトでは、クライアントはポート 11111 の localhost に接続します。`TLS_HOST` と `TLS_PORT` で上書きできます。 + +wolfSSL のサンプルサーバーを起動します。 + +```sh +./examples/server/server -b -p 11111 -g -d -i -V +``` + +クライアント証明書を検証するには、代わりに次のいずれかを使用します。 + +```sh +./examples/server/server -b -p 11111 -g -A ./certs/tpm-ca-rsa-cert.pem -i -V +./examples/server/server -b -p 11111 -g -A ./certs/tpm-ca-ecc-cert.pem -i -V +``` + +その後、wolfTPM の TLS クライアントを実行します。 + +```sh +./examples/tls/tls_client -rsa +./examples/tls/tls_client -ecc +``` + +出力例: + +```sh +./examples/tls/tls_client +TPM2 TLS Client Example +Write (29): GET /index.html HTTP/1.0 + + +Read (193): HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + + + +Welcome to wolfSSL! + + +

wolfSSL has successfully performed handshake!

+ + +``` + +### TLS サーバー + +サーバーは、TLS サーバーに使用する TPM のキーと証明書を示します。TPM の公開鍵をロードし、クリプトコールバックが秘密鍵による署名に TPM を使用します。デフォルトではポート 11111 で待ち受けます。これはビルド時に `TLS_PORT` マクロで変更できます。 + +wolfTPM の TLS サーバーを実行します。 + +```sh +./examples/tls/tls_server -rsa +./examples/tls/tls_server -ecc +``` + +その後、wolfSSL のサンプルクライアントで接続します。 + +```sh +./examples/client/client -h localhost -p 11111 -g -d +``` + +サーバー証明書を検証するには、次のようにします。 + +```sh +./examples/client/client -h localhost -p 11111 -g -A ./certs/tpm-ca-rsa-cert.pem +./examples/client/client -h localhost -p 11111 -g -A ./certs/tpm-ca-ecc-cert.pem +``` + +`https://localhost:11111` をブラウザで開くこともできます。テスト用 CA の `./certs/ca-rsa-cert.pem` と `./certs/ca-ecc-cert.pem` を OS のキーストアにロードするまで、ブラウザは証明書の警告を表示します。テスト目的であれば、ほとんどのブラウザで警告を無視して続行できます。 + +出力例: + +```sh +./examples/tls/tls_server +TPM2 TLS Server Example +Loading RSA certificate and public key +Read (29): GET /index.html HTTP/1.0 + + +Write (193): HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + + + +Welcome to wolfSSL! + + +

wolfSSL has successfully performed handshake!

+ + +``` + +## 関連項目 + +- [Sealing and NVRAM](sealing-and-nvram.md) +- [Management and GPIO](management-and-gpio.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/ja/tpm2-overview.md b/docs/ja/tpm2-overview.md new file mode 100644 index 00000000..6cc23fba --- /dev/null +++ b/docs/ja/tpm2-overview.md @@ -0,0 +1,118 @@ +# TPM 2.0 の概要 + +このページでは、TPM とは何か、wolfTPM が公開する階層と PCR、コード内で使われる用語、および通信している TPM モジュールの識別方法を説明します。 + +wolfTPM は、組み込み用途向けに設計された、API 後方互換性を備えたポータブルなオープンソースの TPM 2.0 スタックです。ネイティブ C で記述されていること、SPI ハードウェアインターフェース用の単一の IO コールバック、外部依存がないこと、コンパクトなコードと低いリソース使用量により、高い移植性を備えています。wolfTPM は、アテステーションのような複雑な TPM 操作を支援する API ラッパーと、TPM を使った証明書署名要求 (CSR) の生成のような複雑な暗号処理を支援するサンプルを提供します。 + +## プロトコルの概要 + +Trusted Platform Module (TPM。ISO/IEC 11889 とも呼ばれます) は、セキュア暗号プロセッサに関する国際標準であり、統合された暗号鍵によってハードウェアを保護するために設計された専用のマイクロコントローラです。各 TPM チップには製造時に一意で秘密の RSA 鍵が焼き込まれているため、コンピュータプログラムは TPM を使ってハードウェアデバイスを認証できます。 + +TPM は次の機能を提供します。 + +- 乱数生成器。 +- 限定された用途向けの暗号鍵を安全に生成する機能。 +- リモートアテステーション: ハードウェアとソフトウェア構成について、ほぼ偽造不可能なハッシュ鍵の要約を作成します。要約の範囲は、構成データをハッシュするソフトウェアによって決まります。これにより、第三者はソフトウェアが変更されていないことを検証できます。 +- バインディング: ストレージ鍵から派生した一意の RSA 鍵である TPM バインド鍵を使ってデータを暗号化します。 +- シーリング: バインディングに似ていますが、加えてデータを復号 (アンシール) できる TPM の状態を指定します。 + +TPM は、プラットフォームの完全性、ディスク暗号化、パスワード保護、ソフトウェアライセンス保護にも利用できます。 + +## 階層 + +``` +Platform TPM_RH_PLATFORM +Owner TPM_RH_OWNER +Endorsement TPM_RH_ENDORSEMENT +``` + +各階層は、製造時に生成された独自のシードを持ちます。 + +`TPM2_Create` または `TPM2_CreatePrimary` で使用される引数がテンプレートを作成し、これが KDF に入力されて、使用した階層に基づく同じ鍵が生成されます。生成される鍵は、再起動後も毎回同じになります。新しい RSA 2048 ビット鍵の生成には約 15 秒かかります。通常、これらは作成後に `TPM2_EvictControl` を使って NV に保存されます。各 TPM は、シードに基づいて独自に一意の鍵を生成します。 + +エフェメラル階層 (`TPM_RH_NULL`) もあり、一時的な鍵の作成に使用できます。 + +## Platform Configuration Registers (PCR) + +PCR は、TPM がサポートし割り当てたバンク内のインデックス 0 から 23 にハッシュダイジェストを保持します。PCR を extend することで、ブートシーケンスの完全性 (セキュアブート) を証明できます。 + +## 用語 + +このプロジェクトでは、append と marshall、parse と unmarshall という用語を使用します。 + +略語: + +* HAL: Hardware Abstraction Layer (ハードウェア抽象化レイヤー)。 +* NV: Non-Volatile memory (不揮発性メモリ)。 +* TPM: Trusted Platform Module。 + +## デバイスの識別 + +次の行は、動作確認済みの各モジュールから取得した識別情報の出力です。`Caps/Did/Vid/Rid` の行は TIS バスレジスタから取得されます。 + +``` +Infineon SLB9670: +TPM2: Caps 0x30000697, Did 0x001b, Vid 0x15d1, Rid 0x10 +Mfg IFX (1), Vendor SLB9670, Fw 7.85 (4555), FIPS 140-2 1, CC-EAL4 1 + +Infineon SLB9672: +TPM2: Caps 0x30000697, Did 0x001d, Vid 0x15d1, Rid 0x36 +Mfg IFX (1), Vendor SLB9672, Fw 16.10 (0x4068), FIPS 140-2 1, CC-EAL4 1 + +Infineon SLB9673: +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a), FIPS 140-2 1, CC-EAL4 1 + +STMicro ST33KTPM2XSPI +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 0 +Mfg STM (2), Vendor ST33KTPM2XSPI, Fw 9.256 (0x0), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XSPI +TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 74.8 (1151341959), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XSPI (newer firmware line) +TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 1.258 (0x0), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XI2C +TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 74.9 (1151341959), FIPS 140-2 1, CC-EAL4 0 + +Microchip ATTPM20 +TPM2: Caps 0x30000695, Did 0x3205, Vid 0x1114, Rid 0x 1 +Mfg MCHP (3), Vendor , Fw 512.20481 (0), FIPS 140-2 0, CC-EAL4 0 + +Nations Technologies Inc. Z32H330 TPM 2.0 module +Mfg NTZ (0), Vendor Z32H330, Fw 7.51 (419631892), FIPS 140-2 0, CC-EAL4 0 + +Nations Technologies Inc. NS350 TPM 2.0 module +TPM2: Caps 0x30000615, Did 0x0701, Vid 0x9999, Rid 0x 1 +Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 + +Nuvoton NPCT650 TPM2.0 +Mfg NTC (0), Vendor rlsNPCT , Fw 1.3 (65536), FIPS 140-2 0, CC-EAL4 0 + +Nuvoton NPCT750 TPM2.0 +TPM2: Caps 0x30000697, Did 0x00fc, Vid 0x1050, Rid 0x 1 +Mfg NTC (0), Vendor NPCT75x"!!4rls, Fw 7.2 (131072), FIPS 140-2 1, CC-EAL4 0 + +SealSQ QVault TPM 2.0 +TPM2: Caps 0x30000797, Did 0x0083, Vid 0x2406, Rid 0x 3 +Mfg SEAL (6), Vendor QVault TPM, Fw 2.1 (0x3010303), FIPS 140-3, CC-EAL4 0 + +NVIDIA Jetson Orin (Tegra234) OP-TEE firmware TPM, via /dev/tpmrm0 +Mfg MSFT (7), Vendor SSE fTPM, Fw 8216.1808 (0x105300), FIPS 140-2, CC-EAL4 0 +``` + +ST33TPHF2X の初期の 1.x ファームウェアは、`TPM_PT_VENDOR_STRING_1..4` をテキストではなくバイナリとして報告するため、`Vendor` フィールドは空で表示されます。後期の 1.x ファームウェアは `ST33TPHF2XSPI` のような ASCII を報告します。代わりにファームウェアのメジャーバージョンでラインを識別できます。1.x と 2.x は ST33TPHF2X (それぞれ SPI ファームウェアと I2C ファームウェア)、9.x は ST33KTPM2X、10.x は ST33KTPM2A です。これがファームウェア更新フォーマットとコマンドコードの選択にどう使われるかは、wolfTPM ソースツリーの `examples/firmware/README.md` を参照してください。 + +!!! note + NVIDIA Jetson Orin のエントリに `Caps/Did/Vid/Rid` の行がないのは、これらの値が TIS バスレジスタから取得されるものであり、ファームウェアTPM にはそれがないためです。このエントリは `--enable-autodetect` で取得したもので、この場合 `wolfTPM2_Init_ex` はカーネルデバイスが開いた時点で戻るため、デバッグ行には到達しません。`--enable-devtpm` ビルドでは引き続きこの行が出力されますが、すべて 0 が読み取られます。`Fw 8216.1808` は `TPM_PT_FIRMWARE_VERSION_1` = `0x20180710` であり、この実装ではバージョン番号ではなくビルド日 (2018-07-10) を表すために使われています。仕様リビジョンは 1.62 で、4 つの PCR バンク (SHA-1、SHA-256、SHA-384、SHA-512) がすべて PCR 0 から 23 で割り当てられています。 + +## 関連項目 + +* [対応ハードウェア](supported-hardware.md) +* [API リファレンス](api-reference.md) +* [はじめに](getting-started.md) +* [プロジェクト構成](project-structure.md) diff --git a/docs/key-management.md b/docs/key-management.md new file mode 100644 index 00000000..adcc95ac --- /dev/null +++ b/docs/key-management.md @@ -0,0 +1,146 @@ +# Key Management + +wolfTPM includes example programs for creating TPM keys, storing them to disk as key blobs, importing external keys, and loading them back into a temporary TPM handle. This page walks through the key generation examples and lists the programs in `examples/keygen/` and the wrapper utilities in `examples/wrap/`. + +## Key generation overview + +The `keygen` example creates a TPM key under the storage key (SRK) and writes the key blob to disk. The `keyload` example reads that blob and loads it into a temporary TPM handle. + +```sh +$ ./examples/keygen/keygen keyblob.bin -rsa +TPM2.0 Key generation example +Loading SRK: Storage 0x81000200 (282 bytes) +Creating new RSA key... +Created new key (pub 280, priv 222 bytes) +Wrote 840 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 840 bytes from keyblob.bin +Loaded key to 0x80000001 + + +$ ./examples/keygen/keygen keyblob.bin -ecc +TPM2.0 Key generation example +Loading SRK: Storage 0x81000200 (282 bytes) +Creating new ECC key... +Created new key (pub 88, priv 126 bytes) +Wrote 744 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 744 bytes from keyblob.bin +Loaded key to 0x80000001 +``` + +Symmetric and keyed hash keys use the same flow: + +```sh +$ ./examples/keygen/keygen -sym=aescfb128 +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: SYMCIPHER + aescfb mode, 128 keybits + Template: Default + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Symmetric template +Creating new SYMCIPHER key... +Created new key (pub 50, priv 142 bytes) +Wrote 198 bytes to keyblob.bin + +$ ./examples/keygen/keyload +TPM2.0 Key load example + Key Blob: keyblob.bin + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 198 bytes from keyblob.bin +Reading the private part of the key +Loaded key to 0x80000001 + +$ ./examples/keygen/keygen -keyedhash +TPM2.0 Key generation example + Key Blob: keyblob.bin + Algorithm: KEYEDHASH + Template: Default + Use Parameter Encryption: NULL +Loading SRK: Storage 0x81000200 (282 bytes) +Keyed Hash template +Creating new KEYEDHASH key... +TPM2_Create key: pub 48, priv 158 +Public Area (size 48): + Type: KEYEDHASH (0x8), name: SHA256 (0xB), objAttr: 0x40460, authPolicy sz: 0 + Keyed Hash: scheme: HMAC (0x5), scheme hash: SHA256 (0xB), unique size 32 +TPM2_Load Key Handle 0x80000001 +New key created and loaded (pub 48, priv 158 bytes) +Wrote 212 bytes to keyblob.bin +``` + +When no filename is given, the default `keyblob.bin` is used. That means `keygen` and `keyload` can run without extra parameters for a quick demonstration. Use one of the `--help` switches to see the full list of algorithms and options `keygen` supports. + +The `keyimport` example takes a private key, wraps it as a TPM key blob and stores it to disk. It can then be loaded with `keyload`: + +```sh +$ ./examples/keygen/keyimport keyblob.bin -rsa +TPM2.0 Key import example +Loading SRK: Storage 0x81000200 (282 bytes) +Imported key (pub 278, priv 222 bytes) +Wrote 840 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 840 bytes from keyblob.bin +Loaded key to 0x80000001 + + +$ ./examples/keygen/keyimport keyblob.bin -ecc +TPM2.0 Key Import example +Loading SRK: Storage 0x81000200 (282 bytes) +Imported key (pub 86, priv 126 bytes) +Wrote 744 bytes to keyblob.bin + +$ ./examples/keygen/keyload keyblob.bin +TPM2.0 Key load example +Loading SRK: Storage 0x81000200 (282 bytes) +Reading 744 bytes from keyblob.bin +Loaded key to 0x80000001 +``` + +`keyload` takes only one argument, the filename of the stored key. It does not need to be told the key type because the RSA or ECC scheme is stored inside the key blob. + +To protect the authorization value while creating a key, add `-aes` or `-xor` to `keygen`. See [Examples Overview](examples-overview.md#parameter-encryption). + +## Programs (examples/keygen/) + +| Program | Description | +| --- | --- | +| `create_primary.c` | Creates and stores primary keys, including endorsement hierarchy keys such as the IAK and IDevID. | +| `keygen.c` | Creates a new RSA, ECC, symmetric or keyed hash key under the SRK and writes the key blob to disk. | +| `keyload.c` | Reads a key blob from disk and loads it into a temporary TPM handle. | +| `keyimport.c` | Imports an existing private key as a TPM key blob and writes it to disk. | +| `external_import.c` | Imports an external private key (built into the example) under the SRK. Use `-rsa` or `-ecc` for the SRK type, and `-load` to load the saved `keyblob.bin` to a third level key. | +| `ecdh.c` | ECDH key agreement using a TPM key, producing a shared secret. | + +## Wrapper utilities (examples/wrap/) + +| Program | Description | +| --- | --- | +| `wrap_test.c` | Exercises the `wolfTPM2_*` wrapper APIs. | +| `caps.c` | Reads and prints TPM capabilities. | +| `getrandom.c` | Gets random bytes from the TPM RNG. | +| `hash.c` | Hashes a message with a TPM hash sequence. | +| `hmac.c` | Computes an HMAC with a persistent TPM HMAC key, creating the key if it is not found. | +| `encrypt_decrypt.c` | Symmetric encrypt/decrypt round trip with a TPM key. | + +## Storing keys in NV + +Keys and secrets can also be stored in the TPM's NV memory, optionally with an encrypted authorization value. See [Sealing and NVRAM](sealing-and-nvram.md). + +## See Also + +* [Examples Overview](examples-overview.md) +* [Sealing and NVRAM](sealing-and-nvram.md) +* [Attestation](attestation.md) diff --git a/docs/management-and-gpio.md b/docs/management-and-gpio.md new file mode 100644 index 00000000..64f55512 --- /dev/null +++ b/docs/management-and-gpio.md @@ -0,0 +1,137 @@ +# Management and GPIO + +This page covers the small TPM management utilities in `examples/management/` and the GPIO control examples in `examples/gpio/`. + +## Management utilities + +| Program | Purpose | +|---------|---------| +| `da_check.c` | Dictionary attack (DA) lockout check. Exercises a DA-protected key and a noDA key, enters lockout with repeated bad authorization, and recovers with a lockout reset. | +| `flush.c` | Flushes transient and persistent handles. Run with a handle (for example `0x80000000`) to free that object; with no parameters it flushes common transient objects (transient keys, policy sessions and HMAC sessions). | +| `tpmclear.c` | Runs `TPM2_Clear` to clear a hierarchy. | + +```sh +./examples/management/da_check +./examples/management/flush [handle] +./examples/management/tpmclear +``` + +!!! warning + `tpmclear` clears the TPM. Keys and data held under the cleared hierarchy are lost. + +## GPIO control + +Some TPM 2.0 modules have extra I/O functions and additional GPIO that a developer can use. The extra GPIO can signal other subsystems about security events or system states. + +!!! note + The GPIO control examples support only ST33 and NPCT75x TPM 2.0 modules. + +There are three programs in `examples/gpio/`: + +| Program | Purpose | +|---------|---------| +| `gpio_config.c` | Configures a GPIO. | +| `gpio_set.c` | Sets a configured GPIO high or low. | +| `gpio_read.c` | Reads the level of a configured GPIO. | + +Every example has a help option `-h`. Run `gpio_config -h` to see the GPIO modes. Demo usage runs when no parameters are supplied. Choose options carefully, because GPIO interact with the physical world. + +### GPIO config (ST33) + +ST33 supports 6 modes. Help output from `gpio_config`: + +```sh +$ ./examples/gpio/gpio_config -h +Expected usage: +./examples/gpio/gpio_config [num] [mode] +* num is a GPIO number between 0-3 (default 0) +* mode is a number selecting the GPIO mode between 0-6 (default 3): + 0. standard - reset to the GPIO's default mode + 1. floating - input in floating configuration. + 2. pullup - input with pull up enabled + 3. pulldown - input with pull down enabled + 4. opendrain - output in open drain configuration + 5. pushpull - output in push pull configuration + 6. unconfigure - delete the NV index for the selected GPIO +Example usage, without parameters, configures GPIO0 as input with a pull down. +``` + +Configure a GPIO as an output: + +```sh +$ ./examples/gpio/gpio_config 0 5 +GPIO num is: 0 +GPIO mode is: 5 +Example how to use extra GPIO on a TPM 2.0 modules +Trying to configure GPIO0... +TPM2_GPIO_Config success +NV Index for GPIO access created +``` + +Configure a GPIO as an input with a pull down (mode 3): + +```sh +$ ./examples/gpio/gpio_config 0 3 +GPIO num is: 0 +GPIO mode is: 3 +Demo how to use extra GPIO on a TPM 2.0 modules +Trying to configure GPIO0... +TPM2_GPIO_Config success +NV Index for GPIO access created +``` + +### GPIO config (NPCT75xx) + +NPCT75x supports 3 output modes and no input modes. Help output from `gpio_config`: + +```sh +$ ./examples/gpio/gpio_config -h +Expected usage: +./examples/gpio/gpio_config [num] [mode] +* num is a GPIO number between 3 and 4 (default 3) +* mode is either push-pull, open-drain or open-drain with pull-up + 1. pushpull - output in push pull configuration + 2. opendrain - output in open drain configuration + 3. pullup - output in open drain with pull-up enabled + 4. unconfig - delete NV index for GPIO access +Example usage, without parameters, configures GPIO3 as push-pull output. +``` + +NPCT75x GPIO numbering starts from GPIO3, while ST33 starts from GPIO0. + +```sh +$ ./examples/gpio/gpio_config 4 1 +Example for GPIO configuration of a NPTC7xx TPM 2.0 module +GPIO number: 4 +GPIO mode: 1 +Successfully read the current configuration +Successfully wrote new configuration +NV Index for GPIO access created +``` + +### GPIO usage + +Switching a GPIO configuration works as follows: + +- For ST33, `gpio_config` deletes the existing NV index, so a new GPIO configuration can be chosen. +- For NPCT75xx, `gpio_config` can reconfigure any GPIO without deleting the created NV index. + +Once configured, set and read the GPIO: + +```sh +$ ./examples/gpio/gpio_set 0 -high +GPIO0 set to high level + +$ ./examples/gpio/gpio_set 0 -low +GPIO0 set to low level + +$ ./examples/gpio/gpio_read 0 +GPIO0 is Low +``` + +## See Also + +- [Sealing and NVRAM](sealing-and-nvram.md) +- [TLS and certificates](tls-and-certificates.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/post-quantum.md b/docs/post-quantum.md new file mode 100644 index 00000000..95afda04 --- /dev/null +++ b/docs/post-quantum.md @@ -0,0 +1,286 @@ +# Post-Quantum Cryptography + +wolfTPM adds support for the post-quantum algorithms introduced in TCG TPM 2.0 Library Specification v1.85. The client library marshals the new v1.85 commands to a TPM. When the target is the in-tree firmware TPM, that server performs the algorithms with wolfCrypt's FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA) modules; when the target is a hardware TPM such as SEALSQ QVault, the device performs them on-chip. This page covers the supported algorithms, how to build with them, and the PQC examples shipped in `examples/pqc`. + +## Overview + +Supported algorithms: + +| Algorithm | Standard | Parameter sets | +|---|---|---| +| ML-DSA (signing) | FIPS 204 | ML-DSA-44 / 65 / 87 | +| HashML-DSA (pre-hash signing) | FIPS 204 | ML-DSA-44 / 65 / 87 with caller hash | +| ML-KEM (key encapsulation) | FIPS 203 | ML-KEM-512 / 768 / 1024 | + +wolfTPM supports the SEALSQ QVault TPM, which SEALSQ positions as the first TPM 2.0 device with these v1.85 PQC algorithms in silicon. SEALSQ describes QVault TPM-185 engineering samples as available, so check with SEALSQ for current production and certification status. The same PQC API also runs against the in-tree fwTPM server, which is useful for CI or when no hardware is present. For measured ML-DSA and ML-KEM performance on QVault TPM silicon, see the Benchmarks section at the end of this page. + +## Building + +### wolfSSL + +wolfSSL provides ML-DSA and ML-KEM in wolfCrypt: + +```sh +./configure --enable-wolftpm --enable-pkcallbacks --enable-keygen \ + --enable-mldsa --enable-mlkem \ + --enable-harden CFLAGS="-DWC_RSA_NO_PADDING" +make +sudo make install +``` + +For the PQC TLS 1.3 demo described below, also add `--enable-tls-mlkem-standalone`. The standalone option is required for the standalone `ML_KEM_*` TLS groups; without it wolfSSL only offers the hybrid groups and `wolfSSL_UseKeyShare` rejects the client default. The `gen_pqc_certs` tool needs certificate generation, which `--enable-wolftpm` already enables, and `--enable-wolftpm` also provides the crypto callback and private-key-id support the TLS server uses. Keep `--enable-pkcallbacks`, which is a separate wolfSSL option. The demo needs wolfSSL 5.9.4-stable or later. + +### fwTPM (software TPM) + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-pqc +make +``` + +`--enable-swtpm` builds `fwtpm_server` with the mssim socket transport on `127.0.0.1:2321` that the examples below connect to. On Linux x86_64 and AArch64 the socket transport is already the default, so the flag is what makes the socket server reliable on every platform. The fwTPM server uses the full v1.85 command set, so configure promotes `--enable-pqc` to `--enable-v185`. If you omit both PQC flags and wolfCrypt has ML-DSA and ML-KEM, configure auto-enables v1.85. Pass `--disable-pqc` to opt out explicitly. + +### Hardware TPM: SEALSQ QVault + +SEALSQ QVault is the hardware TPM currently supported for v1.85 PQC: + +```sh +./configure --enable-sealsq --enable-pqc +make +``` + +On Linux, add `--enable-devtpm` to use the kernel TPM driver. For examples that pass transient handles between processes, also add `CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm0"'`. The default `/dev/tpmrm0` virtualizes and discards those handles when a process closes the device. Keep the inner double quotes literal inside the single-quoted `CFLAGS` value. + +`--enable-pqc` builds the lean ML-DSA and ML-KEM subset (`WOLFTPM_PQC`) for hardware. Use `--enable-v185` (`WOLFTPM_V185`) for the full v1.85 command set. + +Non-SHA-1 TPM examples include: + +```sh +./examples/pqc/pqc_ctrl --caps --algs +./examples/pqc/pqc_ctrl --mldsa=65 --mlkem=768 +./examples/wrap/hash "wolfTPM" -sha256 +``` + +### Trimming the PQC footprint + +To compile only the operations you call (a smaller binary, with the unused code paths removed), mirror the wolfSSL flags: + +```sh +# ML-DSA verify-only + ML-KEM encapsulate-only (no sign, no decapsulate) +./configure --enable-pqc --enable-mldsa=verify-only --enable-mlkem=enc +``` + +| Flag | Values | Drops | +|------|--------|-------| +| `--enable-mldsa` | `all` (default) / `sign-only` / `verify-only` / `no` | the unselected ML-DSA operation | +| `--enable-mlkem` | `all` (default) / `enc` / `dec` / `no` | the unselected ML-KEM operation | +| `--disable-hash-mldsa` | none | pre-hash ML-DSA key support | + +These map to `WOLFTPM_NO_MLDSA_SIGN`, `WOLFTPM_NO_MLKEM_DECAP`, and similar defines, which embedded integrators can also pass directly via `CFLAGS` without autotools. Existing `--enable-v185` builds are unaffected (every operation defaults on). Disabling both algorithms (`--enable-mldsa=no --enable-mlkem=no`) is a configure error. Use `--disable-pqc` to build without any post-quantum support. Trimming removes code paths and shrinks the binary; it does not reduce the public TPM2B buffer maximums, which stay sized for the largest v1.85 parameter set. + +The same flags also trim the fwTPM server: `--enable-fwtpm --enable-mldsa=verify-only` compiles out the ML-DSA sign command handlers, dispatch entries, and crypto. ML-KEM is controlled separately and stays at its default of `all`, so to build a server whose PQC surface is only ML-DSA verify, also pass `--enable-mlkem=no`. fwTPM always builds the full v1.85 spec surface, so the trims apply on top of `WOLFTPM_V185`. + +!!! note + Trimming does not make the examples allocation-free; they still allocate signature and ciphertext buffers with `XMALLOC`. fwTPM has a separate `WOLFTPM2_NO_HEAP` option that moves all buffers to the stack, at the cost of much larger stack use. See [fwTPM Building](fwtpm/building.md) for details. + +## Running the examples + +```sh +make check +``` + +With the fwTPM build above, `make check` runs the software-TPM suite, including PQC coverage: + +- `tests/fwtpm_unit.test`: 30+ in-process PQC handler tests +- `tests/fwtpm_check.sh`: starts the server, then runs `tests/unit.test` (PQC wrapper tests over the mssim socket such as ML-DSA Sign/Verify Sequence, ML-KEM Encap/Decap, and EncryptSecret ML-KEM) and `examples/run_examples.sh`, and runs the tpm2-tools suite when the socket transport is enabled and tpm2-tools is installed +- `tests/fwtpm_da_retry.sh`: dictionary attack retry check (needs a build with `-DFWTPM_DA_USED_RETRY`) + +`make check` does not run `tests/pqc_mssim_e2e.sh`. Run that script directly for a fast, PQC-focused end-to-end check: + +```sh +./tests/pqc_mssim_e2e.sh +``` + +With an fwTPM build, start `fwtpm_server` once in a separate terminal and leave it running while you run the individual examples below (including the TLS demo). It listens on `127.0.0.1:2321`. A SEALSQ build uses its configured hardware transport instead. The `--clear` flag below deletes the fwTPM NV state file before starting, which gives the examples a clean TPM; use it only on a disposable test instance, and omit it to keep an existing fwTPM's persistent state. + +```sh +# separate terminal; leave this running +./src/fwtpm/fwtpm_server --clear +``` + +For the fwTPM server's PQC internals (the eight v1.85 commands, primary-key derivation, buffer constants, and spec-interpretation decisions), see [docs/FWTPM.md](fwtpm/overview.md). + +## Examples + +### pqc_ctrl + +`pqc_ctrl` is a single CLI to drive and validate a PQC TPM (SEALSQ QVault TPM, or the fwTPM). Each command runs an operation against the TPM. Every key operation flushes the transient object table first, so a TPM with a small object memory (such as the SEALSQ QVault TPM) does not hit `TPM_RC_OBJECT_MEMORY` when commands are chained. + +```sh +./examples/pqc/pqc_ctrl # --all (default) +./examples/pqc/pqc_ctrl --caps --algs # identify + list supported algorithms +./examples/pqc/pqc_ctrl --mldsa=87 # ML-DSA-87 sign/verify +./examples/pqc/pqc_ctrl --mlkem=1024 # ML-KEM-1024 encap/decap +./examples/pqc/pqc_ctrl --selftest --getrandom=32 --pcrread=0 +``` + +| Command | Description | +|---|---| +| `--caps` | Manufacturer, vendor string, firmware, FIPS mode | +| `--algs` | List the algorithms the TPM reports as supported | +| `--selftest` | `TPM2_SelfTest` | +| `--getrandom[=N]` | N random bytes (default 16) | +| `--pcrread[=idx]` | Read a PCR (SHA-256 bank, falling back to SHA-384) | +| `--pcrextend=idx` | Extend a PCR with a test digest (explicit index required) | +| `--flush` | Flush all loaded transient objects between operations | +| `--clear` | `TPM2_Clear`: installs a new Storage primary seed, deletes Storage and Endorsement objects and non-platform NV, and resets owner, endorsement, and lockout auth | +| `--mldsa[=44/65/87]` | Pure ML-DSA sign/verify (default 65) | +| `--hash-mldsa[=44/65/87]` | HashML-DSA (SHA-256 pre-hash) sign/verify | +| `--mlkem[=512/768/1024]` | ML-KEM encapsulate/decapsulate | +| `--all` | caps + algs + selftest + getrandom + pcrread + every PQC set | + +Commands run left to right, so they can be chained. The functional `pqc_ctrl` builds only from an untrimmed PQC configuration: the wrapper plus both ML-DSA operations, both ML-KEM operations, and HashML-DSA. Build with `--enable-v185` (or `--enable-pqc`); a trimmed build such as `--enable-mldsa=verify-only` compiles out the CLI. Point it at the SEALSQ part with `--enable-sealsq`, or at the fwTPM with `--enable-fwtpm --enable-swtpm`. + +`pqc_ctrl.sh` runs the whole command set as a pass/fail suite (it mirrors `examples/spdm/spdm_test.sh`) when the device supports all parameter sets. The persistent state changes (the PCR 16 extend and `TPM2_Clear`) are opt-in via `PQC_CTRL_CLEAR=1`. The default run still flushes loaded transient objects, and every key operation flushes the transient object table, so do not run it alongside a workload whose transient TPM handles must stay valid: + +```sh +./examples/pqc/pqc_ctrl.sh +PQC_CTRL_CLEAR=1 ./examples/pqc/pqc_ctrl.sh # also extend PCR 16 and run TPM2_Clear +``` + +!!! warning + `PQC_CTRL_CLEAR=1` does two things, not one. It first extends PCR 16, which cannot be undone without resetting the PCR, and then runs `TPM2_Clear`. `TPM2_Clear` installs a new Storage primary seed, so every key blob and sealed object protected by the old seed is permanently unusable afterward, and a file backup does not restore them. Use it only on a disposable test TPM. + +### pqc_mssim_e2e + +End-to-end client test over the mssim socket. It runs four checks in sequence: + +1. ML-KEM-768 `CreatePrimary`, `Encapsulate`, and `Decapsulate`. It asserts the ciphertext is 1088 bytes and the two shared secrets are byte-identical. +2. HashML-DSA-65 (SHA-256) `CreatePrimary`, `SignDigest`, and `VerifyDigestSignature`. It asserts the signature is 3309 bytes and the validation ticket tag is `TPM_ST_DIGEST_VERIFIED`. +3. An ML-KEM `MakeCredential` and `ActivateCredential` round-trip. +4. An ML-DSA `Quote`. + +```sh +./examples/pqc/pqc_mssim_e2e +``` + +### mlkem_encap + +ML-KEM encapsulation round-trip. It creates a primary ML-KEM key, runs `Encapsulate`, then runs `Decapsulate` on the produced ciphertext and confirms the shared secrets match. + +```sh +./examples/pqc/mlkem_encap # default: ML-KEM-768 +./examples/pqc/mlkem_encap -mlkem=512 +./examples/pqc/mlkem_encap -mlkem=1024 +``` + +### mldsa_sign + +Pure ML-DSA sign and verify round-trip. It creates a primary ML-DSA key and signs a fixed message via `SignSequenceStart` and `SignSequenceComplete`. Pure ML-DSA sequences are streamable, so the message could also be fed through `SequenceUpdate`; this example passes it whole on the Complete buffer for signing. It then verifies via `VerifySequenceStart`, `VerifySequenceUpdate`, and `VerifySequenceComplete`. It asserts the returned validation ticket tag is `TPM_ST_MESSAGE_VERIFIED`. + +```sh +./examples/pqc/mldsa_sign # default: ML-DSA-65 +./examples/pqc/mldsa_sign -mldsa=44 +./examples/pqc/mldsa_sign -mldsa=87 +``` + +### PQC keys via keygen and keyload + +`examples/keygen/keygen` accepts v1.85 PQC options alongside `-rsa`, `-ecc`, `-sym`, and `-keyedhash`: + +```sh +./examples/keygen/keygen keyblob.bin -mldsa=65 # Pure ML-DSA +./examples/keygen/keygen keyblob.bin -hash_mldsa=65 # SHA-256 pre-hash +./examples/keygen/keygen keyblob.bin -mlkem=768 # ML-KEM +``` + +Parameter sets: + +- `-mldsa=44|65|87` (default 65) +- `-hash_mldsa=44|65|87` (default 65, SHA-256 pre-hash) +- `-mlkem=512|768|1024` (default 768) + +Verify that the produced blob round-trips through `TPM2_Create` and `TPM2_Load` by loading it back: + +```sh +./examples/keygen/keyload keyblob.bin +``` + +A successful load prints a transient key handle. The full matrix (three variants times three parameter sets, nine key configurations, each run through keygen and keyload) is exercised by `examples/run_examples.sh` when v1.85 is detected in `config.h`. That generic suite also covers non-PQC operations with their own TPM requirements. + +### PQC keys for parameter encryption + +A post-quantum primary can key a TPM 2.0 parameter-encryption session. ML-KEM (decrypt capable) is used as the session salt key and ML-DSA (sign only) as the session bind key. The session protects the command's first sized parameter the same way an RSA or ECC salted session does. Any RSA or ECC storage key the example needs (for example the parent of a created child) is unchanged. + +!!! note + Parameter-encryption confidentiality comes from the session key, which a bound session derives from the bind entity's authValue (TPM 2.0 Library Part 1, Salted Session). A sign-only ML-DSA key cannot exchange a salt, and the example's bind authValue is a public constant, so an ML-DSA bind alone provides session binding but no confidentiality against a bus observer. To keep the advertised encryption real, the helper also creates a transient SRK and uses it as the asymmetric salt for the ML-DSA session: confidentiality comes from the encrypted salt while the ML-DSA key supplies the binding. A real deployment that relies on a bare bound session for confidentiality must use a bind entity whose authValue is secret and was not sent in cleartext. + +`wrap_test`, `pcr/quote`, `nvram/store`, and `nvram/counter` take `-mlkem[=512|768|1024]` and `-mldsa[=44|65|87]`. `keygen` uses `-paramkey=mlkem[=...]` and `-paramkey=mldsa[=...]` because its `-mlkem` and `-mldsa` options already select the child key algorithm. + +```sh +./examples/wrap/wrap_test -aes -mlkem=768 +./examples/pcr/quote 16 quote.blob -ecc -xor -mldsa=65 +./examples/nvram/counter -aes -mldsa=65 +./examples/keygen/keygen keyblob.bin -ecc -aes -paramkey=mlkem=768 +``` + +ML-KEM is a restricted decryption (salt) key, which requires a symmetric definition. The example helper sets AES-128-CFB on it, because a TPM rejects a restricted key with no symmetric algorithm via `TPM_RC_SYMMETRIC`. + +### create_primary with an ML-DSA primary + +`examples/keygen/create_primary` can create an ML-DSA primary key: + +```sh +./examples/keygen/create_primary -mldsa # default ML-DSA-65 +./examples/keygen/create_primary -mldsa=87 -oh +``` + +### Post-Quantum TLS 1.3 (ML-KEM and TPM ML-DSA) + +This is a full TLS 1.3 handshake where the server's ML-DSA identity key lives in the TPM. The server signs the CertificateVerify inside the TPM via the wolfTPM crypto callback. On a hardware TPM such as QVault this signing happens on-chip; the commands below drive the software fwTPM. The client performs an ML-KEM key exchange and validates the server against a software CA. + +It requires a wolfSSL that routes `wc_MlDsaKey_SignCtx` to the crypto callback for device keys (private key in the TPM). That change is in wolfSSL 5.9.4-stable and later. A development snapshot must contain wolfSSL commit `6b0c832284286dbaec8e5ab35581ff470e90826b`. The commands below reuse the `fwtpm_server` you started earlier. + +!!! warning + This is a demo. The identity key is an unauthenticated deterministic TPM primary (empty auth), reproducible by both `gen_pqc_certs` and the server from the owner hierarchy. A primary's key material is derived from the hierarchy seed and the creation inputs, and an object auth value does not change that derivation. Adding a non-empty auth value or policy alone therefore does not stop another caller who can authorize `CreatePrimary` under the owner hierarchy from recreating the same key. For production, prefer a provisioned child or persistent identity object together with controlled hierarchy authorization. The client validates the server chain against the demo CA but does not bind the certificate to the host name, so the demo connects to the default localhost and does not pass `-h=`. Supplying `-h=` turns on strict verification including `wolfSSL_check_domain_name`, which this leaf cannot satisfy. A production deployment should issue the leaf with a matching subjectAltName. + +Three programs are involved: + +- `examples/pqc/gen_pqc_certs` makes a software ML-DSA CA and a device leaf cert whose subject key is the TPM ML-DSA key. +- `examples/tls/tls_server -mldsa` recreates that TPM key and serves TLS 1.3. +- `examples/tls/tls_client -mldsa` connects, does the ML-KEM key exchange, and verifies the CA. + +```sh +# the fwtpm_server from "Running the examples" is already listening on 127.0.0.1:2321 + +# 1. certificate chain bound to the TPM key (-mldsa must match the server) +./examples/pqc/gen_pqc_certs -mldsa=65 + +# 2. server (same -mldsa as gen_pqc_certs) +./examples/tls/tls_server -p=11111 -mldsa=65 & + +# 3. client (choose the ML-KEM group) +./examples/tls/tls_client -p=11111 -mldsa -group=ML_KEM_768 +``` + +Options: + +- `gen_pqc_certs -mldsa=44/65/87`: ML-DSA parameter set. +- `tls_server -p= -mldsa=44/65/87`. +- `tls_client -h= -p= -group=`, where `` is `ML_KEM_512/768/1024` or a hybrid `SECP256R1MLKEM768` / `X25519MLKEM768` (hybrids need the matching classical curve enabled in wolfSSL). + +The one-shot end-to-end test drives all three and asserts the ML-KEM group, TPM-signed ML-DSA authentication, and CA verification: + +```sh +ENABLE_PQC_TLS=1 ./examples/run_examples.sh # includes the PQC TLS matrix +``` + +## Benchmarks + +Measured ML-DSA and ML-KEM latencies on SEALSQ QVault TPM silicon (key generation, sign, verify, encapsulate, decapsulate), taken with `examples/bench/bench`, are in [benchmarks.md](benchmarks.md). Key generation is a one-off provisioning cost. See that page for how the ML-DSA and ECDSA figures were captured before comparing them. + +## See Also + +- [benchmarks.md](benchmarks.md) +- [FWTPM.md](fwtpm/overview.md) +- [DEVTPM.md](system-interfaces.md) +- [spdm.md](spdm.md) diff --git a/docs/project-structure.md b/docs/project-structure.md new file mode 100644 index 00000000..8137ad01 --- /dev/null +++ b/docs/project-structure.md @@ -0,0 +1,75 @@ +# Project Structure + +This page lists the top-level directories of the wolfTPM source tree and the purpose of each, with notes on the firmware TPM and SPDM subdirectories and the library headers. + +## Source tree + +``` +wolfTPM/ + src/ TPM 2.0 core library and wrappers + fwtpm/ firmware TPM (fwTPM) server + spdm/ SPDM responder and vendor adapters + wolftpm/ public headers + fwtpm/ fwTPM headers + spdm/ SPDM headers + examples/ example applications + hal/ tpm_io_* IO callback backends + tests/ unit and API tests + IDE/ IDE and board projects + docs/ this manual and the Doxyfile + certs/ example keys and certificates + cmake/ CMake support files + m4/ autoconf macros + scripts/ test and helper scripts + tools/ documentation and SBOM tooling + wrapper/ language wrappers + zephyr/ Zephyr module +``` + +## Directory purposes + +| Directory | Purpose | +| --- | --- | +| `src/` | TPM 2.0 core (`tpm2.c`, `tpm2_packet.c`, `tpm2_tis.c`, `tpm2_param_enc.c`, `tpm2_crypto.c`, `tpm2_asn.c`) and the wrapper API (`tpm2_wrap.c`). | +| `src/fwtpm/` | The firmware TPM server (`fwtpm_server`): command handling, crypto, NV storage and IO. | +| `src/spdm/` | The SPDM responder and the vendor adapters. | +| `wolftpm/` | Public headers, including `tpm2.h`, `tpm2_wrap.h` and `tpm2_types.h`. | +| `wolftpm/fwtpm/` | Public headers for the fwTPM server. | +| `wolftpm/spdm/` | Public headers for SPDM (`spdm.h`, `spdm_tcg.h`, `spdm_psk.h`, `spdm_responder.h` and the vendor headers). | +| `examples/` | Example applications for the native and wrapper APIs. | +| `hal/` | IO callback backends (`tpm_io_*`) for Atmel, Barebox, Espressif, Infineon, Linux, Microchip, MMIO, QNX, ST, U-Boot, wolfHAL, Xilinx, Zephyr and fwTPM. | +| `tests/` | Unit tests and API tests. | +| `IDE/` | Projects for STM32CUBE, Espressif, QNX, IAR-EWARM and VisualStudio. | +| `docs/` | This manual and the Doxygen configuration (`Doxyfile`). | +| `certs/` | Example keys and certificates used by the examples and tests. | +| `cmake/` | CMake support files. | +| `m4/` | Autoconf macros. | +| `scripts/` | Test and helper scripts. | +| `tools/` | Documentation tooling and the SBOM generator (`tools/sbom`). | +| `wrapper/` | Language wrappers: `rust` and `CSharp`. | +| `zephyr/` | Zephyr integration. | + +## Library layout + +wolfTPM header files are located in the following locations: + +| Library | Header location | +| --- | --- | +| wolfTPM | `wolftpm/` | +| wolfSSL | `wolfssl/` | +| wolfCrypt | `wolfssl/wolfcrypt` | + +The general header file that should be included from wolfTPM is shown below: + +```c +#include +``` + +Every example application that is included with wolfTPM includes the `tpm_io.h` header file, located in `hal/`. The `tpm_io.c` file sets up the example HAL IO callback necessary for testing and running the example applications with a Linux Kernel, STM32 CubeMX HAL or Atmel/Microchip ASF. The reference is easily modified, such that custom IO callbacks or different callbacks may be added or removed as desired. + +## See Also + +* [Building](building.md) +* [Build Options](build-options.md) +* [fwTPM Overview](fwtpm/overview.md) +* [SPDM Attestation](spdm.md) diff --git a/docs/release-notes.md b/docs/release-notes.md new file mode 100644 index 00000000..06af8969 --- /dev/null +++ b/docs/release-notes.md @@ -0,0 +1,146 @@ +# Release Notes + +This page tracks recent wolfTPM releases. It reproduces the Unreleased section and the two most recent releases from the repository ChangeLog. The complete history, back to the first release, is in [ChangeLog.md](https://github.com/wolfSSL/wolfTPM/blob/master/ChangeLog.md) at the top of the repository. + +## Unreleased + +* Added `wolfTPM2_AllocatePCRBanks` for changing which PCR banks a TPM allocates. + - Added `examples/pcr/allocate` to report and re-provision the banks. + - Fixed the fwTPM applying the allocation immediately instead of at the next + `Startup(CLEAR)` per TPM 2.0 Part 3 22.5, accepting a selection that would + leave it with no PCR banks, ignoring the `pcrSelect` bitmap, and reporting + no allocated banks after a restart against an existing NV file. + +## wolfTPM Release 4.2.0 (Sep 14, 2026) + +**Summary** + +Feature and maintenance release centered on TCG TPM 2.0 v1.85 specification +compliance in the firmware TPM (fwTPM), expanded post-quantum support, and new +platform backends. Highlights: a broad set of fwTPM v1.85 compliance fixes +(command attributes, PolicyAuthorize, context-blob authentication, NV +authorization, ticket HMAC ordering), plus SPDM responder corrections; +ML-DSA authentication for post-quantum TLS 1.3 and SealSQ QVault post-quantum +TPM support; wolfHAL I2C/SPI backends and NVIDIA Jetson Orin OP-TEE fwTPM +support; ST33 firmware-update corrections; transport and NV/hash performance +improvements; and extensive security hardening (Coverity, static analysis, and +negative tests). + +**Detail** + +* Firmware TPM (fwTPM) TCG v1.85 specification compliance + - Command-code masking and vendor-bit return-code fix (PR #556) + - Corrected auth-entry handling (PR #566) + - PolicyAuthorize compliance fixes and corrected response codes for the + keySign name ticket and approvedPolicy (PRs #567, #572) + - Authenticate object context blobs on ContextSave/ContextLoad (PR #568) + - Reject unsupported LoadExternal private types, fix creation-ticket HMAC + ordering, and validate ML-DSA / ML-KEM templates in LoadExternal and + CreateLoaded (PRs #573, #578) + - Validate NV space authorization and report the v1.85 revision (PR #575) + - Fix hierarchy and policy-authorization gaps and SPDM responder version + negotiation (PR #577) + - Correct command-attribute reporting and the verified-ticket HMAC algorithm + (PR #579) + - Additional TCG v1.85 fwTPM and SPDM compliance fixes (PR #584) +* Post-quantum and TLS + - TPM-backed ML-DSA authentication for post-quantum TLS 1.3, with an example + and tests (PR #559) + - SealSQ QVault post-quantum TPM support (PR #570) + - ML-KEM credential activation and ML-DSA quotes in the fwTPM (PR #592) +* New platform and HAL support + - wolfHAL I2C and SPI backends, enabled with `--enable-wolfhal` and an + application-supplied `board.h` (PR #562) + - NVIDIA Jetson Orin (Tegra234) OP-TEE firmware TPM, reached through the + Linux TPM kernel driver as `/dev/tpmrm0` (PR #576) + - Finer per-command-group gating macros in the fwTPM (PR #574) + - Caller-supplied policy authorization for firmware upgrade (PR #560) +* ST33 firmware update + - Fix Generation 1 manifest size and refuse oversized commands (PR #583) + - Select ST33 field-upgrade commands from the TPM command set (PR #586) +* Performance + - Reuse transport connections and reduce NV-write and hash-cache overhead + (PR #563) +* Security hardening (Coverity, static analysis, input validation) + - Harden the crypto callback, ASN.1 parsing, parameter encryption, and + marshalling, with negative tests (PR #551) + - Bound the TPM2 response decrypt-parameter size, zeroize primary-key auth, + and expand marshalling/import test coverage (PR #555) + - Guard a tainted PCR-select copy in the fwTPM properties path (PR #558) + - Fix a fwTPM response buffer overflow and an SPDM clear-frame command bypass + (PR #561) + - Harden wolfTPM2 PCR/hash wrapper validation (PR #554) + - Strengthen TPM input validation and memory handling (PR #565) + - Fix a wolfCrypt refcount race in P521 primary derivation and a policy-session + authorization bypass (PR #571) + - Harden PCR policy bounds checks (PR #581) + - Harden wolfTPM validation and data handling (PR #582) + - Harden fwTPM protocol handling and SPDM authentication (PR #588) + - Make fwTPM state changes transactional and harden PolicyPCR and + private-blob wrapping (PR #593) + - Additional Coverity fixes across the TPM bounds and configuration paths, + including bounded fwTPM child-blob copies, a guarded public-name buffer + allocation, and restricted unsealed-output file permissions + (PRs #591, #595, #603, #605) + - Harden fwTPM key derivation and command validation (PR #596) + - Fix TPM2 core key-import parsing and response handling and improve core + zeroization and robustness (PRs #597, #600) + - Harden error handling and secret zeroization in the examples, SPI transfer, + and SPDM version parsing (PRs #598, #599, #604) + - Reject truncated fwTPM Rewrap input, require bound authorization for policy + sessions over empty-policy objects, bind the full keyed-hash secret into the + public name, fail public-area parsing on overflow, normalize the TIS + locality return, and clear residual request bytes from the shared command + buffer (PR #608) +* Build fixes + - Fix AES_BLOCK_SIZE undeclared under OPENSSL_COEXIST wolfSSL (PR #552) + - Fix an edge-case build with TIS lock and no wolfCrypt (PR #564) + - Fix the --enable-pqc build with --disable-wolfcrypt (PR #606) + - Refresh the expired wolfSSL example CA certificates and add a refresh + script (PR #601) +* Documentation and licensing + - Add contribution guidance (CONTRIBUTING.md) (PR #569) + - GPLv2 exception to the base GPLv3 license: wolfTPM combined with U-Boot + from Cisco Systems, Inc. may be licensed under GPLv2 (PR #557) + +## wolfTPM Release 4.1.0 (Jul 10, 2026) + +**Summary** + +Feature release centered on TPM locality control and expanded post-quantum support. Highlights: runtime locality selection (`wolfTPM2_SetLocality`) with a corrected fwTPM per-PCR locality enforcement table and an optional GPIO nRST reset HAL; TPM 2.0 v1.85 post-quantum (ML-DSA / ML-KEM) support brought into the firmware TPM with fine-grained build macros; fwTPM Dictionary Attack hardening, transparent `TPM_RC_RETRY` handling, and SPDM secured transport for the fwTPM; FIPS 140-3 capability reporting; freestanding (no-libc) build support; SBOM (CycloneDX / SPDX) generation for EU Cyber Resilience Act (CRA) compliance; and extensive security hardening (Coverity, CodeQL). + +**Detail** + +* Runtime TPM locality control (PR #546) + - New `wolfTPM2_SetLocality(dev, locality)` selects locality 0-4 at runtime, and `examples/pcr/reset` takes a `-loc=n` flag. Works on the built-in TIS/SPI driver (with release-and-retry for non-preempting chips) and the fwTPM over both socket and TIS/SHM; returns `NOT_COMPILED_IN` where locality is not selectable (I2C, Linux kernel driver, Windows TBS) + - fwTPM per-PCR locality enforcement replaced with one source-of-truth table (TCG PC Client profile): corrects the reset map, adds the missing PCR-extend check, and reports proper `RESET_L*`/`EXTEND_L*`/`DRTM_RESET` bitmaps. Behavior change: DRTM PCRs 17-22 can no longer be extended from locality 0 (now `TPM_RC_LOCALITY`) + - Fixed `TPM_CAP_ALGS`/`TPM_CAP_COMMANDS` paging to honor the property cursor so clients that follow `moreData` make progress + - Optional hardware-reset HAL: `--enable-hal-reset[=LINE]` adds `TPM2_IoCb_Reset()`, pulsing the nRST line via the Linux GPIO char device (default ST33 GPIO24, Nuvoton GPIO4) +* TPM 2.0 v1.85 post-quantum (PQC) support in the fwTPM: ML-DSA sign/verify, ML-KEM encap/decap, and seed handling to TCG Phase B, with PQC CI and fuzz coverage (PR #445) + - Fine-grained build macros to trim the footprint: `WOLFTPM_PQC` (the new lean `--enable-pqc`), per-algorithm `WOLFTPM_MLDSA`/`WOLFTPM_MLKEM`, and per-operation gates, plus `--enable-mldsa[=...]` / `--enable-mlkem[=...]` / `--disable-hash-mldsa` (PRs #527, #533) + - wolfSSL v5.8.0+ PQC floor and upstream-drift CI; ML-DSA `TPM2_CreateLoaded` primary and PQC parameter encryption in the examples; new `_ex` session/OAEP/PQC-hash wrappers (PRs #501, #509, #531, #539, #520) +* fwTPM Dictionary Attack (DA) hardening to the TCG spec (PR #541): `noDA` honored on objects, `failedTries` persisted with the non-orderly-shutdown penalty, `recoveryTime`/`lockoutRecovery` self-heal, and DA properties reported via `TPM2_GetCapability`. Adds `wolfTPM2_DictionaryAttackLockReset`/`wolfTPM2_DictionaryAttackParameters`, an `examples/management/da_check` example, and the `tests/fwtpm_da_retry.sh` harness +* Optional transparent `TPM_RC_RETRY` handling for TPMs that momentarily report busy; opt in via `TPM2_SetCommandRetries` or `-DWOLFTPM_MAX_RETRIES=N`, or compile out with `WOLFTPM_NO_RETRY` (PR #537) +* SPDM secured transport extended to the fwTPM (PR #510), and FIPS 140-3 capability reporting (PR #502) +* fwTPM session, policy, and NV fixes: transient state kept across command-port reconnects, `continueSession` set in the password-auth response, PolicyAuthorize zero-ticket handling, and an append-only NV journal for write-once flash ports (PRs #518, #530, #517, #540) +* New examples and options: crypto-primitive examples (getrandom, hash, AES, ECDH), a `WOLFTPM2_ECC_DEFAULT_CURVE` option (ZD 21780), and native_test ECC P-384 coverage (PRs #532, #519, #492) +* Nations NS350 example-suite fixes: RSA-4096 buffer sizing and SRK algorithm selection from the stored key type (PR #494) +* Freestanding build support: `WOLFTPM_NO_STD_HEADERS` keeps the standard C headers out of `tpm2_types.h` for bare-metal integrators, with a `freestanding-build.yml` CI job (PR #549) +* Software Bill of Materials (SBOM) generation for EU Cyber Resilience Act (CRA) compliance: new `make sbom` / `install-sbom` autotools targets and a CMake `sbom` target emit CycloneDX and SPDX documents for the built library, recording wolfSSL as a dependency (PR #536) +* Security hardening: automated security review (bounds/OOB fixes in the TPM2 packet parsers and marshaling, secret zeroization, policy/ticket bypass fixes), Coverity fixes across the fwTPM PCR/seed/hash/seal paths, CodeQL/Semgrep/Copilot review gates, and a heap out-of-bounds read fix in `TPM2_ASN_RsaUnpadPkcsv15` (PRs #496, #503, #511, #512, #518, #523, #535, #545, #547, #548, #543, #542, #544, #538, #513, #514, #524, #528, #507, #516) +* CI and build improvements: expanded CMake test cases, a GHCR container image, nightly fuzzing, wolfSSL latest-stable auto-resolve, and preflight smoke tests (PRs #495, #534, #522, #525, #508, #526, #521) +* Bug fixes + - Fixed the wolfCrypt crypto callback to propagate `ALREADY_E` for wolfSSL PR 10604 (PR #546) + - Ensured the wolfCrypt DRBG is used with crypto callbacks and made `TPM2_StirRandom` a TCG-compliant no-op on HW-RNG-backed TPMs (PRs #498, #493) + - Added a note on using the TPM RNG for the StartAuth session nonce (ZD 21476, PR #478) + + +## Full History + +Older releases are not repeated here. See `ChangeLog.md` in the repository root for every release. + +## See Also + +- [Testing and CI](testing.md) +- [SBOM and Compliance](sbom-and-compliance.md) +- [API Reference](api-reference.md) diff --git a/docs/rust-wrapper.md b/docs/rust-wrapper.md new file mode 100644 index 00000000..37f9bc04 --- /dev/null +++ b/docs/rust-wrapper.md @@ -0,0 +1,261 @@ +# Rust Wrapper + +The `wolftpm` crate provides safe Rust bindings for wolfTPM. The raw FFI is generated with bindgen and kept in the `sys` module. The rest of the crate is a safe API: functions return `Result`, TPM handles are released when they go out of scope, and all `unsafe` stays inside the crate. The crate lives in `wrapper/rust/wolftpm` in the wolfTPM source tree. + +## Requirements + +- Rust and Cargo, stable, rustc 1.81 or newer. +- A built wolfTPM C library (`libwolftpm`) and its wolfSSL dependency (`libwolfssl`). The crate links a prebuilt library. It does not build the C code itself. +- For the tests, a software TPM. wolfTPM's own `fwtpm_server` works, or any other TPM emulator or software TPM. See [fwTPM](fwtpm/overview.md) and [SWTPM](system-interfaces.md). + +## Step 1: Build the C Library + +Run these from the wolfTPM repository root: + +```sh +./autogen.sh +./configure --enable-swtpm --enable-fwtpm +make +``` + +This produces `src/.libs/libwolftpm`. With `--enable-fwtpm` it also builds the software TPM server at `src/fwtpm/fwtpm_server`. + +## Step 2: Build the Crate + +```sh +cd wrapper/rust/wolftpm +cargo build +``` + +The build finds the libraries in this order: + +1. If `WOLFTPM_PREFIX` or `WOLFSSL_PREFIX` are set, it uses `$PREFIX/include` and `$PREFIX/lib` of an installed copy. +2. Otherwise it uses the in-tree build: headers from the repo root, libraries from `src/.libs`. wolfSSL is located with `pkg-config`, then a local `./wolfssl` or a sibling `../wolfssl` checkout. + +Shared libraries are preferred. Static is used when no shared library is present. + +The library is `no_std` and uses `alloc` for owned keys, blobs, and output buffers. Bare-metal applications must provide a global allocator. The build script translates Rust cross-compilation targets such as `riscv32imac-unknown-none-elf` to clang's target spelling when generating the FFI bindings. + +The `wrapper/rust` directory also has a Makefile for the common tasks. After building the C library, `make -C wrapper/rust` builds, lints, and documents the crate, and `make -C wrapper/rust test` runs the tests (a software TPM must be listening on `localhost:2321`). + +## Step 3: Run the Tests + +The integration tests talk to a software TPM over a socket. They are behind the `swtpm-tests` feature, so a plain `cargo test` does not need a running server. + +Start a server on port 2321 (from the repo root): + +```sh +./src/fwtpm/fwtpm_server --clear --port 2321 --platform-port 2322 & +``` + +Run the tests against it: + +```sh +cd wrapper/rust/wolftpm +TPM2_SWTPM_HOST=localhost TPM2_SWTPM_PORT=2321 \ + cargo test --features swtpm-tests -- --test-threads=1 +``` + +Use `--test-threads=1` because the software TPM serves one client at a time. + +Run a single test file, for example the signing tests: + +```sh +cargo test --features swtpm-tests --test sign -- --test-threads=1 +``` + +The default host and port are `localhost:2321`, so the environment variables can be omitted when the server is on that address. + +## What the Tests Check + +Each file under `tests/` exercises one area against the software TPM: + +| File | Checks | +| --- | --- | +| `tests/smoke.rs` | Random bytes differ across draws, and a primary key loads. | +| `tests/keys.rs` | Create and load a child key, blob round-trip, short-auth blob round-trip, and an auth-protected parent. | +| `tests/sign.rs` | Sign a digest and verify it, and reject a tampered signature. | +| `tests/seal.rs` | Seal a secret and unseal it, and fail with the wrong auth. | +| `tests/seal_pcr.rs` | PCR-bound seal and unseal, unseal fails after a PCR changes, and an invalid PCR selection is rejected. | +| `tests/nv.rs` | Define an NV index, write and read it, then delete it. | +| `tests/pcr.rs` | Read a PCR, extend it, and confirm the value changed. | +| `tests/certify.rs` | An attestation key (ECC and RSA) certifies another key. | +| `tests/quote.rs` | Quote PCRs with an ECC and RSA AIK, and reject a bad PCR selection. | +| `tests/credential.rs` | MakeCredential then ActivateCredential round-trip. | +| `tests/ek.rs` | Create the endorsement key and export its public part. | +| `tests/persist.rs` | Persist a key, read it back, and evict it. | +| `tests/rsa.rs` | RSA-OAEP encrypt and decrypt, and an explicit OAEP-SHA1 round-trip. | +| `tests/hmac.rs` | Raw-key HMAC and a TPM-resident keyed-hash key HMAC. | +| `tests/caps.rs` | Self-test and capability query. | +| `tests/ecdh.rs` | ECDH generate then recover the same shared secret. | +| `tests/symmetric.rs` | AES-CFB encrypt and decrypt round-trip. | +| `tests/import.rs` | Import an external RSA and ECC private key. | + +## Example Test Output + +``` +running 2 tests +test certify_with_ecc_aik ... ok +test certify_with_rsa_aik ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 4 tests +test create_and_load_child ... ok +test key_blob_roundtrip_then_load ... ok +test key_blob_roundtrip_preserves_short_auth ... ok +test auth_protected_parent_loads_child ... ok +test result: ok. 4 passed; 0 failed; 0 ignored + +running 2 tests +test sign_then_verify ... ok +test verify_rejects_tampered_signature ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 2 tests +test rsa_oaep_roundtrip ... ok +test rsa_oaep_sha1_roundtrip ... ok +test result: ok. 2 passed; 0 failed; 0 ignored + +running 1 test +test make_and_activate_credential ... ok +test result: ok. 1 passed; 0 failed; 0 ignored +``` + +## Step 4: Run the Examples + +There are two examples. The first is minimal: + +```sh +cargo run --example create_primary +``` + +It opens the software TPM, reads random bytes, and creates an RSA and an ECC storage root key. + +The second runs the whole API in one pass: + +```sh +cargo run --example full_flow +``` + +Expected output. The random bytes and handle values differ between runs: + +``` +device connected to software TPM +get_random a91b37b1838d002453f1632ba2c0adbc +create_primary ECC SRK handle 0x80000000 +create_and_load signing key handle 0x80000001 +sign/verify 64 byte signature, verified +seal/unseal recovered "my secret" +key blob 257 bytes, reloaded as handle 0x80000002 +pcr read/extend PCR16 000000000000.. -> debb3e7acfff.. +nv define/rw 32 bytes at index 0x01500100 +certify 157 byte attestation +done all operations succeeded +``` + +If the wolfTPM C library was built with debug output, you will also see verbose TPM2_* traces from the library. A normal build prints only the lines above. + +## Using the Wrapper + +```rust +use wolftpm::{Device, HashAlg, Hierarchy, KeyAlg, KeyBlob, Template}; + +fn main() -> Result<(), wolftpm::TpmError> { + // Connect to a software TPM. Use Device::open() for the platform default. + let dev = Device::open_swtpm()?; + + // Random bytes from the TPM. + let mut nonce = [0u8; 32]; + dev.get_random(&mut nonce)?; + + // Storage root key under the owner hierarchy. + let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?; + + // Signing key under the SRK, then sign and verify a digest. + let signer = dev.create_and_load(&srk, &Template::signing(KeyAlg::EccP256)?, None)?; + let digest = [0x11u8; 32]; + let sig = signer.sign_hash(&digest)?; + signer.verify_hash(&digest, &sig)?; + + // Seal a secret to the TPM and read it back. + let sealed = dev.seal(&srk, b"my secret", None)?; + let _secret = dev.unseal(sealed, &srk, None)?; + + // Persist a key as bytes, then load it again. Scope the reloaded key so it + // releases its TPM handle before more transient objects are created below + // (many TPMs allow only three transient objects at once). + let bytes = { + let blob = dev.create_key(&srk, &Template::signing(KeyAlg::EccP256)?, None)?; + blob.to_bytes()? + }; + { + let restored = KeyBlob::from_bytes(&dev, &bytes)?; + let _loaded = restored.load(&srk, None)?; + } + + // Read and extend a PCR. + let _value = dev.pcr_read(16, HashAlg::Sha256)?; + dev.pcr_extend(16, HashAlg::Sha256, &[0xAB; 32])?; + + // Define, write, read, and delete an NV index. + let mut slot = dev.nv_create(0x0150_0100, 32, None)?; + dev.nv_write(&mut slot, b"metadata", 0)?; + let mut buf = [0u8; 32]; + dev.nv_read(&mut slot, &mut buf, 0)?; + dev.nv_delete(0x0150_0100)?; + + // Attest that a key lives in this TPM, signed by an attestation key. + let aik = dev.create_and_load(&srk, &Template::attestation(KeyAlg::EccP256)?, None)?; + let _attestation = dev.certify(&signer, &aik, &nonce)?; + + Ok(()) +} +``` + +Keys and the device release their TPM handles automatically when they drop. + +## What the Crate Covers + +- Device open and cleanup, TPM random numbers, self-test, and capability query. +- Primary and child keys. Templates for storage, signing, attestation, EK, RSA decrypt, keyed-hash HMAC, symmetric AES, and ECDH keys. +- Key blob serialize and load for persistence, and external RSA and ECC key import. +- Persistent key handles: store, read back, and evict. +- Sign and verify. +- RSA-OAEP encrypt and decrypt, including an explicit label hash (SHA-1 for Microsoft enrollment interop). +- Symmetric AES-CFB encrypt and decrypt. +- ECDH key agreement. +- HMAC, both raw-key and with a TPM-resident keyed-hash key. +- Seal and unseal, plain and bound to a PCR policy. +- PCR read and extend. +- NV define, write, read, delete, and certificate read (EK certificate). +- Attestation: certify a key, and quote PCRs. +- Credential activation: MakeCredential and ActivateCredential. + +Recovered secrets (unseal, RSA decrypt, ECDH, AES decrypt, credential activation) are returned in a `Secret` that zeroizes its buffer on drop. + +## Transport Security + +For confidentiality on the TPM transport, start a parameter-encryption session with `Device::start_encrypted_session` before the secret-bearing operations: + +```rust +let srk = dev.create_primary(Hierarchy::Owner, KeyAlg::EccP256, None)?; +let _session = dev.start_encrypted_session(&srk)?; // salted HMAC + AES-CFB +let sealed = dev.seal(&srk, b"secret", None)?; // command param encrypted +let plain = dev.unseal(sealed, &srk, None)?; // response param encrypted +``` + +While the session is alive its salted HMAC session occupies auth slot 1, so wolfTPM encrypts the sensitive command and response parameters of seal/unseal, RSA and AES encrypt/decrypt, HMAC, NV, ECDH, and key create/load. Only one session is allowed at a time. The attestation commands (certify, quote, activate_credential) need the same auth slot and are refused while a session is active, so drop the session before calling them. + +!!! warning + Without a session, parameters cross the transport in the clear. Either use a session or run over a trusted local transport (the Linux kernel device or a local socket) rather than a remote `TPM2_SWTPM_HOST` or an observable physical bus. + +## License + +GPLv3, or a commercial wolfSSL license, matching wolfTPM. + +## See Also + +- [fwTPM](fwtpm/overview.md) +- [SWTPM](system-interfaces.md) +- [Build Options](build-options.md) +- [C# Wrapper](csharp-wrapper.md) diff --git a/docs/sbom-and-compliance.md b/docs/sbom-and-compliance.md new file mode 100644 index 00000000..1331c49f --- /dev/null +++ b/docs/sbom-and-compliance.md @@ -0,0 +1,105 @@ +# SBOM and Compliance + +wolfTPM can generate a Software Bill of Materials (SBOM) to support compliance with the EU Cyber Resilience Act (CRA). This page covers how to generate it and how the generator is organized. + +## SBOM and EU CRA compliance + +wolfTPM generates an SBOM in CycloneDX 1.6 and SPDX 2.3 formats. The generator is the wolfGlass snapshot vendored in `tools/sbom/` and pinned by `tools/sbom/.wolfglass-rev`. The SBOM records the configured build options (from `wolftpm/options.h`), hashes the built `libwolftpm` library artifact (shared or static; ELF, Mach-O, or PE), and lists wolfSSL as a dependency so vulnerability scanners can associate wolfSSL advisories with a wolfTPM deployment. + +Output is reproducible. Set `SOURCE_DATE_EPOCH` (or build from a git checkout, which uses the last commit time) and repeated runs are byte-identical. + +With autotools: + +```sh +make sbom +``` + +This requires `python3` and `pyspdxtools` (`pip install spdx-tools`). The generator ships in the tree, so `make sbom` does not need a separate wolfSSL checkout. Pass `WOLFSSL_DIR=/path/to/wolfssl` when pkg-config cannot see the wolfSSL that this build linked, so the dependency version is read from `wolfssl/version.h`. `SBOM_WOLFSSL_VERSION` overrides that detection. + +The CMake build exposes the same target. `WOLFSSL_DIR` is optional and has the same meaning: + +```sh +cmake -B build . +cmake --build build --target sbom +``` + +The output files are: + +- `wolftpm-.cdx.json` +- `wolftpm-.spdx.json` +- `wolftpm-.spdx` + +Optional overrides: + +| Variable | Purpose | +|---|---| +| `SBOM_LICENSE_OVERRIDE` | SPDX expression to use instead of the licence parsed from `COPYING` (for example `LicenseRef-wolfSSL-Commercial` for commercial licensees). Defaults to `GPL-3.0-or-later`, the per-file header licence. | +| `SBOM_LICENSE_TEXT` | Path to the licence text for any `LicenseRef-*` used in `SBOM_LICENSE_OVERRIDE` (required by SPDX 2.3). | +| `SBOM_WOLFSSL_VERSION` | Version recorded for the wolfSSL dependency. Auto-detected from `WOLFSSL_DIR/wolfssl/version.h` (or the wolfSSL `pkg-config` entry) when unset. | + +To install the generated files: + +```sh +make install-sbom # installs to $(datadir)/doc/wolftpm/ +make uninstall-sbom +``` + +For further CRA guidance see [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md). + +## Generator internals + +The `share/` set of wolfGlass is the only vendorable part. The `tools/wolfglass-sync` script copies these files into a product at `tools/sbom/`, together with the pin files (`VERSION` and `.wolfglass-rev`). Copy the files, not the `share/` folder name. + +### Contents + +| File | Role | +|---|---| +| `sbom-driver.py` | The product-neutral SBOM engine (Python). | +| `sbom-driver` | Thin shell wrapper that runs `sbom-driver.py`. | +| `validate_sbom.py` | Structural validator for CI (`--name-prefix`). | +| `frontends/compdb_sbom.py` | Extractor for any `compile_commands.json`. | +| `frontends/iar_sbom.py` | Extractor for an IAR Embedded Workbench `.ewp`. | +| `frontends/zephyr_sbom.py` | Extractor for a Zephyr module `CMakeLists.txt`. | +| `build/sbom.mk` | Shared plain-Make fragment and `wolfglass_sbom_rule` macro. | +| `build/sbom.cmake` | Shared CMake helper: `wolfglass_add_sbom()`. | +| `gen-sbom` | The vendored SBOM generator. | +| `sbom.am` | Shared autotools fragment. | + +### The driver contract + +Every front end produces a composition input and a config input and hands them to the driver. + +Composition (at least one): + +- `--srcs-file PATH`: the source files compiled into the artifact (tier E). +- `--lib PATH`: the built library to hash (tier R/L/S). +- `--no-artifact-hash`: record the artifact as-built and do not re-hash. Use it with `--lib` for a FIPS canister or a kernel module. Never substitute a source list for a certified artifact. + +Config (choose one): + +- `--cflags="..."`: raw CFLAGS. The driver expands the `-D` tokens through the host compiler. Use the `=` form so a leading-dash value is not read as a flag. +- `--options-h PATH`: a pre-expanded flat `#define` header, used verbatim. +- `--user-settings PATH`: a `user_settings.h`, which the generator captures. +- `--source-only`: no build-config macros (for example a Kconfig-driven build). + +Dependency (for linkers and bindings): `--dep-wolfssl`, `--dep-openssl`, and `--dep-version` are passed through only when the generator supports them. + +The driver captures macros with the host compiler, so the SBOM is reproducible across toolchains. It scrubs absolute host paths from the captured macros unless you pass `--no-scrub`. + +The shared driver is product-neutral and calls the vendored `share/gen-sbom` by default. Pass `--gen-sbom` only when you want to override that copy. + +### The manifest contract + +A product does not copy logic. It describes itself: + +- **Make:** set `SBOM_NAME`, `SBOM_SRCS`, `SBOM_CFLAGS`, and a version (`SBOM_VERSION`, or `SBOM_VERSION_FILE` and `SBOM_VERSION_MACRO`), then `include tools/sbom/build/sbom.mk`. For a second target, instantiate `$(eval $(call wolfglass_sbom_rule,,))`. If the product configuration lives in a `user_settings.h`, also set `SBOM_SETTINGS_H` (and `SBOM_INCLUDE_DIRS` if that header needs paths the CFLAGS do not already carry). `SBOM_CFLAGS` alone records the literal `-D` set and nothing it derives, which for a gated header means the SBOM describes a configuration nobody built. +- **CMake:** `include(tools/sbom/build/sbom.cmake)` and call `wolfglass_add_sbom()` with `NAME`, `VERSION_FILE`, `VERSION_MACRO`, `TARGETS`, `DEFS`, `LICENSE`. `SBOM_GEN` is the canonical generator override. `GEN_SBOM` remains a legacy alias for compatibility. +- **Autotools:** set the `SBOM_*` variables and `include tools/sbom/sbom.am`. + +Keep only true product knowledge in the product: the route-through script, the module extractor, and the HAL source selector. + +## See Also + +- [Testing and CI](testing.md) +- [Release Notes](release-notes.md) +- [API Reference](api-reference.md) diff --git a/docs/sealing-and-nvram.md b/docs/sealing-and-nvram.md new file mode 100644 index 00000000..3c7ae5d2 --- /dev/null +++ b/docs/sealing-and-nvram.md @@ -0,0 +1,350 @@ +# 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: + +```sh +$ ./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](#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. + +```sh +./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. + +```sh +# 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. + +```sh +# 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. + +```sh +# 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: + +```sh +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: + +```sh +$ ./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: + +```sh +$ ./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](#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: + +1. Use AES-CFB parameter encryption for all communication (salted and bound). +2. Derive a password from unique device parameters and use it as the "auth" to load the NV (authenticate). +3. The NV contains a hash of the public key (the hash matches the `.config` setting). +4. wolfBoot still has the public key internally and programs the TPM NV if it is not populated. +5. The NV is locked and created under the platform hierarchy. + +Example: + +```sh +$ ./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: + +```sh +# 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: + +```sh +# 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: + +```sh +# 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 +``` + +## See Also + +- [TLS and certificates](tls-and-certificates.md) +- [Management and GPIO](management-and-gpio.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/spdm.md b/docs/spdm.md new file mode 100644 index 00000000..50ce8766 --- /dev/null +++ b/docs/spdm.md @@ -0,0 +1,589 @@ +# SPDM Attestation and Secure Sessions + +wolfTPM includes built-in SPDM (Security Protocol and Data Model, DMTF DSP0274) support for Nuvoton NPCT75x and Nations NS350 TPMs, using wolfSSL/wolfCrypt. SPDM negotiates protocol version 1.3 over the TCG SPDM-over-TPM binding. Both vendors support identity key mode (ECDHE P-384) for session establishment. The Nations NS350 additionally supports PSK (pre-shared key) mode. Once a session is established, all TPM commands and responses are encrypted with AES-256-GCM over the existing SPI or I2C bus. Identity key mode requires the responder's P-384 public key from a trusted provisioning source. The TCG exchange is a raw public key exchange (GET_PUBK and GIVE_PUB); no certificates are exchanged. + +The SPDM code lives in the [wolfSPDM](https://github.com/wolfSSL/wolfSPDM) library, included as the `lib/wolfSPDM` submodule and compiled into libwolftpm in its TPM profile. A checkout that will use SPDM needs the submodule present, either from a recursive clone or from initializing it afterward. Without it, `./configure --enable-spdm` stops with: `--enable-spdm needs the wolfSPDM submodule: run git submodule update --init lib/wolfSPDM`. + +## Quick start + +Clone recursively, because SPDM lives in the `lib/wolfSPDM` submodule: + +```sh +git clone --recursive https://github.com/wolfSSL/wolfTPM.git +git clone https://github.com/wolfSSL/wolfssl.git # sibling checkout +cd wolfTPM +``` + +Already cloned without `--recursive`? Run `git submodule update --init lib/wolfSPDM` once inside the checkout. + +### Nuvoton NPCT75x + +```sh +# Build wolfSSL (in the sibling checkout, then return here) +cd ../wolfssl && ./autogen.sh && \ +./configure --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp && \ +make && sudo make install && sudo ldconfig && cd - + +# Build wolfTPM (submodule already present from the recursive clone) +./autogen.sh && ./configure --enable-spdm --enable-nuvoton && make + +# Enable SPDM (one-time), then reset the TPM, then connect +./examples/spdm/spdm_ctrl --enable +# reset the TPM now (see "TPM reset pin control" for the gpioset and reset-HAL commands) +RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +./examples/spdm/spdm_ctrl --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +See the TPM reset pin control section for the reset commands and their caveats. `responder_pubkey.hex` holds the trusted raw P-384 X||Y point (192 hex characters) from your provisioning records. + +### Nations NS350 + +```sh +# Build wolfSSL (in the sibling checkout, then return here) +cd ../wolfssl && ./autogen.sh && \ +./configure --enable-wolftpm --enable-ecc --enable-sha384 --enable-aesgcm --enable-hkdf --enable-sp && \ +make && sudo make install && sudo ldconfig && cd - + +# Build wolfTPM (submodule already present from the recursive clone) +./autogen.sh && ./configure --enable-spdm --enable-nations && make + +# Connect (identity key is factory default) +RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +./examples/spdm/spdm_ctrl --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +## Overview and how it works + +The `spdm_ctrl` tool establishes SPDM secure sessions between the host and a TPM over SPI or I2C, enabling AES-256-GCM encrypted bus communication. The implementation uses Algorithm Set B: SHA-384 and AES-256-GCM, with ECDH P-384, ECDSA P-384, and HKDF-SHA384 added in identity key mode. Two session establishment modes are supported. + +`spdm_ctrl` and `nv_bind` are the examples that accept SPDM credentials. Other wolfTPM examples use uncredentialed `wolfTPM2_Init()` and intentionally return `WOLFSPDM_E_BAD_STATE` while a TPM is locked in SPDM-only mode. Unlock it with `spdm_ctrl` before running those examples. + +Supported hardware: + +- Nuvoton NPCT75x: identity key mode (ECDHE P-384) +- Nations NS350: identity key mode and PSK mode + +### Identity key mode (Nuvoton and Nations) + +``` +Host TPM (Nuvoton NPCT75x / Nations NS350) + | | + |--- GET_VERSION ------------------>| (negotiate SPDM version) + |<-- VERSION -----------------------| + | | + |--- GET_CAPABILITIES ------------->| (Nations only) + |<-- CAPABILITIES ------------------| + |--- NEGOTIATE_ALGORITHMS --------->| (Nations only) + |<-- ALGORITHMS --------------------| + | | + |--- GET_PUBK --------------------->| (get TPM's P-384 identity key) + |<-- GET_PUBK response -------------| + | | + |--- KEY_EXCHANGE ----------------->| (ECDHE P-384 key agreement) + |<-- KEY_EXCHANGE_RSP --------------| (+ ECDSA signature and HMAC) + | | + | --- Handshake keys derived --- | + | | + |=== GIVE_PUB =====================>| (encrypted: host's P-384 key) + |<== GIVE_PUB response =============| + | | + |=== FINISH =======================>| (encrypted: signature + HMAC) + |<== FINISH_RSP ====================| + | | + | --- App data keys derived --- | + | | + |=== TPM2_CMD (AES-256-GCM) =======>| (every command encrypted) + |<== TPM2_RSP (AES-256-GCM) ========| +``` + +The Nuvoton adapter skips GET_CAPABILITIES and NEGOTIATE_ALGORITHMS; the Nations adapter sends them after VERSION. The handshake uses ECDH P-384 for key agreement, ECDSA P-384 signatures, HKDF-SHA384 for key derivation, and HMAC-SHA384 for authentication. P-384 is not part of the PSK key agreement. After the handshake, all TPM commands are wrapped in SPDM `VENDOR_DEFINED_REQUEST("TPM2_CMD")` messages and encrypted with AES-256-GCM. TPM responses arrive in `VENDOR_DEFINED_RESPONSE` messages. Secured records keep independent 64-bit request and response sequence numbers that increment with each message to prevent replay. + +### PSK mode (Nations only) + +PSK mode replaces the ECDHE key exchange with a symmetric pre-shared key. The same AES-256-GCM encryption is used for data transport. The requester goes straight from GET_VERSION to PSK_EXCHANGE; capability and algorithm negotiation are not required for this flow. + +``` +Host TPM (Nations NS350) + | | + |--- GET_VERSION ------------------>| (negotiate SPDM version) + |<-- VERSION -----------------------| + | | + |--- PSK_EXCHANGE ----------------->| (session key from PSK) + |<-- PSK_EXCHANGE_RSP --------------| (+ HMAC proof) + | | + | --- Handshake keys derived --- | (Salt_0 = 0xFF * H for PSK mode) + | | + |=== PSK_FINISH ===================>| (encrypted: requester HMAC) + |<== PSK_FINISH_RSP ================| + | | + | --- App data keys derived --- | + | | + |=== TPM2_CMD (AES-256-GCM) =======>| (every command encrypted) + |<== TPM2_RSP (AES-256-GCM) ========| +``` + +PSK and identity key modes are mutually exclusive on the NS350. The identity key is provisioned by factory default and must be unset before PSK can be used. See the PSK lifecycle section. + +### SPDM-only mode (encrypted bus enforcement) + +SPDM-only mode forces TPM commands through the encrypted SPDM channel. The one exception is plaintext `TPM2_GetCapability`, which the fwTPM responder deliberately allows while locked to match the supported silicon. Both vendors support SPDM-only mode. The typical lifecycle: + +``` +1. Enable SPDM (one-time, persists across resets) +2. Connect (handshake, derives session keys) +3. Lock SPDM-only (TPM rejects cleartext commands except GetCapability) +4. Reset (TPM enters SPDM-only enforcement) +5. Initialize with the trusted key or PSK and run commands (all encrypted) +6. Unlock (connect + unlock in one session) +7. Reset (TPM back to normal cleartext mode) +``` + +After an application supplies the responder key through `wolfTPM2_InitWithSpdmKey()`, wolfTPM authenticates the responder and establishes the encrypted session. It continues after a successful or already-initialized startup probe and after the expected `TPM_RC_DISABLED` result. Other startup failures, such as a firmware-upgrade state, are returned before any SPDM connection is attempted. See the Auto-SPDM section for details. + +The reset method differs by vendor: + +- Nuvoton: GPIO 4 reset (see TPM reset pin control) +- Nations: GPIO 4 is wired to TPM_RST on the NS350 daughter board used by the test harness, so the same GPIO reset applies there. If your board does not wire it, use a full power cycle. + +## Building + +### 1. Clone with the wolfSPDM submodule + +See the Quick start section. SPDM is built from the `lib/wolfSPDM` submodule, so clone wolfTPM recursively, or run `git submodule update --init lib/wolfSPDM` in an existing checkout. + +### 2. wolfSSL + +Both Nuvoton and Nations use the same wolfSSL flags, which provide the crypto for SPDM Algorithm Set B. wolfSSL 5.8.0 or later is required; the wolfSPDM configure check in the `lib/wolfSPDM` submodule enforces this. + +```sh +cd ../wolfssl +./autogen.sh +./configure --enable-wolftpm --enable-ecc --enable-sha384 \ + --enable-aesgcm --enable-hkdf --enable-sp +make +sudo make install && sudo ldconfig +cd - # back to the wolfTPM checkout +``` + +### 3. wolfTPM + +```sh +./autogen.sh +./configure --enable-spdm --enable-nuvoton # Nuvoton +# or +./configure --enable-spdm --enable-nations # Nations +make +``` + +Build with `--enable-spdm` plus at least one handshake mode: `--enable-tcg` for the TCG raw public key handshake, `--enable-psk` for the PSK handshake. Vendor wire-format adapters (`--enable-nuvoton`, `--enable-nations`) are optional for PSK mode and the fwTPM responder, but an identity-key session needs the matching vendor adapter; without one, `wolfTPM2_InitWithSpdmKey_ex()` returns `WOLFSPDM_E_NOT_AVAILABLE`. + +### The wolfTPM SPDM profile + +`--enable-spdm` defines `WOLFTPM_SPDM`, which auto-selects wolfSPDM's `WOLFSPDM_PROFILE_TPM`. The TPM binding is the TCG SPDM Binding, so this profile is a lean, TCG-focused build. The generic DSP0274 requester functions below are compiled out automatically. The Nations adapter still uses its own TCG-specific GET_CAPABILITIES and NEGOTIATE_ALGORITHMS implementations in `spdm_tcg.c`. + +- the DMTF standard requester functions: `GET_CAPABILITIES`, `NEGOTIATE_ALGORITHMS`, `GET_DIGESTS`, `GET_CERTIFICATE`, and certificate-chain validation +- measurements, challenge, and chunking (they ride the cert flow) +- heartbeat and key update +- the MCTP application-data API (secured messages use the TCG 16-byte pad) + +There is no `--disable-mctp` option on wolfTPM's `configure`, and you should not try to add one. The lean profile is automatic with `--enable-spdm`, and wolfSPDM's downstream CI asserts the standard-requester symbols above are absent from `libwolftpm`. + +The profile does not define `WOLFSPDM_NO_MCTP`, so the MCTP secured-message framing stays compiled, though a TCG-only TPM never exercises it. Building wolfSPDM standalone with `--disable-mctp` (which requires `--enable-tcg`) additionally strips that path for a pure-TCG requester. That flag belongs to wolfSPDM's own `configure`, never wolfTPM's. + +### Configure options + +| Option | Description | +|--------|-------------| +| `--enable-spdm` | Enable SPDM support (required) | +| `--enable-tcg` | TCG SPDM Binding spec handshake (auto when fwtpm/nuvoton/nations on) | +| `--enable-psk` | DSP0274 PSK handshake (auto with `--enable-nations`; requires `--enable-tcg`) | +| `--enable-fwtpm` | Build fwtpm_server with the SPDM responder (needs `--enable-spdm` and a handshake mode; no silicon needed) | +| `--enable-nuvoton` | Enable Nuvoton TPM hardware support (auto-enables `--enable-tcg`) | +| `--enable-nations` | Enable Nations NS350 hardware support (auto-enables `--enable-tcg --enable-psk`) | +| `--enable-debug` | Debug output with verbose SPDM tracing | +| `--enable-smallstack` | Heap-allocate the SPDM context and the SPDM request and response buffers, and lower the public message-size limits (default: caller-owned inline context, about 32 KB) | + +`configure` rejects these incompatible combinations: + +- `--enable-nuvoton --disable-tcg` (Nuvoton uses the TCG SPDM Binding) +- `--enable-nations --disable-tcg` or `--enable-nations --disable-psk` +- `--enable-psk --disable-tcg` (PSK rides on TCG framing) + +### fwTPM SPDM responder (no silicon required) + +`fwtpm_server` ships an SPDM 1.3 responder that drives the same handshake the real Nuvoton and Nations parts use, so the full TCG and PSK stack can be exercised in CI without real hardware: + +Build it with the socket responder enabled: + +```sh +./configure --enable-fwtpm --enable-swtpm --enable-spdm --enable-tcg --enable-psk --enable-nuvoton --enable-nations +make +``` + +Then start it in one of the SPDM modes. The fwTPM responder takes a non-empty PSK of at most 64 bytes (128 hex characters); the exact 64-byte requirement applies to Nations hardware provisioning, not to this responder. The value below is the test PSK used by `spdm_test.sh`: + +```sh +SPDM_PSK=dbc2192291d807742441b963f6712841f7697e2e39c45931f3abc53658c8b9338bd3561cab5d90cf9e493295bb5bd6b2c455e0fd19392e0ce4f3433cbcfc7047 +./src/fwtpm/fwtpm_server --spdm-tcg # TCG raw public key handshake +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" # PSK handshake +``` + +For a manual PSK test, supply the same `SPDM_PSK` value to the requester, for example `spdm_ctrl --psk "$SPDM_PSK"`. + +Test it end-to-end: + +```sh +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-tcg +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl fwtpm-psk +``` + +See [fwtpm/spdm.md](fwtpm/spdm.md) for the responder modes and the end-to-end test scripts. + +### Vendor selection in dual-vendor builds + +When both `--enable-nuvoton` and `--enable-nations` are compiled in, `spdm_ctrl` selects the vendor adapter with an optional runtime flag: + +```sh +./examples/spdm/spdm_ctrl --vendor=nuvoton \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect +./examples/spdm/spdm_ctrl --vendor=nations \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect +``` + +Single-vendor builds accept only the adapter compiled into the binary and reject an unavailable `--vendor=` value. + +## Usage and control commands + +### One-time setup + +The administrative commands (enable, disable, identity key set and unset) use an empty platform authorization, and `--tpm-clear` uses the default empty lockout authorization. `spdm_ctrl` has no option to supply different hierarchy secrets, so these commands do not work on a TPM provisioned with non-empty authorizations. + +Nuvoton: + +```sh +# Enable SPDM on the TPM (persists across resets) +./examples/spdm/spdm_ctrl --enable + +# Reset the TPM (see TPM reset pin control) + +# Verify SPDM is enabled +./examples/spdm/spdm_ctrl --status +``` + +Nations: identity key mode is the factory default, so no setup is required. If it was previously unset, restore it with: + +```sh +./examples/spdm/spdm_ctrl --identity-key-set +``` + +### Establishing a session + +Identity key mode (both vendors): + +```sh +# Establish SPDM session (VERSION, GET_PUBK, KEY_EXCHANGE, GIVE_PUB, FINISH; +# Nations also sends GET_CAPABILITIES and NEGOTIATE_ALGORITHMS) +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect + +# Query SPDM status +./examples/spdm/spdm_ctrl --status +``` + +`--responder-pubkey` takes the trusted raw P-384 X||Y point as 192 hex characters. Obtain it from device provisioning records or another authenticated manufacturer channel. The examples here read these values into shell variables, for instance `RESPONDER_PUBKEY="$(cat responder_pubkey.hex)"`. The responder public key is not secret, but it is a trust anchor, so protect it from tampering. The PSK and ClearAuth are secrets: keep those files readable only by their owner (`chmod 600`). Passing a secret as a command-line argument (for example `--psk`) exposes it to other users on the host through `/proc//cmdline`; these example CLIs are demonstration tools, so handle real secrets accordingly on a shared machine. + +!!! warning + `--get-pubkey` is unauthenticated discovery and must not be used by itself to establish trust. + +PSK mode (Nations) requires the PSK to be provisioned first. See the PSK lifecycle section. In the commands below, `PSK_HEX` holds the 64-byte PSK as 128 hex characters and `CLEARAUTH_HEX` holds the 32-byte ClearAuth as 64 hex characters, each read from a file only you can read. + +```sh +# Establish PSK session (VERSION, PSK_EXCHANGE, PSK_FINISH) +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" +``` + +### Lock and unlock SPDM-only mode + +Lock requires an active SPDM session. After locking, a reset is required for enforcement to take effect. + +Nuvoton (identity key): + +```sh +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM (see TPM reset pin control) + +# Unlock +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM again +``` + +Nations (identity key): + +```sh +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM (GPIO 4 on the tested board, otherwise a power cycle) + +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM again +``` + +Nations (PSK mode): + +```sh +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" --lock +# Reset the TPM + +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" --unlock +# Reset the TPM again +``` + +### PSK lifecycle (Nations) + +PSK and identity key modes are mutually exclusive on the NS350. The identity key is provisioned by default and must be unset before PSK can be used. + +```sh +# 1. Unset identity key (enables PSK mode) +./examples/spdm/spdm_ctrl --identity-key-unset + +# 2. Provision PSK (64-byte PSK + 32-byte ClearAuth) +# The demo computes SHA-384(ClearAuth) and sends PSK(64)+Digest(48) = 112 bytes +./examples/spdm/spdm_ctrl --psk-set "$PSK_HEX" "$CLEARAUTH_HEX" + +# 3. Establish PSK session +./examples/spdm/spdm_ctrl --psk "$PSK_HEX" + +# 4. Clear PSK (sends raw 32-byte ClearAuth; TPM verifies SHA-384 internally) +./examples/spdm/spdm_ctrl --psk-clear "$CLEARAUTH_HEX" + +# 5. Restore identity key (factory default) +./examples/spdm/spdm_ctrl --identity-key-set +``` + +!!! warning + The ClearAuth must be exactly 32 bytes. PSK_SET stores its SHA-384 digest (48 bytes). PSK_CLEAR sends the raw 32 bytes and the TPM computes SHA-384 to verify. `spdm_ctrl` rejects a ClearAuth of the wrong length. + +### Command reference + +All `spdm_ctrl` options (the set accepted depends on the vendor adapters compiled in): + +| Option | Vendor | Description | +|--------|--------|-------------| +| `--enable` | Nuvoton | Enable SPDM via NTC2_PreConfig (one-time, persists, requires reset) | +| `--disable` | Nuvoton | Disable SPDM via NTC2_PreConfig (requires reset) | +| `--identity-key-set` | Nations | Provision SPDM identity key (factory default) | +| `--identity-key-unset` | Nations | Remove the provisioned identity key (required before PSK) | +| `--vendor=nuvoton\|nations` | Both | Select the identity/vendor adapter explicitly | +| `--get-pubkey` | Both | Discover the TPM identity key without authenticating it | +| `--responder-pubkey` *hex* | Both | Pin a trusted raw P-384 X\|\|Y responder key (192 hex characters) | +| `--connect` | Both | Establish identity key SPDM session (ECDH P-384 handshake) | +| `--caps` | Both | Read TPM capabilities over the current transport | +| `--status` | Both | Query SPDM status | +| `--session-info` | Both | Show the TPM's view of the SPDM session (`TPM_CAP_SPDM_SESSION_INFO`) | +| `--policy-nv` | Both | Define an NV index guarded by `TPM2_PolicyTransportSPDM`, then write and read it over the session | +| `--lock` | Both | Lock SPDM-only mode (needs an active session: `--connect`, or `--psk` for Nations PSK) | +| `--unlock` | Both | Unlock SPDM-only mode (needs an active session: `--connect`, or `--psk` for Nations PSK) | +| `--psk` *hex* | Nations | Establish PSK session (64-byte PSK) | +| `--psk-set` *psk* *clearauth* | Nations | Provision PSK (64-byte PSK, 32-byte ClearAuth) | +| `--psk-clear` *clearauth* | Nations | Clear PSK (32-byte ClearAuth) | +| `--caps184` | Nations | Query TPM 184 vendor properties and SPDM session info | +| `--tpm-clear` | Both | Send `TPM2_Clear` over the current transport (authorized with `TPM_RH_LOCKOUT`, default empty lockout auth) | + +### Usage example + +```sh +# One-time setup: enable SPDM + reset TPM +./examples/spdm/spdm_ctrl --enable +# Reset the TPM (see "TPM reset pin control" below) + +# Query SPDM status +./examples/spdm/spdm_ctrl --status + +# Discover TPM identity key (unauthenticated; do not use as its own trust source) +./examples/spdm/spdm_ctrl --get-pubkey + +# Establish SPDM session with a key from trusted provisioning records +./examples/spdm/spdm_ctrl \ + --vendor=nuvoton --responder-pubkey "$RESPONDER_PUBKEY" --connect + +# Lock SPDM-only mode (connect + lock in one session) +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --lock +# Reset the TPM + +# Unlock SPDM-only mode +./examples/spdm/spdm_ctrl \ + --responder-pubkey "$RESPONDER_PUBKEY" --connect --unlock +# Reset the TPM +``` + +### nv_bind + +The `nv_bind` example is a focused, self-contained version of the `--policy-nv` idea. It provisions an NV index whose `authPolicy` is `TPM2_PolicyTransportSPDM`, stores a secret over an SPDM-PSK session, then shows that the identical read over a plain (non-SPDM) connection is refused with `TPM_RC_CHANNEL`. + +Start the responder in a separate terminal and leave it listening, then run `nv_bind` from another terminal. `--clear` deletes the fwTPM NV state file, so use a disposable instance. + +```sh +# terminal 1: responder +./src/fwtpm/fwtpm_server --spdm-psk --spdm-psk-hex "$SPDM_PSK" --clear +``` + +```sh +# terminal 2: once the responder is listening +./examples/spdm/nv_bind --psk "$SPDM_PSK" +``` + +The fwTPM generates a fresh SPDM identity key each time it starts, so on the fwTPM a policy bound to `tpmKeyName` is only valid for that server lifetime. A hardware TPM holds a persistent identity key, where such a binding is durable. PSK sessions report empty key names, since no asymmetric key authenticated them. + +### TPM reset pin control + +SPDM enable/disable and SPDM-only mode changes require a TPM reset to take effect. A host-controllable reset pin is the easiest way to do that, but cycling the TPM power rail also works. + +!!! warning + For custom hardware designs, route the TPM reset pin to a host-controllable GPIO or make the TPM power rail switchable. Without a way to reset or power cycle the TPM, SPDM mode changes cannot be applied and recovery from SPDM-only mode is not possible. + +The reset line is board specific. On a Raspberry Pi, Nuvoton uses GPIO4 and the ST33KTPM uses GPIO24 (pin 18). The tested NS350 daughter board also wires GPIO4 to TPM_RST. Confirm your wiring before toggling. + +With libgpiod 1.x, `gpioset` drives the line and then, in its default mode, releases the request when it exits (the chip is a positional argument). The pulse below holds each level only while the board's pull resistor does, which is what `spdm_test.sh` relies on on the tested boards: + +```sh +gpioset gpiochip0 4=0 && sleep 0.1 && gpioset gpiochip0 4=1 && sleep 2 +``` + +With libgpiod 2.x the chip is given with `--chip`, and `gpioset` holds the line only while the process runs. A plain `&&` chain releases the line as each `gpioset` exits, and `--daemonize` does the opposite: it keeps the request and the line level held until the daemon is killed, which leaves the reset pin claimed and can block a later reset. Neither is a clean finite pulse. For a timed pulse, use `gpioset --toggle` (see the gpioset manual) so one process drives the line low, waits, drives it high, waits, and then exits; verify the sequence on your board first, because the released level depends on the pull resistor. For ST33 use line 24 instead of 4. For repeatable automation, prefer the wolfTPM reset HAL below. + +wolfTPM can also drive the reset from code: build with `--enable-hal-reset` and call `TPM2_IoCb_Reset(ctx, userCtx)`, which takes a `TPM2_CTX*` and a `void*`. The default line is ST33 GPIO24 and Nuvoton GPIO4. A Nations build also defaults to GPIO24 unless line 4 is supplied explicitly. See `hal/README.md` in the source tree. + +## TCG SPDM vendor commands + +Both Nuvoton and Nations TPMs implement the TCG "TPM Communication over SPDM Secure Session" binding, though the Nuvoton flow omits the GET_CAPABILITIES and NEGOTIATE_ALGORITHMS negotiation that the Nations flow performs (see Identity key mode). It carries each message as an SPDM `VENDOR_DEFINED_REQUEST` (request code `0xFE`) answered by a `VENDOR_DEFINED_RESPONSE` (response code `0x7E`), with `StandardID=0x0001` (TCG). The vendor code (VdCode) inside the message is an 8-byte ASCII string. + +The published TCG table defines `GET_PUBK`, `GIVE_PUB`, `TPM2_CMD`, and optional locality-specific `TPM2CMD0` through `TPM2CMD4` values. `GET_STS_`, `SPDMONLY`, `PSK_SET_`, and `PSK_CLR_` are implementation or vendor extensions, not TCG-defined commands. The exact vendor-extension wire details for the two vendor adapters live in the `lib/wolfSPDM` submodule. + +| VdCode | Command | Defined by | Vendor | Description | +|--------|---------|------------|--------|-------------| +| `GET_PUBK` | Get Public Key | TCG | Both | Get TPM's SPDM-Identity P-384 public key | +| `GIVE_PUB` | Give Public Key | TCG | Both | Send host's P-384 public key to TPM | +| `TPM2_CMD` | TPM Command | TCG | Both | Wrap TPM command in SPDM secured message | +| `GET_STS_` | Get Status | Vendor extension | Both | Query SPDM status | +| `SPDMONLY` | SPDM-Only Mode | Vendor extension | Both | Lock/unlock SPDM-only enforcement | +| `PSK_SET_` | PSK Set | Vendor extension | Nations | Provision pre-shared key (64-byte PSK + SHA-384 digest) | +| `PSK_CLR_` | PSK Clear | Vendor extension | Nations | Clear provisioned PSK (requires ClearAuth) | + +## Vendor specifics + +### Nuvoton NPCT75x + +- Enable/disable: SPDM is enabled via the `NTC2_PreConfig` vendor command (`--enable` / `--disable`). This persists across resets. +- GPIO reset: GPIO 4 is wired to TPM_RST on the Nuvoton daughter board. A GPIO reset clears stale SPDM state. See TPM reset pin control for the commands. + +### Nations NS350 + +- Mode switching: identity key and PSK modes are mutually exclusive. The identity key is provisioned by factory default. Use `--identity-key-unset` before provisioning PSK, and `--identity-key-set` to restore. +- Reset: the hardware-tested harness (`spdm_test.sh`) treats GPIO 4 as wired to TPM_RST on the NS350 daughter board and uses it when normalizing Nations state. The identity key and PSK are stored in NV and survive a reset. If your board does not wire the line, a full power cycle is needed, because `sudo reboot` leaves the 3.3V rail powered. +- Capabilities query: use `--caps184` to query TPM 184 vendor properties including SPDM session info. +- ClearAuth: must be exactly 32 bytes. `PSK_SET` stores its SHA-384 digest (48 bytes). `PSK_CLEAR` sends the raw 32 bytes and the TPM computes SHA-384 to verify. + +!!! note + On some NS350 firmware versions, `--status` may report "Identity Key: not provisioned" even when the key is present. The `--connect` command is the definitive test: if the ECDHE handshake succeeds, the identity key is provisioned. + +Nations PSK operations can return vendor-specific error codes, for example PSK already provisioned, no PSK provisioned, an internal SPDM session error, or a ClearAuth that does not match the stored digest. The exact numeric values are firmware specific; they are not defined in public Nations material or in the source tree, so take them from the Nations integration guide for your firmware revision rather than from a fixed table here. + +### Auto-SPDM + +Call `wolfTPM2_InitWithSpdmKey()` with the trusted responder key for identity mode, or `wolfTPM2_InitWithSpdmPsk()` with the provisioned PSK for PSK mode. Both entry points recover a TPM that is already locked in SPDM-only mode. The identity-mode initialization sequence is: + +1. `TPM2_Startup` probes whether the TPM is already in SPDM-only mode. +2. The caller-provided responder key is installed as the trust anchor. +3. The discovered responder key is compared with that trusted key. +4. An SPDM session is always established (P-384 keygen and handshake). +5. If the probe returned `TPM_RC_DISABLED`, `TPM2_Startup` is retried securely. +6. All subsequent commands go through the SPDM encrypted channel. + +In a dual-vendor build, `wolfTPM2_InitWithSpdmKey()` selects the identity adapter from the TPM DID/VID. A transport that does not expose DID/VID must call `wolfTPM2_InitWithSpdmKey_ex()` with `WOLFSPDM_MODE_NUVOTON` or `WOLFSPDM_MODE_NATIONS`. Automatic mode fails closed rather than guessing. + +`wolfTPM2_Init()` without a credential fails closed if it detects any SPDM-only mode. For a normal-mode TPM that does not require an immediate secure channel, identity-mode applications may instead call `wolfTPM2_SpdmInit()`, `wolfTPM2_SpdmSetResponderPubKey()`, and then the vendor-specific connect function. + +Both `TPM2_SendCommand` (non-auth commands) and `TPM2_SendCommandAuth` (auth-session commands such as PCR operations, key creation, and signing) are intercepted and routed through SPDM when a session is active. + +### Memory modes + +- Default: zero heap allocation. The SPDM context is a caller-owned inline context of about 32 KB. It is not necessarily static-duration storage; it lives wherever the caller places it. +- Small stack (`--enable-smallstack`): the wolfSPDM context and the SPDM request and response buffers are allocated with `XMALLOC`; some per-command buffers, such as the TPM response buffer and the TIS I/O buffer, stay on the stack. It also lowers three public message-size limits, so an oversized command or response can return `BUFFER_E`. Useful on platforms with small stacks; size payloads to the reduced limits. + +`wolfSPDM_New()` exists only when wolfSPDM is built with `WOLFSPDM_DYNAMIC_MEMORY`. Without it, use `wolfSPDM_InitStatic()` or `wolfSPDM_Init()` on caller-provided storage. + +## wolfSPDM API + +| Function | Description | +|----------|-------------| +| `wolfSPDM_InitStatic()` | Initialize context in caller-provided buffer (static mode) | +| `wolfSPDM_New()` | Allocate and initialize context on heap (only with `WOLFSPDM_DYNAMIC_MEMORY`) | +| `wolfSPDM_Init()` | Initialize a pre-allocated context | +| `wolfSPDM_Free()` | Free context (releases resources; frees heap only if dynamic) | +| `wolfSPDM_GetCtxSize()` | Return `sizeof(WOLFSPDM_CTX)` at runtime | +| `wolfSPDM_SetIO()` | Set transport I/O callback | +| `wolfSPDM_SetResponderPubKey()` | Pin the trusted responder P-384 key (identity mode) | +| `wolfSPDM_SetPSK()` | Set the pre-shared key (PSK mode) | +| `wolfSPDM_SetMode()` | Select the vendor/handshake mode | +| `wolfSPDM_SetRequesterKeyPair()` | Set the host's P-384 key pair used for GIVE_PUB and FINISH | +| `wolfSPDM_SetDebug()` | Enable/disable debug output | +| `wolfSPDM_Connect()` | Full SPDM handshake | +| `wolfSPDM_IsConnected()` | Check session status | +| `wolfSPDM_Disconnect()` | End session | +| `wolfSPDM_SecuredExchange()` | Encrypt/send/receive/decrypt in one call | + +## Troubleshooting + +### Handshake fails after an interrupted session + +Stale SPDM state on the TPM can make the next handshake fail. Reset the TPM. + +- Nuvoton: GPIO 4 is wired to TPM_RST on the Nuvoton daughter board, so a GPIO reset clears the state. See TPM reset pin control for the commands. +- Nations NS350: the tested daughter board also wires GPIO 4 to TPM_RST, so the same GPIO reset applies. If your board does not wire it, do a full power cycle. `sudo reboot` is not sufficient because the 3.3V rail stays powered. + +### SPDM error codes + +| Code | Name | Description | +|------|------|-------------| +| 0x01 | InvalidRequest | Message format incorrect | +| 0x04 | UnexpectedRequest | Message out of sequence | +| 0x05 | Unspecified | Unspecified error | +| 0x06 | DecryptError | Decryption or MAC verification failed | +| 0x07 | UnsupportedRequest | Request not supported or format rejected | +| 0x41 | MajorVersionMismatch | SPDM major version mismatch | + +## Standard SPDM support + +The in-tree TPM profile covers only the TCG SPDM binding. For standard SPDM protocol support, including sessions with the DMTF spdm-emu emulator, measurements, challenge authentication, heartbeat, and key update, use the standalone [wolfSPDM](https://github.com/wolfSSL/wolfSPDM) library. Those features are out of scope in wolfTPM. + +## Automated tests + +`spdm_test.sh` runs the full SPDM setup lifecycle: + +```sh +# Nuvoton (identity key, includes GPIO resets between tests) +SPDM_RESPONDER_PUBKEY="$(cat responder_pubkey.hex)" +export SPDM_RESPONDER_PUBKEY +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nuvoton + +# Nations (identity key; the harness also uses GPIO 4 to normalize state) +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations + +# Nations (PSK, full lifecycle: provision, connect, clear, restore) +./examples/spdm/spdm_test.sh ./examples/spdm/spdm_ctrl nations-psk +``` + +The identity-mode hardware runs require `SPDM_RESPONDER_PUBKEY` from a trusted provisioning source (device provisioning records). The PSK run does not use it. The `fwtpm-tcg` test instead reads the freshly generated public key from the owner-only server log created by the test harness and passes it through the same pinning interface. This local bootstrap is not a hardware provisioning mechanism. + +For production use with hardware TPMs and SPDM support, contact support@wolfssl.com. + +## See Also + +- [fwtpm/spdm.md](fwtpm/spdm.md) +- [post-quantum.md](post-quantum.md) +- [FWTPM.md](fwtpm/overview.md) +- [DEVTPM.md](system-interfaces.md) diff --git a/docs/stm32cube.md b/docs/stm32cube.md new file mode 100644 index 00000000..2cabe7ba --- /dev/null +++ b/docs/stm32cube.md @@ -0,0 +1,27 @@ +# STM32CubeIDE + +wolfTPM is available as an STM32 Cube Pack, `I-CUBE-wolfTPM.pack`, downloadable from https://www.wolfssl.com/files/ide/I-CUBE-wolfTPM.pack. The pack has an optional but recommended dependency on the wolfCrypt library. The files live in `IDE/STM32CUBE` in the wolfTPM source tree. + +!!! note + This page is short and will be expanded later. + +## Setup + +1. Set up the wolfCrypt library in your ST project by following the wolfSSL STM32Cube guide: https://github.com/wolfSSL/wolfssl/blob/master/IDE/STM32Cube/README.md. To run the wolfTPM unit tests, name the entry function `wolfTPMTest` instead of `wolfCryptDemo`. +2. Install the wolfTPM Cube Pack in the same way as the wolfSSL pack, using CubeMX. +3. Open the project `.ioc` file, click the `Software Packs` drop-down menu, then `Select Components`. Expand the `wolfTPM` pack and check all the components. +4. In the `Software Packs` configuration category of the `.ioc` file, click the wolfTPM pack and enable the library by checking the box. +5. In the `Connectivity` category, find and enable SPI for your project. +6. In the `Software Packs` configuration category, open the wolfTPM pack and set the `Enable wolfCrypt` parameter to True. +7. Save your changes and answer yes to the prompt asking about generating code. +8. Build the project and run the unit tests on the target. + +## Notes + +Redirect `printf` to the UART so the test output is visible. See the [STM32 printf changes](https://github.com/wolfSSL/wolfssl/tree/master/IDE/STM32Cube#stm32-printf) in the wolfSSL guide. + +## See Also + +- [Building](building.md), for the bare-metal build options +- [System Interfaces](system-interfaces.md), for the SWTPM over UART example on STM32H5 +- [Embedded Integrations](embedded-integrations.md) diff --git a/docs/supported-hardware.md b/docs/supported-hardware.md new file mode 100644 index 00000000..406c1ddc --- /dev/null +++ b/docs/supported-hardware.md @@ -0,0 +1,199 @@ +# Supported Hardware + +wolfTPM talks to TPM 2.0 parts over SPI or I2C through a single HAL I/O callback, or to a system TPM through the operating system driver. This page lists the platforms wolfTPM has HAL backends for, the hardware it has been tested with, the configure flag for each part, and the build steps for each vendor. + +## Platform + +The hardware examples are most often run on a Raspberry Pi using the Linux `spidev` interface. That is the example platform, not a requirement. The Linux HAL picks a default SPI chip select per vendor: Infineon builds use `/dev/spidev0.1`, while Microchip, ST, Nuvoton, Nations Technologies and SEALSQ builds use `/dev/spidev0.0`. Override the device with `TPM2_SPI_DEV_PATH` and `TPM2_SPI_DEV_CS` if your wiring differs. + +To interface with your hardware bus (SPI or I2C), wolfTPM uses a single HAL callback. You pass it during initialization when calling `TPM2_Init` or `wolfTPM2_Init`. See [HAL IO Callback](hal-io-callback.md) for the callback model. + +Example HAL implementations are provided in the `hal` directory for: + +* Atmel ASF (`tpm_io_atmel.c`) +* Barebox (`tpm_io_barebox.c`) +* Espressif ESP-IDF (`tpm_io_espressif.c`) +* Firmware TPM (`tpm_io_fwtpm.c`) +* Infineon TriCore and PSoC/CyHAL (`tpm_io_infineon.c`) +* Linux SPI and I2C (`tpm_io_linux.c`) +* Memory-mapped I/O (`tpm_io_mmio.c`) +* Microchip Harmony (`tpm_io_microchip.c`) +* QNX (`tpm_io_qnx.c`) +* STM32 CubeMX (`tpm_io_st.c`) +* U-Boot (`tpm_io_uboot.c`) +* wolfHAL (`tpm_io_wolfhal.c`) +* Xilinx (`tpm_io_xilinx.c`) +* Zephyr (`tpm_io_zephyr.c`) + +An advanced I/O option (`--enable-advio` or `WOLFTPM_ADV_IO`) adds the register address and a read/write flag as parameters to the I/O callback. This is required for I2C support, and `--enable-i2c` turns it on. + +## Tested Hardware + +wolfTPM has been tested with: + +* Infineon OPTIGA(TM) Trusted Platform Module 2.0 SLB9670 (SPI), SLB9672 (SPI) and SLB9673 (I2C). + * [LetsTrust](https://letstrust.de) is a vendor of TPM development boards. +* STMicroelectronics ST33KTPM2XSPI, ST33KTPM2I, ST33TPHF2XSPI (SPI) and ST33TPHF2XI2C (I2C). +* Microchip ATTPM20 module. +* Nuvoton NPCT650 and NPCT750 TPM 2.0 modules. +* Nations Technologies Z32H330 and NS350 TPM 2.0 modules. +* SEALSQ QVault TPM 2.0 module (SPI, post-quantum ML-DSA and ML-KEM). +* NVIDIA Jetson Orin (Tegra234) firmware TPM: a TPM 2.0 running as an OP-TEE trusted application, reached through the Linux kernel driver rather than a bus. See [System Interfaces](system-interfaces.md). + +The firmware updater also recognizes the ST33KTPM2A firmware line, but that part is not in the tested list. + +Device identification is printed in two steps. A direct bus connection first prints a `TPM2: Caps ... Did ... Vid ... Rid` line read from the TIS registers. A second `Mfg ...` line then reports the manufacturer, vendor string, firmware version and certification flags. A firmware TPM has no TIS registers, so it prints only the second line. See [TPM 2.0 Overview](tpm2-overview.md) for captured output from each tested module. + +## Supported Parts + +| Vendor | Part(s) | Bus | configure flag | Notes | +| ------ | ------- | --- | -------------- | ----- | +| Infineon | SLB9670 | SPI | `--enable-infineon=slb9670` | Library SPI clock default 43 MHz. AES key size limited to 128 bits. | +| Infineon | SLB9672 | SPI | `--enable-infineon` | Default for SPI. Library SPI clock default 33 MHz. Supports firmware upgrade. | +| Infineon | SLB9673 | I2C | `--enable-infineon=slb9673 --enable-i2c --enable-advio` | I2C only, so no SPI clock applies. | +| STMicroelectronics | ST33KTPM2XSPI, ST33TPHF2XSPI | SPI | `--enable-st33` | Library SPI clock default 33 MHz. Wait states required. | +| STMicroelectronics | ST33KTPM2I, ST33TPHF2XI2C | I2C | `--enable-st33 --enable-i2c` | Wait states required. Firmware upgrade support is on by default. | +| Microchip | ATTPM20 | SPI | `--enable-microchip` | Library SPI clock default 33 MHz. Wait states required. | +| Nuvoton | NPCT650, NPCT750 | SPI | `--enable-nuvoton` | Library SPI clock default 43 MHz. Wait states required. | +| Nations Technologies | Z32H330, NS350 | SPI | `--enable-nations` | Wait states required (`WOLFTPM_CHECK_WAIT_STATE`, enabled for Nations builds). | +| SEALSQ | QVault TPM 2.0 | SPI | `--enable-sealsq` | Library SPI clock default 33 MHz. Wait states required. Post-quantum commands also need `--enable-pqc` or `--enable-v185`. | +| NVIDIA | Jetson Orin (Tegra234) firmware TPM | None (kernel driver) | `--enable-autodetect` or `--enable-devtpm` | Accessed through `/dev/tpmrm0`, falling back to `/dev/tpm0`. No bus flag. | + +The SPI clocks in this table are library defaults from `wolftpm/tpm2_types.h`, not the electrical limits of each part. The part limits are set by the vendor datasheets and can be lower or higher: + +* **Infineon SLB9670:** 43 MHz is allowed only at 3.3 V with a sufficiently fast SCLK edge. The limit is lower at 1.8 V or with slower edges. +* **Infineon SLB9672:** the datasheet gives 33 MHz nominal and 34.65 MHz maximum. +* **STMicroelectronics:** ST33KTPM2X supports up to 66 MHz, ST33KTPM2I up to 48 MHz and ST33TPHF2XSPI up to 33 MHz. wolfTPM uses 33 MHz for all ST parts. +* **Microchip ATTPM20:** rated to 36 MHz, but wolfTPM uses 33 MHz because of issues at the higher rate. +* **SEALSQ QVault:** the datasheet lists 33 MHz in its summary and 36 MHz in its timing table. wolfTPM uses the conservative 33 MHz. + +!!! note + The part limits above come from vendor datasheets and were not checked against code in this repository. Confirm them against the current datasheet for your part. + +To change the SPI clock, define `TPM2_SPI_MAX_HZ` at build time, for example `CFLAGS="-DTPM2_SPI_MAX_HZ=20000000"`. The default for a selected vendor is set in `wolftpm/tpm2_types.h`. I2C builds on Linux default to 400 kHz (`TPM2_I2C_HZ`). + +## Autodetect and the Kernel Device + +When no vendor flag is given, `--enable-autodetect` is on by default. It detects the module at run time. With autodetect, wolfTPM turns on wait state checking and caps the SPI clock at 33 MHz, the lowest default among the supported parts. This cap applies when wolfTPM falls back to direct SPI access, where it tries `/dev/spidev0.0` through `/dev/spidev0.4`. + +On Linux, autodetect and `--enable-devtpm` first try the kernel TPM device. The driver opens `/dev/tpmrm0` (the resource manager, kernel 5.12 and later) and falls back to `/dev/tpm0` if it is not present. Define `WOLFTPM_USE_TPMRM` to use only the resource manager, or set `TPM2_LINUX_DEV` to pin a specific device. See [System Interfaces](system-interfaces.md). + +## Building per Vendor + +All builds start from a clone of the repository: + +```sh +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM +``` + +### Infineon + +Supports SLB9670 or SLB9672 (SPI) and SLB9673 (I2C). Pick one of the following. + +SLB9672 on SPI (the default for `--enable-infineon`): + +```sh +./autogen.sh +./configure --enable-infineon +make +``` + +SLB9670 on SPI: + +```sh +./autogen.sh +./configure --enable-infineon=slb9670 +make +``` + +SLB9673 on I2C: + +```sh +./autogen.sh +./configure --enable-infineon=slb9673 --enable-i2c --enable-advio +make +``` + +### STMicroelectronics ST33 + +SPI parts (ST33KTPM2XSPI, ST33TPHF2XSPI): + +```sh +./autogen.sh +./configure --enable-st33 +make +``` + +I2C parts (ST33KTPM2I, ST33TPHF2XI2C): + +```sh +./autogen.sh +./configure --enable-st33 --enable-i2c +make +``` + +Firmware upgrade support is enabled by default (`--enable-firmware`), which builds the `st33_fw_update` example tool. Pass `--disable-firmware` to leave it out. + +Raspberry Pi wiring: the ST33KTPM2X SPI device is `/dev/spidev0.0`, with nRST (active low) on GPIO24 (pin 18). Nuvoton uses GPIO4. You can optionally drive nRST from code with `--enable-hal-reset` and `TPM2_IoCb_Reset()`. See [HAL IO Callback](hal-io-callback.md). + +### Microchip ATTPM20 + +```sh +./autogen.sh +./configure --enable-microchip +make +``` + +### Nuvoton + +```sh +./autogen.sh +./configure --enable-nuvoton +make +``` + +### Nations Technologies + +Pass `--enable-nations`. Without it, a default `./configure` does not define `WOLFTPM_NATIONS`, so the Nations settings and vendor commands are not built. Z32H330 and NS350 are the tested modules. The NS350 Raspberry Pi TPM 2.0 module uses `/dev/spidev0.0`. Wait states are required and are turned on for Nations builds through `WOLFTPM_CHECK_WAIT_STATE`. + +```sh +./autogen.sh +./configure --enable-nations +make +``` + +### SEALSQ QVault + +Build with `--enable-sealsq` for the ordinary TPM commands. The ML-DSA and ML-KEM commands are gated separately, so also pass `--enable-pqc` (lean post-quantum subset) or `--enable-v185` (full v1.85 command set), which require a wolfSSL build with ML-DSA and ML-KEM. The post-quantum build options are covered in [Post-Quantum Support](post-quantum.md). + +```sh +./autogen.sh +./configure --enable-sealsq --enable-pqc +make +``` + +### Espressif ESP-IDF + +The ESP-IDF component needs a wolfSSL source tree. If CMake cannot find one, it stops with the error "Could not find wolfssl". Place a wolfSSL checkout in a parent directory named `wolfssl`, `wolfssl-master` or `wolfssl-`, or point the `WOLFSSL_ROOT` variable at it. The wolfSSL ESP Registry managed component also works as an alternative. + +The wolfTPM-specific settings are in the wolfSSL `user_settings.h` file, typically found in `[project]/components/wolfssl/include`. + +```sh +git clone https://github.com/wolfSSL/wolfssl.git +git clone https://github.com/wolfSSL/wolfTPM.git +cd wolfTPM/IDE/Espressif + +# set your path to ESP-IDF, shown here for VisualGDB using v5.2 +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.2 + +. "${WRK_IDF_PATH}/export.sh" +idf.py build +``` + +## See Also + +* [HAL IO Callback](hal-io-callback.md) +* [System Interfaces](system-interfaces.md) +* [TPM 2.0 Overview](tpm2-overview.md) +* [Post-Quantum Support](post-quantum.md) diff --git a/docs/system-interfaces.md b/docs/system-interfaces.md new file mode 100644 index 00000000..1b1a78fe --- /dev/null +++ b/docs/system-interfaces.md @@ -0,0 +1,518 @@ +# System Interfaces + +Besides talking directly to a TPM chip over SPI or I2C, wolfTPM can reach a TPM through an operating system interface or a software simulator. This page covers the three of them: the software TPM simulators (SWTPM), the Linux kernel device (`/dev/tpmX`), and the Windows TBS API. Only one transport can be enabled in a given build. + +## Software simulator (SWTPM) + +wolfTPM can use a software TPM defined by section D.3 of [TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code](https://trustedcomputinggroup.org/wp-content/uploads/TPM-Rev-2.0-Part-4-Supporting-Routines-01.38-code.pdf). + +Software TPM implementations tested: + +* [Official TCG Reference](https://github.com/TrustedComputingGroup/TPM): reference code from the specification maintained by TCG. See [TCG TPM](#tcg-tpm). +* [IBM (ibmswtpm2) / Ken Goldman](https://github.com/kgoldman/ibmswtpm2): a fork of the reference code maintained by IBM (93% identical to the official TCG code). See [ibmswtpm2](#ibmswtpm2). +* [Microsoft ms-tpm-20-ref](https://github.com/microsoft/ms-tpm-20-ref): a fork of the reference code maintained by Microsoft (100% identical to the official TCG code). See [ms-tpm-20-ref](#ms-tpm-20-ref). +* [libtpms/swtpm by Stefan Berger](https://github.com/stefanberger/swtpm): uses the libtpms front end interfaces. See [swtpm](#swtpm). + +The software TPM transport is a socket connection by default. A UART is also supported. This implementation only uses the TPM command interface, typically on port 2321. It does not support the platform interface, typically on port 2322. + +### wolfTPM SWTPM support + +To enable the socket transport for SWTPM use `--enable-swtpm`. By default all software TPM simulators use TCP port 2321. + +```sh +./configure --enable-swtpm +make +``` + +!!! note + It is not possible to enable more than one transport interface at a time. When building with the SWTPM socket interface, the built-in TIS and devtpm (`/dev/tpm0`) interfaces are not available. + +Build options: + +* `WOLFTPM_SWTPM`: use the socket transport (no TIS layer) +* `TPM2_SWTPM_HOST`: the socket host (default is localhost) +* `TPM2_SWTPM_PORT`: the socket port (default is 2321) + +### wolfTPM SWTPM UART support + +To use the SWTPM protocol over a UART serial connection instead of TCP sockets, use `--enable-swtpm=uart`. This is intended for talking to a firmware TPM (fwTPM) running on an embedded target, such as the wolfTPM fwTPM server on STM32H5. + +```sh +./configure --enable-swtpm=uart +make +``` + +The serial device path and baud rate can be set at compile time or at runtime: + +```sh +# Runtime override via environment variable +TPM2_SWTPM_HOST=/dev/ttyACM0 ./examples/wrap/caps +``` + +Build options: + +* `WOLFTPM_SWTPM_UART`: use the UART serial transport (set automatically by `--enable-swtpm=uart`) +* `TPM2_SWTPM_HOST`: the serial device path (default is `/dev/ttyACM0` on Linux and `/dev/cu.usbmodem` on macOS). It can be overridden at runtime with the `TPM2_SWTPM_HOST` environment variable. +* `TPM2_SWTPM_PORT`: the baud rate (default is 115200) + +The UART transport uses the same mssim protocol as the socket transport. The serial port is configured as 8N1 raw mode with no flow control. Like the socket transport, the serial port file descriptor is kept open across commands (no reconnect per command). Both transports close the connection during `wolfTPM2_Cleanup`. On the socket transport, any transmit or receive failure also closes the connection so the next command reconnects. The UART transport closes only when the per-command `TPM_SESSION_END` write fails. + +#### Security note: environment variable override + +The `TPM2_SWTPM_HOST` environment variable is a development convenience that overrides the compile-time serial device path. On systems where untrusted local users share the environment with the TPM client, an attacker could redirect TPM I/O to a rogue device, such as a PTY they control. For production and hardened deployments: + +* Unset `TPM2_SWTPM_HOST` in the process environment. +* Rely on the compile-time default (set via `TPM2_SWTPM_HOST` as a build `-D` macro) to pin the serial path. + +The same guidance applies to `TPM2_SWTPM_PORT` (baud rate) and, for the socket transport, to using the environment variable to redirect the TCP host. + +#### Example: wolfTPM fwTPM on STM32H5 + +The wolfTPM project includes a firmware TPM server port for STM32 Cortex-M33 targets with TrustZone support. See [wolftpm-examples/STM32/fwtpm-stm32h5](https://github.com/wolfSSL/wolftpm-examples/tree/main/STM32/fwtpm-stm32h5) for build, flash, and test instructions. + +```sh +# Build host client with UART transport +./configure --enable-swtpm=uart +make + +# Run examples against STM32 fwTPM (adjust device path as needed) +export TPM2_SWTPM_HOST=/dev/ttyACM0 +./examples/wrap/caps +./examples/keygen/keygen -ecc +./examples/seal/seal +``` + +### Using a SWTPM + +#### SWTPM Power Up and Startup + +The TCG TPM and Microsoft ms-tpm-20-ref implementations require power up and startup commands on the platform interface before the command interface is enabled. Use these commands to issue the required power up and startup: + +```sh +echo -ne "\x00\x00\x00\x01" | nc 127.0.0.1 2322 +echo -ne "\x00\x00\x00\x0B" | nc 127.0.0.1 2322 +``` + +#### TCG TPM + +```sh +git clone git@github.com:TrustedComputingGroup/TPM.git +cd TPM +cd TPMCmd +./bootstrap +./configure +make +``` + +Run with `./Simulator/src/tpm2-simulator`, then run power on and self test. See [SWTPM Power Up and Startup](#swtpm-power-up-and-startup). + +#### ibmswtpm2 + +```sh +git clone https://github.com/kgoldman/ibmswtpm2.git +cd ibmswtpm2/src/ +make +``` + +Run with `./tpm_server`. + +!!! note + You can use the `-rm` switch to remove the cache file NVChip. Alternatively, delete the NVChip file (`rm NVChip`). + +#### ms-tpm-20-ref + +```sh +git clone https://github.com/microsoft/ms-tpm-20-ref +cd ms-tpm-20-ref/TPMCmd +./bootstrap +./configure +make +``` + +Run with `./Simulator/src/tpm2-simulator`, then run power on and self test. See [SWTPM Power Up and Startup](#swtpm-power-up-and-startup). + +#### swtpm + +Build libtpms: + +```sh +git clone git@github.com:stefanberger/libtpms.git +cd libtpms +./autogen.sh --with-tpm2 --with-openssl --prefix=/usr +make install +``` + +Build swtpm: + +```sh +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +./autogen.sh +make install +``` + +On macOS, do the following first: + +```sh +brew install openssl socat +pip3 install cryptography + +export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" +export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" + +# libtpms had to use --prefix=/usr/local +``` + +Run swtpm: + +```sh +mkdir -p /tmp/myvtpm +swtpm socket --tpmstate dir=/tmp/myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init +``` + +#### swtpm with QEMU + +This demonstrates using wolfTPM in QEMU to communicate through the Linux kernel device `/dev/tpmX`. You need to install or build [swtpm](https://github.com/stefanberger/swtpm). A short build method is below. You may need to consult the instructions for [libtpms](https://github.com/stefanberger/libtpms/wiki#compile-and-install-on-linux) and [swtpm](https://github.com/stefanberger/swtpm/wiki#compile-and-install-on-linux). + +```sh +PREFIX=$PWD/inst +git clone git@github.com:stefanberger/libtpms.git +cd libtpms/ +./autogen.sh --with-openssl --with-tpm2 --prefix=$PREFIX && make install +cd .. +git clone git@github.com:stefanberger/swtpm.git +cd swtpm +PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig/ ./autogen.sh --with-openssl --with-tpm2 \ + --prefix=$PREFIX && \ + make install +cd .. +``` + +Set up a basic Linux installation. Other installation bases can be used. This step takes some time to install the base Linux system. + +```sh +# download mini install image +curl -O http://archive.ubuntu.com/ubuntu/dists/bionic-updates/main/installer-amd64/current/images/netboot/mini.iso +# create qemu image file +qemu-img create -f qcow2 lubuntu.qcow2 5G +# create directory for tpm state and socket +mkdir $PREFIX/mytpm +# start swtpm +$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ + --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & +# start qemu for installation +qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 -cdrom mini.iso +``` + +Once a base system is installed, start QEMU again and build wolfSSL and wolfTPM in the QEMU instance. + +```sh +# start swtpm again +$PREFIX/bin/swtpm socket --tpm2 --tpmstate dir=$PREFIX/mytpm \ + --ctrl type=unixio,path=$PREFIX/mytpm/swtpm-sock --log level=20 & +# start qemu system to install and run wolfTPM +qemu-system-x86_64 -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ + -chardev socket,id=chrtpm,path=$PREFIX/mytpm/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 -hda lubuntu.qcow2 +``` + +In the QEMU terminal, check out and build wolfTPM: + +```sh +sudo apt install automake libtool gcc git make + +# get and build wolfSSL +git clone https://github.com/wolfssl/wolfssl.git +pushd wolfssl +./autogen.sh && \ + ./configure --enable-wolftpm --disable-examples --prefix=$PWD/../inst && \ + make install +popd + +# get and build wolfTPM +git clone https://github.com/wolfssl/wolftpm.git +pushd wolftpm +./autogen.sh && \ + ./configure --enable-devtpm --prefix=$PWD/../inst --enable-debug && \ + make install +sudo make check +popd +``` + +You can now run examples such as `sudo ./examples/wrap/wrap` within QEMU. `sudo` may be required for access to `/dev/tpm0`. + +### Running examples + +```sh +./examples/wrap/caps +./examples/pcr/extend +./examples/wrap/wrap_test +``` + +See `examples/README.md` in the source tree for additional example usage. + +## Linux kernel device (/dev/tpmX) + +On Linux the kernel TPM driver stack exposes a TPM through a character device, and wolfTPM can use it directly instead of driving SPI or I2C itself. This is the right transport whenever the kernel already owns the TPM: a discrete chip bound to a kernel driver, a Windows-style firmware TPM, or a TEE-resident firmware TPM such as the one on NVIDIA Jetson platforms. + +With `--enable-devtpm` there is no TIS layer and no HAL IO callback. `hal/tpm_io.c` is compiled out entirely and `TPM2_IoCb` is `NULL` (see `hal/tpm_io.h`), so pass `NULL` for the callback argument of `TPM2_Init` and `wolfTPM2_Init`. + +With `--enable-autodetect` this is not the case. The TIS/SPI HAL stays compiled in on purpose, because it is the fallback, and `TPM2_IoCb` is a real function. Keep passing it, or the SPI fallback that build exists to provide is unreachable. + +### Two device nodes + +The kernel presents up to two nodes per TPM: + +* `/dev/tpm0`: the raw device. One user at a time, no resource management. Whatever you send reaches the TPM. +* `/dev/tpmrm0`: the in-kernel resource manager (kernel 4.12 and later, practical from 5.12). It virtualizes handles, swaps transient objects and sessions in and out as needed, and flushes everything belonging to a connection when that connection closes. + +wolfTPM prefers `/dev/tpmrm0` and falls back to `/dev/tpm0`. The resource manager is the better default: a TPM has very few transient object slots, and without it a program that leaks a handle wedges the TPM for everything else on the system. + +Build-time overrides, honored by both `--enable-devtpm` and `--enable-autodetect`: + +* `-DWOLFTPM_USE_TPMRM`: use `/dev/tpmrm0` only, with no fallback to the raw device. +* `CFLAGS='-DTPM2_LINUX_DEV="/dev/tpm1"'`: use a specific node. The inner quotes are required, because the macro is used directly as a C string literal and an unquoted value does not compile. + +### Startup, shutdown, and shared state + +The TPM is started by firmware long before Linux runs, and on the resource manager it is shared with every other process on the system. Restarting or shutting it down is therefore not an individual caller's decision, so wolfTPM stays out of the way on this transport: + +* `wolfTPM2_Init` skips the startup and self-test sequence. +* `wolfTPM2_Reset` and `wolfTPM2_Shutdown` send no TPM command and return `NOT_COMPILED_IN` (-174), the same way `wolfTPM2_SetLocality` does on this transport. A `wolfTPM2_Reset(dev, 0, 0)` that asked for neither a shutdown nor a startup still returns `TPM_RC_SUCCESS`, since nothing was declined. Treat `NOT_COMPILED_IN` here as "the OS owns this", not as a failure. +* `wolfTPM2_SetLocality` returns `NOT_COMPILED_IN` because the kernel owns the locality. + +The kernel does not reliably stop you here. Command filtering on `/dev/tpmrm0` is primarily about handle isolation, not about blocking global state changes, and behavior varies by kernel version and TPM implementation. On Linux 5.15 with the Jetson OP-TEE fTPM, a `TPM2_Shutdown(TPM_SU_CLEAR)` sent through the resource manager is passed straight through and returns success, both from wolfTPM and from `tpm2_shutdown`. So this is a case where the library declining to send the command is what protects other users of the TPM, rather than the kernel doing it for you. + +If you need to control TPM startup state, you need `/dev/tpm0` and exclusive use of the TPM, or direct SPI access with the wolfTPM TIS driver. + +### What the native API does on autodetect builds + +Two behaviors matter if you use `TPM2_Init` or `TPM2_Init_ex` directly rather than the `wolfTPM2_*` wrapper. + +The kernel device wins over your callback. If `/dev/tpmrm0` or `/dev/tpm0` opens, every command is routed there and the HAL IO callback you passed is never invoked. On a host that has both a kernel-bound TPM and a discrete SPI part, that means you now talk to a different TPM than a pre-autodetect build did. `--enable-spi` on its own does not pin SPI, because it leaves autodetect on and the kernel device still wins. Pin the part you want with `--enable-devtpm`, `--enable-`, `--enable-spi --disable-autodetect`, or `-DTPM2_LINUX_DEV`. + +Init now acquires a descriptor. `TPM2_Init*` opens the device on autodetect builds, and `TPM2_Cleanup()` is what closes it. Native callers that skipped cleanup previously leaked nothing, but now they leak a descriptor per context. This matters most on hosts exposing only the raw `/dev/tpm0`, which permits a single open. A context that merely initialized holds the TPM exclusively for its lifetime, and a second context in the same process falls through to a different transport. + +`TPM2_Init_minimal()` is unaffected: it performs no IO and still succeeds with no device present. + +### Transient handles do not outlive a process + +This is the difference most likely to break an existing application. + +On `/dev/tpmrm0` the kernel gives each open file description its own handle space. Transient object handles are virtualized (the value the TPM assigned is not the value you get back), and everything in that space is flushed when the file descriptor closes. A transient key created by one process is gone by the time a second process runs, and the handle number it printed is meaningless to anyone else. + +Creating a primary key on the Jetson fTPM through the resource manager returns: + +``` +Create Primary Handle: 0x80ffffff +``` + +This is not the `0x80000000` a raw device would report. Query the transient handles from a separate process afterwards and the list is empty: + +```bash +tpm2_getcap handles-transient # no output, the space was torn down +``` + +Two practical consequences: + +* A "create a key, keep it, use it from the next command" workflow does not work across processes. Do the whole sequence in one process, or make the object persistent with `TPM2_EvictControl` so it gets a stable `0x81xxxxxx` handle that does survive. +* Passing a hard-coded transient handle such as `0x80000000` on a command line fails. The kernel rejects the reference before it reaches the TPM, and because that happens at the file-descriptor layer the error surfaces as `errno 22 = Invalid argument` on `read()`, which wolfTPM reports as `TPM_RC_FAILURE` rather than as a handle error. If you see `TPM_RC_FAILURE` alongside `Failed to read from /dev/tpmrm0 ... errno 22`, suspect a stale or cross-process transient handle before suspecting the TPM. + +The wolfTPM script `examples/run_examples.sh` hits exactly this: its provisioning section creates IAK and IDevID primaries with `-keep` in one process and then references `0x80000000` and `0x80000001` from another. That block cannot pass on the resource manager by construction. Everything on either side of it is unaffected. Use `/dev/tpm0` with exclusive access if you need to run it as written. + +### Building + +```bash +./autogen.sh +./configure --enable-devtpm +make +``` + +`--enable-devtpm` uses the kernel node only. Use `--enable-autodetect` instead if you want wolfTPM to try `/dev/tpmrm0`, then `/dev/tpm0`, and finally fall back to probing SPI. This is useful for one binary that has to run on several boards. + +Only one transport can be enabled at a time. `--enable-devtpm` conflicts with `--enable-swtpm` and `--enable-winapi`, and configure stops if you ask for more than one. + +#### The x86_64 and aarch64 default + +A bare `./configure` on Linux x86_64 or aarch64 does not produce a build that talks to `/dev/tpmX`. On those hosts wolfTPM auto-enables the software TPMs (swTPM and fwTPM) so that `make check` passes with no hardware attached, and defining `WOLFTPM_SWTPM` suppresses the kernel-device autodetect path. The result talks to a simulator on TCP port 2321. + +Selecting any hardware path explicitly turns that default back off: `--enable-autodetect`, `--enable-devtpm`, `--enable-spi`, `--enable-i2c`, `--enable-mmio`, `--enable-winapi`, `--enable-wintbs`, or any `--enable-`. Configure prints a notice when the software default is taken, so check the end of its output if a build unexpectedly fails to find your TPM. + +This matters most on single-board aarch64 machines with a firmware TPM, where the kernel device is the only transport there is. + +### Permissions + +The TPM character devices are not world-accessible. On a typical system they are mode `0660` owned by group `tss`: + +``` +crw-rw---- 1 tss root 10, 224 /dev/tpm0 +crw-rw---- 1 tss tss 252, 65536 /dev/tpmrm0 +``` + +wolfTPM detects `EACCES` and reports it plainly: + +``` +Permission denied on /dev/tpm0 +Use sudo or add tss group to user. +``` + +The fix is to put your user in the owning group and start a new login session: + +```bash +sudo usermod -aG tss $USER +``` + +The `tss` group is created by tpm2-tss. On distributions that ship it, the group frequently exists with no members, so this step is required even though the group looks correctly set up. + +To use a group of your own instead, add a udev rule. + +1. Create the group and add your user: + + ```bash + sudo addgroup wolftpm + sudo adduser [username] wolftpm + ``` + +2. Create `/etc/udev/rules.d/wolftpm-udev.rules` containing: + + ``` + KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", GROUP="wolftpm" + ``` + +3. Reload the rules with `sudo udevadm control -R`, then re-plug or reboot. + +### NVIDIA Jetson Orin (Tegra234) firmware TPM + +Jetson Orin platforms carry a TPM 2.0 implemented in firmware, running as a trusted application inside OP-TEE rather than as a discrete package on a bus. Linux reaches it through the `tpm_ftpm_tee` driver, which speaks to the TA over the TEE interface and registers an ordinary TPM chip. From the point of view of wolfTPM it is just another `/dev/tpmrm0`. + +Confirm the device is present before building: + +```bash +lsmod | grep tpm_ftpm_tee +ls -l /dev/tpm* +cat /sys/class/tpm/tpm0/tpm_version_major # expect 2 +``` + +If the module is missing, try `sudo modprobe tpm_ftpm_tee` and check that the kernel was configured with `CONFIG_TCG_FTPM_TEE`. On NVIDIA Jetson Linux (L4T) images the driver is present and an `fTPM Device Provisioning Service` systemd unit runs at boot. You can see it complete in the boot log. + +An OP-TEE boot message about silicon-identity fTPM provisioning not being enabled refers to a separate NVIDIA feature. It does not mean the TPM 2.0 device is unavailable. + +Build as above with `--enable-devtpm` or `--enable-autodetect`, then confirm with: + +```bash +./examples/wrap/caps +``` + +Because this is a firmware TPM, expect two differences from a discrete part. There is no TIS bus, so the `TPM2: Caps/Did/Vid/Rid` values do not exist and the device is identified purely from `TPM2_GetCapability` properties. Under `--enable-devtpm` the `DEBUG_WOLFTPM` line is still printed but reads all zeros. Under `--enable-autodetect`, `wolfTPM2_Init_ex` returns as soon as the kernel device opens, before that printf, so the line is absent entirely. Also, the algorithm coverage of a firmware TPM is set by its firmware build rather than by a datasheet, so check it rather than assuming. Where an operation is absent, the benchmark reports it as unsupported rather than failing. The Jetson Orin fTPM supports every operation the benchmark exercises. + +### Testing + +The examples run unchanged on this transport: + +```bash +./examples/wrap/caps +./examples/native/native_test +./examples/wrap/wrap_test +./examples/bench/bench +./examples/run_examples.sh +``` + +`run_examples.sh` already skips the locality test on backends that do not support it. + +### CI coverage + +Both `--enable-devtpm` and `--enable-autodetect` are build-tested in CI, but not run, because GitHub-hosted runners have no `/dev/tpm*` node. Runtime coverage of this transport requires a self-hosted runner with a real TPM bound to the kernel driver. + +## Windows TBS API + +wolfTPM can be built to use the Windows native TBS (TPM Base Services). When using the Windows TBS interface, NV access is blocked by default. TPM NV storage space is very limited, and when it fills up it can cause undefined behavior, such as failures loading key handles. NV space is not managed by TBS. + +The TPM is designed to return an encrypted private key blob on key creation using `TPM2_Create`, which you can safely store on disk and load when needed. The symmetric encryption key used to protect the private key blob is only known by the TPM. When you load a key using `TPM2_Load` you get a transient handle, which can be used for signing and for encryption and decryption. + +For primary keys created with `TPM2_CreatePrimary` you get back a handle. No encrypted private data is returned. That handle remains loaded until `TPM2_FlushContext` is called. + +For normal key creation using `TPM2_Create` you get back a `TPM2B_PRIVATE outPrivate`, which is the encrypted blob that you can store and load at any time using `TPM2_Load`. + +### Limitations + +wolfTPM has been tested on Windows 10 with TPM 2.0 devices. Windows does support TPM 1.2, but functionality is limited and wolfTPM does not support it. + +The presence of a TPM 2.0 can be checked by opening PowerShell and running `Get-PnpDevice -Class SecurityDevices`: + +``` +Status Class FriendlyName +------ ----- ------------ +OK SecurityDevices Trusted Platform Module 2.0 +Unknown SecurityDevices Trusted Platform Module 2.0 +``` + +### Building in MSYS2 + +Tested using MSYS2: + +```bash +export PREFIX=$PWD/tmp_install + +cd wolfssl +./autogen.sh +./configure --prefix="$PREFIX" --enable-wolftpm +make +make install + +cd wolftpm/ +./autogen.sh +./configure --prefix="$PREFIX" --enable-winapi +make +./examples +``` + +To install the development base tools on MSYS2 use `pacman -S base-devel` and `pacman -S mingw-w64-x86_64-toolchain`. + +### Building on Linux + +Tested using mingw-w32-bin_x86_64-linux_20131221.tar.bz2 from the [MinGW-w64 Win32 toolchain builds](https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds/). + +Extract the tools and add them to the `PATH`: + +```bash +mkdir mingw_tools +cd mingw_tools +tar xjvf ../mingw-w32-bin_x86_64-linux_20131221.tar.bz2 +export PATH=$PWD/bin/:$PWD/i686-w64-mingw32/bin:$PATH +cd .. +``` + +Build: + +```bash +export PREFIX=$PWD/tmp_install +export CFLAGS="-DWIN32 -DMINGW -D_WIN32_WINNT=0x0600 -DUSE_WOLF_STRTOK" +export LIBS="-lws2_32" + +cd wolfssl +./autogen.sh +./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-wolftpm +make +make install + +cd ../wolftpm/ +./autogen.sh +./configure --host=i686 CC=i686-w64-mingw32-gcc --prefix="$PREFIX" --enable-winapi +make +cd .. +``` + +### Running on Windows + +To confirm the presence and status of the TPM on the machine, run `tpm.msc`. See `examples/README.md` in the source tree for running the examples. + +## See Also + +- [Getting Started](getting-started.md) +- [Building wolfTPM](building.md) +- [Build Options](build-options.md) +- [Supported Hardware](supported-hardware.md) diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 00000000..1a8356f3 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,88 @@ +# Testing + +This page describes how to run the wolfTPM tests locally and lists the continuous integration workflows that run on the repository. + +## Running tests locally + +Build and run the main test suite: + +```sh +./configure +make check +``` + +`make check` runs the unit tests, the fwTPM tests and the post-quantum (PQC) tests. The unit test sources are: + +| File | Purpose | +|---|---| +| `tests/unit_tests.c` | wolfTPM library unit tests | +| `tests/fwtpm_unit_tests.c` | fwTPM command processor unit tests | +| `tests/fwtpm_hal_unit_tests.c` | fwTPM HAL unit tests | + +The shell-based tests are: + +| File | Purpose | +|---|---| +| `tests/fwtpm_check.sh` | Entry point used by `make check` for the fwTPM tests | +| `tests/fwtpm_da_retry.sh` | Dictionary attack and retry handling | +| `tests/pqc_mssim_e2e.sh` | Post-quantum end-to-end test | + +To run the example programs against a TPM or simulator: + +```sh +./examples/run_examples.sh +``` + +The script reads these environment variables: + +| Variable | Purpose | +|---|---| +| `WOLFSSL_PATH` | Path to the wolfSSL build used by the examples | +| `WOLFCRYPT_ENABLE` | Set when wolfCrypt support is built in | +| `NO_FILESYSTEM` | Skip examples that need a filesystem | +| `ENABLE_DESTRUCTIVE_TESTS` | Also run tests that change TPM state, such as clearing it | + +!!! warning + Destructive tests modify the TPM. Do not enable them on a TPM that holds keys or data you need. + +## CI workflows + +The workflows live in `.github/workflows/`. The table lists the workflow name from each file. + +| File | Name | +|---|---| +| `_resolve-wolfssl.yml` | Resolve wolfSSL versions | +| `cmake-build.yml` | WolfTPM CMake Build Tests | +| `codeql.yml` | CodeQL | +| `codespell.yml` | Codespell | +| `coverity-scan-fixes.yml` | Coverity Scan master branch | +| `docs-site.yml` | Build manual with documentation tooling | +| `freestanding-build.yml` | Freestanding Build (WOLFTPM_NO_STD_HEADERS) | +| `fuzz.yml` | Fuzz Testing | +| `fwtpm-test.yml` | fwTPM Tests | +| `make-test-swtpm.yml` | WolfTPM Build Tests | +| `multi-compiler.yml` | Multiple Compilers | +| `nightly.yml` | Nightly CI | +| `pqc-build-matrix.yml` | PQC Build Matrix (v1.85 trimming) | +| `pqc-examples.yml` | PQC Examples (v1.85) | +| `publish-ci-image.yml` | Publish wolfTPM CI image | +| `publish-docs-image.yml` | Publish documentation image | +| `release-checks.yml` | Release Checks | +| `rust-test.yml` | WolfTPM Rust Wrapper Tests | +| `sanitizer.yml` | Sanitizer Tests | +| `sbom.yml` | SBOM Test | +| `seal-test.yml` | Seal Test Suite | +| `semgrep.yml` | Semgrep | +| `smoke-test.yml` | Smoke Test | +| `spdm-test.yml` | SPDM Test | +| `win-swtpm-test.yml` | Windows swtpm Transport Test | +| `win-test.yml` | Windows Build Test | +| `wolfhal-build.yml` | wolfHAL Build Tests | +| `wolfssl-versions-pqc.yml` | wolfSSL Version Matrix | +| `zephyr.yml` | Zephyr wolfTPM Tests | + +## See Also + +- [Benchmarks](benchmarks.md) +- [SBOM and Compliance](sbom-and-compliance.md) +- [Release Notes](release-notes.md) diff --git a/docs/tls-and-certificates.md b/docs/tls-and-certificates.md new file mode 100644 index 00000000..49a37c36 --- /dev/null +++ b/docs/tls-and-certificates.md @@ -0,0 +1,241 @@ +# TLS and Certificates + +This page covers the wolfTPM examples that build on TPM keys for certificates and secure connections: generating a certificate signing request (CSR), signing test certificates, PKCS #7 signing, and TLS client and server programs that keep the private key inside the TPM. + +The PKCS #7 and TLS examples create RSA and ECC keys in NV for testing, using handles defined in `./hal/tpm_io.h`. They require generating CSRs and signing them with a test script, as described below. + +## CSR + +The `csr` example (`examples/csr/csr.c`) generates a Certificate Signing Request for building a certificate based on a TPM key pair. + +```sh +./examples/csr/csr +``` + +It creates two files: + +- `./certs/tpm-rsa-cert.csr` +- `./certs/tpm-ecc-cert.csr` + +Options: + +| Option | Description | +|--------|-------------| +| `-cert` | Make a self signed certificate instead of a CSR. | +| `-signcb` | Use the `wc_SignCert_cb` callback based signing. | + +Example output (the base64 body is shortened here): + +```sh +./examples/csr/csr +TPM2 CSR Example +Generated/Signed Cert (DER 860, PEM 1236) +-----BEGIN CERTIFICATE REQUEST----- +MIIDWDCCAkACAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP +BgNVBAcMCFBvcnRsYW5kMQ0wCwYDVQQEDARUZXN0MRAwDgYDVQQKDAd3b2xmU1NM +... +l/076ekjTI+7PwzBZIG2F3nOIDUmHwe0lAWdU8h9IoAlM6kS22fh6gZZqQg= +-----END CERTIFICATE REQUEST----- + +Generated/Signed Cert (DER 467, PEM 704) +-----BEGIN CERTIFICATE REQUEST----- +MIIBzzCCAXUCAQIwgZsxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAP +... +6AIgBm+EU6m5SDsk7BYmxTQAhgJFrelwymOa7m16kAXnFuU= +-----END CERTIFICATE REQUEST----- +``` + +The first request is for the RSA key and the second is for the ECC key. + +!!! note + The CSR example needs wolfSSL built with certificate generation and certificate request support (`--enable-certgen --enable-certreq`) and the crypto callback. + +## Certificate signing + +An external script generates test certificates from the TPM generated CSRs. Normally the CSR would be provided to a trusted CA for signing. + +```sh +./certs/certreq.sh +``` + +The script creates the following X.509 files (also in .pem format): + +- `./certs/ca-ecc-cert.der` +- `./certs/ca-rsa-cert.der` +- `./certs/client-rsa-cert.der` +- `./certs/client-ecc-cert.der` +- `./certs/server-rsa-cert.der` +- `./certs/server-ecc-cert.der` + +## PKCS #7 + +The `pkcs7` example (`examples/pkcs7/pkcs7.c`) signs and verifies data with PKCS #7 using a TPM based key. Run these in order: + +1. `./examples/csr/csr` +2. `./certs/certreq.sh` +3. `./examples/pkcs7/pkcs7` + +The result is displayed on the console. + +| Option | Description | +|--------|-------------| +| `-ecc` / `-rsa` | Use an ECC or RSA key (default is RSA). | +| `-incert=file` | Certificate for the key used. Defaults are `./certs/client-rsa-cert.der` and `./certs/client-ecc-cert.der`. | +| `-out=file` | Write the generated PKCS #7 file containing the signed data and certificate. | + +Example output: + +```sh +./examples/pkcs7/pkcs7 +TPM2 PKCS7 Example +PKCS7 Signed Container 1625 +PKCS7 Container Verified (using TPM) +PKCS7 Container Verified (using software) +``` + +## TLS examples + +The TLS examples use TPM based ECDHE (ECC ephemeral key) support. Compile-time toggles: + +| Define | Effect | +|--------|--------| +| `WOLFTPM2_USE_SW_ECDHE` | Disables use of the TPM for ECC ephemeral key generation and the shared secret. Set with `CFLAGS="-DWOLFTPM2_USE_SW_ECDHE"` or a `#define`. | +| `WOLFTPM_USE_SYMMETRIC` | Enables symmetric AES, hashing and HMAC support through the TPM for the TLS examples. | +| `TLS_USE_ECC` | Forces ECC use with wolfSSL when RSA is also enabled. | + +!!! note + To run the TLS server and client on the same machine, build wolfTPM with `WOLFTPM_TIS_LOCK` (`--enable-tislock`). It enables concurrent access protection for the TPM device. + +The programs are in `examples/tls/`: + +| Program | Purpose | +|---------|---------| +| `tls_client.c` | TLS client that uses a TPM key and certificate for mutual authentication. | +| `tls_server.c` | TLS server that uses a TPM key and certificate. | +| `tls_client_notpm.c` | TLS client that does not use the TPM, for comparison and benchmarking. | + +### Generate the certificates + +Generating the client and server certificates requires running: + +1. `./examples/keygen/keygen rsa_test_blob.raw -rsa -t` +2. `./examples/keygen/keygen ecc_test_blob.raw -ecc -t` +3. `./examples/csr/csr` +4. `./certs/certreq.sh` +5. Copy the CA files from wolfTPM to the wolfSSL certs directory: + +```sh +cp ./certs/ca-ecc-cert.pem ../wolfssl/certs/tpm-ca-ecc-cert.pem +cp ./certs/ca-rsa-cert.pem ../wolfssl/certs/tpm-ca-rsa-cert.pem +``` + +The `wolf-ca-rsa-cert.pem` and `wolf-ca-ecc-cert.pem` files come from the wolfSSL example certificates: + +```sh +cp ../wolfssl/certs/ca-cert.pem ./certs/wolf-ca-rsa-cert.pem +cp ../wolfssl/certs/ca-ecc-cert.pem ./certs/wolf-ca-ecc-cert.pem +``` + +### TLS client + +The client shows a TPM key and certificate used for TLS mutual authentication (client authentication). The wolfSSL TLS client loads a public key to indicate that mutual authentication is used, and the crypto callback uses the TPM for the private key signing. + +By default the client connects to localhost on port 11111. Override with `TLS_HOST` and `TLS_PORT`. + +Start a wolfSSL example server: + +```sh +./examples/server/server -b -p 11111 -g -d -i -V +``` + +To validate the client certificate, use one of these instead: + +```sh +./examples/server/server -b -p 11111 -g -A ./certs/tpm-ca-rsa-cert.pem -i -V +./examples/server/server -b -p 11111 -g -A ./certs/tpm-ca-ecc-cert.pem -i -V +``` + +Then run the wolfTPM TLS client: + +```sh +./examples/tls/tls_client -rsa +./examples/tls/tls_client -ecc +``` + +Example output: + +```sh +./examples/tls/tls_client +TPM2 TLS Client Example +Write (29): GET /index.html HTTP/1.0 + + +Read (193): HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + + + +Welcome to wolfSSL! + + +

wolfSSL has successfully performed handshake!

+ + +``` + +### TLS server + +The server shows a TPM key and certificate used for a TLS server. It loads the TPM public key, and the crypto callback uses the TPM for the private key signing. By default it listens on port 11111, which can be changed at build time with the `TLS_PORT` macro. + +Run the wolfTPM TLS server: + +```sh +./examples/tls/tls_server -rsa +./examples/tls/tls_server -ecc +``` + +Then connect with the wolfSSL example client: + +```sh +./examples/client/client -h localhost -p 11111 -g -d +``` + +To validate the server certificate: + +```sh +./examples/client/client -h localhost -p 11111 -g -A ./certs/tpm-ca-rsa-cert.pem +./examples/client/client -h localhost -p 11111 -g -A ./certs/tpm-ca-ecc-cert.pem +``` + +You can also browse to `https://localhost:11111`. Browsers show certificate warnings until the test CAs `./certs/ca-rsa-cert.pem` and `./certs/ca-ecc-cert.pem` are loaded into the OS key store. For testing, most browsers allow continuing past the warning. + +Example output: + +```sh +./examples/tls/tls_server +TPM2 TLS Server Example +Loading RSA certificate and public key +Read (29): GET /index.html HTTP/1.0 + + +Write (193): HTTP/1.1 200 OK +Content-Type: text/html +Connection: close + + + +Welcome to wolfSSL! + + +

wolfSSL has successfully performed handshake!

+ + +``` + +## See Also + +- [Sealing and NVRAM](sealing-and-nvram.md) +- [Management and GPIO](management-and-gpio.md) +- [Firmware update](firmware-update.md) +- [Supported hardware](supported-hardware.md) diff --git a/docs/tpm2-overview.md b/docs/tpm2-overview.md new file mode 100644 index 00000000..eb1041e0 --- /dev/null +++ b/docs/tpm2-overview.md @@ -0,0 +1,118 @@ +# TPM 2.0 Overview + +This page describes what a TPM is, the hierarchies and PCRs that wolfTPM exposes, the terminology used in the code, and how to identify the TPM module you are talking to. + +wolfTPM is a portable, open-source TPM 2.0 stack with backward API compatibility designed for embedded use. It is highly portable, due to having been written in native C, having a single IO callback for SPI hardware interface, no external dependencies, and its compacted code with low resource usage. wolfTPM offers API wrappers to help with complex TPM operations like attestation and examples to help with complex cryptographic processes like the generation of Certificate Signing Request (CSR) using a TPM. + +## Protocol overview + +Trusted Platform Module (TPM, also known as ISO/IEC 11889) is an international standard for a secure crypto processor, a dedicated micro controller designed to secure hardware through integrated cryptographic keys. Computer programs can use a TPM to authenticate hardware devices, since each TPM chip has a unique and secret RSA key burned in as it is produced. + +A TPM provides the following: + +- A random number generator. +- Facilities for the secure generation of cryptographic keys for limited uses. +- Remote attestation: Creates a nearly unforgeable hash key summary of the hardware and software configuration. The software in charge of hashing the configuration data determines the extent of the summary. This allows a third party to verify that the software has not been changed. +- Binding: Encrypts data using the TPM bind key, a unique RSA key descended from a storage key. +- Sealing: Similar to binding, but in addition, specifies the TPM state for the data to be decrypted (unsealed). + +A TPM can also be used for platform integrity, disk encryption, password protection, and software license protection. + +## Hierarchies + +``` +Platform TPM_RH_PLATFORM +Owner TPM_RH_OWNER +Endorsement TPM_RH_ENDORSEMENT +``` + +Each hierarchy has their own manufacture generated seed. + +The arguments used on `TPM2_Create` or `TPM2_CreatePrimary` create a template, which is fed into a KDF to produce the same key based hierarchy used. The key generated is the same each time, even after reboot. The generation of a new RSA 2048 bit key takes about 15 seconds. Typically these are created and then stored in NV using `TPM2_EvictControl`. Each TPM generates their own keys uniquely based on the seed. + +There is also an Ephemeral hierarchy (`TPM_RH_NULL`), which can be used to create ephemeral keys. + +## Platform Configuration Registers (PCRs) + +PCRs hold hash digests at indices 0 to 23 in banks supported and allocated by the TPM. They can be extended to prove the integrity of a boot sequence (secure boot). + +## Terminology + +This project uses the terms append vs. marshall and parse vs. unmarshall. + +Acronyms: + +* HAL: Hardware Abstraction Layer. +* NV: Non-Volatile memory. +* TPM: Trusted Platform Module. + +## Device Identification + +The following lines are the identification output captured from each tested module. The `Caps/Did/Vid/Rid` line comes from the TIS bus registers. + +``` +Infineon SLB9670: +TPM2: Caps 0x30000697, Did 0x001b, Vid 0x15d1, Rid 0x10 +Mfg IFX (1), Vendor SLB9670, Fw 7.85 (4555), FIPS 140-2 1, CC-EAL4 1 + +Infineon SLB9672: +TPM2: Caps 0x30000697, Did 0x001d, Vid 0x15d1, Rid 0x36 +Mfg IFX (1), Vendor SLB9672, Fw 16.10 (0x4068), FIPS 140-2 1, CC-EAL4 1 + +Infineon SLB9673: +TPM2: Caps 0x1ae00082, Did 0x001c, Vid 0x15d1, Rid 0x16 +Mfg IFX (1), Vendor SLB9673, Fw 26.13 (0x456a), FIPS 140-2 1, CC-EAL4 1 + +STMicro ST33KTPM2XSPI +TPM2: Caps 0x30000415, Did 0x0003, Vid 0x104a, Rid 0x 0 +Mfg STM (2), Vendor ST33KTPM2XSPI, Fw 9.256 (0x0), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XSPI +TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 74.8 (1151341959), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XSPI (newer firmware line) +TPM2: Caps 0x30000415, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 1.258 (0x0), FIPS 140-2 1, CC-EAL4 0 + +STMicro ST33TPHF2XI2C +TPM2: Caps 0x1a7e2882, Did 0x0000, Vid 0x104a, Rid 0x4e +Mfg STM (2), Vendor , Fw 74.9 (1151341959), FIPS 140-2 1, CC-EAL4 0 + +Microchip ATTPM20 +TPM2: Caps 0x30000695, Did 0x3205, Vid 0x1114, Rid 0x 1 +Mfg MCHP (3), Vendor , Fw 512.20481 (0), FIPS 140-2 0, CC-EAL4 0 + +Nations Technologies Inc. Z32H330 TPM 2.0 module +Mfg NTZ (0), Vendor Z32H330, Fw 7.51 (419631892), FIPS 140-2 0, CC-EAL4 0 + +Nations Technologies Inc. NS350 TPM 2.0 module +TPM2: Caps 0x30000615, Did 0x0701, Vid 0x9999, Rid 0x 1 +Mfg NSG (0), Vendor NS350, Fw 30.30 (0x24042510), FIPS 140-2 1, CC-EAL4 0 + +Nuvoton NPCT650 TPM2.0 +Mfg NTC (0), Vendor rlsNPCT , Fw 1.3 (65536), FIPS 140-2 0, CC-EAL4 0 + +Nuvoton NPCT750 TPM2.0 +TPM2: Caps 0x30000697, Did 0x00fc, Vid 0x1050, Rid 0x 1 +Mfg NTC (0), Vendor NPCT75x"!!4rls, Fw 7.2 (131072), FIPS 140-2 1, CC-EAL4 0 + +SealSQ QVault TPM 2.0 +TPM2: Caps 0x30000797, Did 0x0083, Vid 0x2406, Rid 0x 3 +Mfg SEAL (6), Vendor QVault TPM, Fw 2.1 (0x3010303), FIPS 140-3, CC-EAL4 0 + +NVIDIA Jetson Orin (Tegra234) OP-TEE firmware TPM, via /dev/tpmrm0 +Mfg MSFT (7), Vendor SSE fTPM, Fw 8216.1808 (0x105300), FIPS 140-2, CC-EAL4 0 +``` + +Early ST33TPHF2X 1.x firmware reports `TPM_PT_VENDOR_STRING_1..4` as binary rather than text, so the `Vendor` field prints empty. Later 1.x firmware reports ASCII such as `ST33TPHF2XSPI`. The firmware major version identifies the line instead: 1.x and 2.x are ST33TPHF2X (SPI and I2C firmware respectively), 9.x is ST33KTPM2X and 10.x is ST33KTPM2A. See `examples/firmware/README.md` in the wolfTPM source tree for how this selects the firmware update format and command codes. + +!!! note + The NVIDIA Jetson Orin entry has no `Caps/Did/Vid/Rid` line because those values come from TIS bus registers, which a firmware TPM does not have. The entry was captured with `--enable-autodetect`, where `wolfTPM2_Init_ex` returns as soon as the kernel device opens, so the debug line is never reached. An `--enable-devtpm` build still prints it, reading all zeros. `Fw 8216.1808` is `TPM_PT_FIRMWARE_VERSION_1` = `0x20180710`, which this implementation uses to carry a build date (2018-07-10) rather than a version number. Spec revision is 1.62, and all four PCR banks (SHA-1, SHA-256, SHA-384, SHA-512) are allocated with PCRs 0 to 23. + +## See Also + +* [Supported Hardware](supported-hardware.md) +* [API Reference](api-reference.md) +* [Getting Started](getting-started.md) +* [Project Structure](project-structure.md) diff --git a/mkdocs-ja.yml b/mkdocs-ja.yml new file mode 100644 index 00000000..5a86fd7a --- /dev/null +++ b/mkdocs-ja.yml @@ -0,0 +1,89 @@ +site_name: wolfTPM マニュアル +site_description: 組み込み向けポータブル TPM 2.0 スタック。ファームウェア TPM、ポスト量子暗号、SPDM に対応 +site_url: https://www.wolfssl.com/documentation/manuals/wolftpm/ +repo_url: https://github.com/wolfSSL/wolfTPM +edit_uri: edit/master/docs/ja/ +docs_dir: docs/ja +copyright: Copyright © 2026 wolfSSL Inc. +use_directory_urls: false + +exclude_docs: | + dev/ + +nav: + - 概要: + - はじめに: index.md + - TPM 2.0 の概要: tpm2-overview.md + - プロジェクト構成: project-structure.md + - 始めましょう: + - 始めましょう: getting-started.md + - ビルド: building.md + - ビルドオプション: build-options.md + - システムインターフェース: system-interfaces.md + - ハードウェア: + - サポートされるハードウェア: supported-hardware.md + - HAL IO コールバック: hal-io-callback.md + - 使い方: + - サンプル概要: examples-overview.md + - 鍵管理: key-management.md + - アテステーション: attestation.md + - シーリングと NVRAM: sealing-and-nvram.md + - TLS と証明書: tls-and-certificates.md + - ファームウェアアップデート: firmware-update.md + - 管理と GPIO: management-and-gpio.md + - ポスト量子暗号: + - ポスト量子暗号: post-quantum.md + - SPDM: + - SPDM: spdm.md + - ファームウェア TPM: + - 概要: fwtpm/overview.md + - ビルド: fwtpm/building.md + - 使い方: fwtpm/usage.md + - HAL とポーティング: fwtpm/hal-and-porting.md + - ポスト量子暗号: fwtpm/post-quantum.md + - SPDM: fwtpm/spdm.md + - ラッパー: + - Rust ラッパー: rust-wrapper.md + - C# ラッパー: csharp-wrapper.md + - 統合: + - STM32Cube: stm32cube.md + - 組み込み統合: embedded-integrations.md + - リファレンス: + - API リファレンス: api-reference.md + - TPM2 API: group__TPM2__Proprietary.md + - TPM2 ラッパー API: group__wolfTPM2__Wrappers.md + - TPM2 ヘッダーファイル: tpm2_8h.md + - TPM2 ラッパーヘッダーファイル: tpm2__wrap_8h.md + - TPM2 HAL IO: tpm__io_8h.md + - テスト: testing.md + - ベンチマーク: benchmarks.md + - SBOM とコンプライアンス: sbom-and-compliance.md + - リリースノート: release-notes.md + - 引用元: cited-sources.md + +theme: + name: material + language: ja + logo: assets/logo.png + favicon: assets/logo.png + features: + - navigation.sections + - navigation.top + - content.code.copy + palette: + primary: indigo + accent: indigo + +extra_css: + - assets/skin.css + - assets/table-code.css + +markdown_extensions: + - tables + - fenced_code + - admonition + - toc: + permalink: true + +plugins: + - search diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..46ea6e60 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,91 @@ +site_name: wolfTPM Manual +site_description: Portable TPM 2.0 stack for embedded use, with a firmware TPM, post-quantum, and SPDM +site_url: https://www.wolfssl.com/documentation/manuals/wolftpm/ +repo_url: https://github.com/wolfSSL/wolfTPM +edit_uri: edit/master/docs/ +docs_dir: docs +copyright: Copyright © 2026 wolfSSL Inc. +use_directory_urls: false + +# docs/dev/ holds maintainer notes, not manual pages; docs/ja/ is the Japanese +# mirror built from mkdocs-ja.yml. Keep both out of the English site. +exclude_docs: | + dev/ + ja/ + +nav: + - Overview: + - Introduction: index.md + - TPM 2.0 Overview: tpm2-overview.md + - Project Structure: project-structure.md + - Getting Started: + - Getting Started: getting-started.md + - Building: building.md + - Build Options: build-options.md + - System Interfaces: system-interfaces.md + - Hardware: + - Supported Hardware: supported-hardware.md + - HAL IO Callback: hal-io-callback.md + - Usage: + - Examples Overview: examples-overview.md + - Key Management: key-management.md + - Attestation: attestation.md + - Sealing and NVRAM: sealing-and-nvram.md + - TLS and Certificates: tls-and-certificates.md + - Firmware Update: firmware-update.md + - Management and GPIO: management-and-gpio.md + - Post-Quantum: + - Post-Quantum: post-quantum.md + - SPDM: + - SPDM: spdm.md + - Firmware TPM: + - Overview: fwtpm/overview.md + - Building: fwtpm/building.md + - Usage: fwtpm/usage.md + - HAL and Porting: fwtpm/hal-and-porting.md + - Post-Quantum: fwtpm/post-quantum.md + - SPDM: fwtpm/spdm.md + - Wrappers: + - Rust Wrapper: rust-wrapper.md + - C# Wrapper: csharp-wrapper.md + - Integrations: + - STM32Cube: stm32cube.md + - Embedded Integrations: embedded-integrations.md + - Reference: + - API Reference: api-reference.md + - TPM2 API: group__TPM2__Proprietary.md + - TPM2 Wrapper API: group__wolfTPM2__Wrappers.md + - TPM2 Header File: tpm2_8h.md + - TPM2 Wrapper Header File: tpm2__wrap_8h.md + - TPM2 HAL IO: tpm__io_8h.md + - Testing: testing.md + - Benchmarks: benchmarks.md + - SBOM and Compliance: sbom-and-compliance.md + - Release Notes: release-notes.md + - Cited Sources: cited-sources.md + +theme: + name: material + logo: assets/logo.png + favicon: assets/logo.png + features: + - navigation.sections + - navigation.top + - content.code.copy + palette: + primary: indigo + accent: indigo + +extra_css: + - assets/skin.css + - assets/table-code.css + +markdown_extensions: + - tables + - fenced_code + - admonition + - toc: + permalink: true + +plugins: + - search diff --git a/tests/check_doc_constants.sh b/tests/check_doc_constants.sh index 32336765..ea2d51f5 100755 --- a/tests/check_doc_constants.sh +++ b/tests/check_doc_constants.sh @@ -2,7 +2,8 @@ # tests/check_doc_constants.sh — verify doc / header constant parity. # # Greps every FWTPM_MAX_* / FWTPM_NV_* / FWTPM_SEED_* compile-time constant -# from wolftpm/fwtpm/fwtpm.h and asserts that docs/FWTPM.md mentions each one. +# from wolftpm/fwtpm/fwtpm.h and asserts that the fwTPM manual under docs/fwtpm/ +# mentions each one. # Catches doc drift when a constant is bumped (e.g. v1.85 lifted # FWTPM_MAX_COMMAND_SIZE 4096->8192) but the docs still cite the old value. # @@ -12,9 +13,9 @@ set -u HEADER="wolftpm/fwtpm/fwtpm.h" -DOC="docs/FWTPM.md" +DOC="docs/fwtpm" -if [ ! -f "$HEADER" ] || [ ! -f "$DOC" ]; then +if [ ! -f "$HEADER" ] || [ ! -d "$DOC" ]; then echo "SKIP: $HEADER or $DOC not found" exit 77 fi @@ -45,7 +46,7 @@ echo "Checking ${#CONSTS[@]} FWTPM_* constants in $DOC..." MISSING=() for c in "${CONSTS[@]}"; do - if ! grep -qF "$c" "$DOC"; then + if ! grep -qrF "$c" "$DOC"; then MISSING+=("$c") fi done @@ -54,7 +55,7 @@ if [ "${#MISSING[@]}" -gt 0 ]; then echo "ERROR: the following constants are defined in $HEADER but NOT mentioned in $DOC:" printf ' %s\n' "${MISSING[@]}" echo "" - echo "Add a row for each to the Configuration Macros table in $DOC." + echo "Document each one in the fwTPM manual under $DOC (for example docs/fwtpm/building.md)." exit 1 fi diff --git a/tools/check-docs-no-internal-links.sh b/tools/check-docs-no-internal-links.sh new file mode 100755 index 00000000..16e1efa4 --- /dev/null +++ b/tools/check-docs-no-internal-links.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Docs guard. docs/ is published as the manual, so the public tree must never +# point at an internal ledger or at a developer's home directory. +# +# tools/check-docs-no-internal-links.sh [path...] +# default paths: docs README.md +# tools/check-docs-no-internal-links.sh --selftest +set -u + +root="$(cd "$(dirname "$0")/.." && pwd)" +PATTERN='internal-docs|/Users/[A-Za-z]|/home/[A-Za-z]' + +selftest() { + local dir fails=0 + dir="$(mktemp -d)" + printf 'See ~/wolftpm-internal-docs/task-list.md for the rows.\n' > "$dir/bad1.md" + printf 'Logs live in /home/aidangarske/wolftpm-work.\n' > "$dir/bad2.md" + printf 'Run `make check` first.\n' > "$dir/ok.md" + if grep -qE "$PATTERN" "$dir/ok.md"; then + echo "SELFTEST FAIL: clean doc flagged"; fails=$((fails + 1)); fi + if ! grep -qE "$PATTERN" "$dir/bad1.md"; then + echo "SELFTEST FAIL: internal ledger link missed"; fails=$((fails + 1)); fi + if ! grep -qE "$PATTERN" "$dir/bad2.md"; then + echo "SELFTEST FAIL: home directory path missed"; fails=$((fails + 1)); fi + rm -rf "$dir" + if [ "$fails" -ne 0 ]; then echo "SELFTEST: $fails failure(s)"; exit 1; fi + echo "SELFTEST: ok" + exit 0 +} + +[ "${1:-}" = "--selftest" ] && selftest + +cd "$root" || exit 2 +if [ $# -gt 0 ]; then paths=("$@"); else paths=(docs README.md); fi + +echo "docs guard: no internal-ledger or home-directory references in: ${paths[*]}" +hits="$(grep -rnE "$PATTERN" "${paths[@]}")" +rc=$? +if [ "$rc" -eq 1 ]; then + echo "OK: no internal references." + exit 0 +fi +if [ "$rc" -ne 0 ]; then + echo "FAIL: grep error $rc (missing path?)" + exit 2 +fi +printf '%s\n' "$hits" +echo "FAIL: $(printf '%s\n' "$hits" | wc -l | tr -d ' ') reference(s) to internal material in the public tree." +exit 1 diff --git a/tools/docs-manual/Makefile b/tools/docs-manual/Makefile new file mode 100644 index 00000000..73130e77 --- /dev/null +++ b/tools/docs-manual/Makefile @@ -0,0 +1,60 @@ +.DEFAULT_GOAL := all +include ../common/common.am +include build/order.mk + +SRC := src +MKDOC := mkdocs.yml +PDF := wolfTPM-Manual.pdf +DOXYBOOK := "$(WT_SOURCE)/tools/docs-manual/doxybook.cfg" + +.PHONY: all api html-prep pdf-prep +# html-prep must run before pdf-prep: pdf-prep rewrites api/md in place, and +# html-prep copies those pages, so the HTML must be staged from the pristine set. +all: html pdf + +# Generate the API reference markdown straight from the in-tree headers. +# Doxyfile INPUT paths are repo-root relative, so run doxygen from WT_SOURCE and +# redirect its output into this manual dir to keep the source checkout clean. +api: + $(Q)rm -rf api + $(Q)mkdir -p api/md api/doxygen + $(Q)cd "$(WT_SOURCE)" && ( cat docs/Doxyfile; \ + echo "OUTPUT_DIRECTORY=$(CURDIR)/api/doxygen"; \ + echo "GENERATE_HTML=NO"; echo "GENERATE_XML=YES"; echo "QUIET=YES" ) | doxygen - + $(Q)doxybook2 --input api/doxygen/xml --output api/md --config $(DOXYBOOK) + +# Doxybook2 output needs fixing for mkdocs: it swaps underscores for dashes in +# anchors, emits leading-slash links, and prefixes header-file titles. +html-prep: api + $(Q)cp -a api/md/group* build/html/ + $(Q)cp -a api/md/*8h* build/html/ + $(Q)cp -a api/md/Classes build/html/ + $(Q)perl -i -pe 's#\]\(/Classes/#](#g' build/html/Classes/*.md + $(Q)perl -i -pe "s/Classes\///g" build/html/Classes/*.md + $(Q)perl -i -pe 's#\]\(/#](../#g' build/html/Classes/*.md + $(Q)perl -i -pe 's#\]\(/#](#g' build/html/group* build/html/*8h* + $(Q)perl -i -pe "s/(\]\([^)#]*#[a-z]+-)([^)]+?)(\))/\$$1.(\$$2=~tr#-#_#r).\$$3/ge" build/html/group* build/html/*8h* build/html/Classes/*.md + $(Q)perl -i -pe "s/\/group_/group_/g" build/html/group* build/html/*8h* + $(Q)perl -i -pe "s/\/tpm2_/tpm2_/g" build/html/group* build/html/*8h* + $(Q)perl -i -pe "s/dox_comments\/header_files\///" build/html/*8h* + +# Prepare the generated API pages for the PDF, then rewrite the hand-written +# pages' cross-links into single-document anchors (pdf-links skips the API pages). +pdf-prep: api + $(Q)perl -i -pe "s/# /## /g" api/md/*.md + $(Q)perl -i -pe "s/(\/group_.*|Classes\/struct.*|\/.*8h)\.md//g" api/md/*.md + $(Q)perl -i -pe "s/^-(-)+$$//" api/md/*.md + $(Q)perl -i -pe "s/^title:.*//" api/md/*.md + $(Q)perl -i -pe "s/^Updated on.*//" api/md/*.md + $(Q)perl -i -pe "s/^summary.*//" api/md/*.md + $(Q)perl -i -pe "s/dox_comments\/header_files\///" api/md/*.md + $(Q)perl -i -pe "s/^\\\\//" api/md/*.md + $(Q)perl -i -pe "s/\\\\par/par/g" api/md/*.md + $(Q)perl -i -pe "s/\[(.*?)\]\(Classes\/.*?.md\)/\[\1\]\(#typedef-\1\)/g" api/md/*.md + $(Q)perl -i -pe "s/(?<=md\#function\-)(.*)(?=\))/\$$1=~s#-#_#gr/ge" api/md/*.md + $(Q)perl -i -pe "s/(?<=md\#typedef\-)(.*)(?=\))/\$$1=~s#-#_#gr/ge" api/md/*.md + $(Q)perl -i -pe "s/(?<=md\#enum\-)(.*)(?=\))/\$$1=~s#-#_#gr/ge" api/md/*.md + $(Q)perl -i -pe 's!^\| enum\| (\*\*\[.*?\]\(.*?\)\*\*) \{(.*)\} \|\s*$$!do { my ($$name, $$vals) = ($$1, $$2); my @items = split(/, /, $$vals); my @chunks; my $$cur = ""; for my $$item (@items) { my $$cand = $$cur eq "" ? $$item : "$$cur, $$item"; if (length($$cand) > 220 && $$cur ne "") { push @chunks, $$cur; $$cur = $$item; } else { $$cur = $$cand; } } push @chunks, $$cur if $$cur ne ""; @chunks <= 1 ? "| enum| $$name { $$vals} |" : "| enum| $$name { $$chunks[0] |\n" . join("", map { "| | $$chunks[$$_]" . ($$_ == $$#chunks ? " }" : "") . " |\n" } 1..$$#chunks) }!ge if length > 2000' api/md/*.md + $(Q)cp -a api/md/group* build/pdf/ + $(Q)cp -a api/md/*8h* build/pdf/ + $(Q)python3 "$(WT_SOURCE)/tools/docs_manual.py" pdf-links --documentation-root .. diff --git a/tools/docs-manual/documentation-rev b/tools/docs-manual/documentation-rev new file mode 100644 index 00000000..ece5a800 --- /dev/null +++ b/tools/docs-manual/documentation-rev @@ -0,0 +1 @@ +a1bfd1d82cafa8e5b9c11eaed8246dc247910828 diff --git a/tools/docs-manual/doxybook.cfg b/tools/docs-manual/doxybook.cfg new file mode 100644 index 00000000..3bf94f81 --- /dev/null +++ b/tools/docs-manual/doxybook.cfg @@ -0,0 +1,19 @@ +{ + "indexInFolders": true, + "linkSuffix": ".md", + "indexClassesName": "index", + "indexFilesName": "index", + "indexGroupsName": "index", + "indexNamespacesName": "index", + "indexRelatedPagesName": "index", + "indexExamplesName": "index", + "mainPageInRoot": true, + "mainPageName": "index", + "folderGroupsName": "", + "folderFilesName": "", + "foldersToGenerate": [ + "classes", + "modules", + "files" + ] +} diff --git a/tools/docs_manual.py b/tools/docs_manual.py new file mode 100755 index 00000000..60223ce1 --- /dev/null +++ b/tools/docs_manual.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python3 +"""Build the wolfTPM manual with wolfSSL/documentation's shared tooling.""" + +import argparse +import json +import os +import re +import shutil +import subprocess +from pathlib import Path + +import yaml +from markdown.extensions.toc import slugify + + +MANUAL = "wolfTPM" +PDF = {"en": "wolfTPM-Manual.pdf", "ja": "wolfTPM-Manual-jp.pdf"} +CONFIG = {"en": "mkdocs.yml", "ja": "mkdocs-ja.yml"} +DOCS = {"en": "docs", "ja": "docs/ja"} +HEADING = re.compile(r"^(#{1,6})[ \t]+(.+?)[ \t]*#*[ \t]*$") +LINK = re.compile(r"\]\((?:([^)#]+\.md))?(?:#([^)]+))?\)") +EXCLUDE_DIRS = {"dev", "assets", "ja"} +# Legacy longform docs kept for Doxygen and the top-level README; not manual pages. +EXCLUDE_FILES = {"README.md", "FWTPM.md", "SWTPM.md", "DEVTPM.md", "WindowTBS.md"} +GENERATED = re.compile(r"^(group__.+|.+_8h)\.md$") + + +def pages_from_nav(value): + if isinstance(value, str): + yield value + elif isinstance(value, list): + for item in value: + yield from pages_from_nav(item) + elif isinstance(value, dict): + for item in value.values(): + yield from pages_from_nav(item) + + +def page_key(page): + return "wtpm-" + slugify(Path(page).with_suffix("").as_posix().replace("/", "-"), "-") + + +def heading_slug(title): + title = re.sub(r"[`*]", "", title) + title = re.sub(r"\[([^]]+)\]\([^)]+\)", r"\1", title) + return slugify(title, "-") + + +def on_disk_pages(source_docs): + pages = set() + for path in source_docs.rglob("*.md"): + rel = path.relative_to(source_docs) + if EXCLUDE_DIRS.intersection(rel.parts): + continue + if rel.as_posix() in EXCLUDE_FILES: + continue + pages.add(rel.as_posix()) + return pages + + +def stage(documentation_root, source_root, lang): + manual = documentation_root / MANUAL + source_docs = source_root / DOCS[lang] + shared = documentation_root / "common" / "common.am" + if not source_docs.is_dir() or not shared.is_file(): + raise RuntimeError(f"{source_docs} or documentation/common/common.am is missing") + + config = yaml.safe_load((source_root / CONFIG[lang]).read_text()) + pages = list(pages_from_nav(config["nav"])) + if not pages or pages[0] != "index.md" or len(set(pages)) != len(pages): + raise RuntimeError("manual navigation must start at index.md and contain unique pages") + + disk = on_disk_pages(source_docs) + generated = [p for p in pages if not (source_docs / p).is_file()] + for page in generated: + if not GENERATED.match(Path(page).name): + raise RuntimeError(f"navigation references a missing page: {page}") + hand = [p for p in pages if p not in generated] + if set(hand) != disk: + raise RuntimeError( + f"manual navigation mismatch: missing={sorted(disk - set(hand))}, " + f"unknown={sorted(set(hand) - disk)}" + ) + + manual.mkdir(exist_ok=True) + for name in ("src", "build", "html", "api"): + path = manual / name + if path.exists(): + shutil.rmtree(path) + keep_suffixes = (".md", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".css") + + def ignore(directory, names): + ignored = set(shutil.ignore_patterns(*EXCLUDE_DIRS, *EXCLUDE_FILES)( + directory, names)) + for name in names: + full = os.path.join(directory, name) + if os.path.isdir(full): + continue + if not name.lower().endswith(keep_suffixes): + ignored.add(name) + return ignored + + shutil.copytree(source_docs, manual / "src", ignore=ignore) + shutil.copyfile(manual / "src" / "index.md", manual / "src" / "Home.md") + (manual / "build").mkdir() + ordered = ["Home.md" if page == "index.md" else page for page in pages] + (manual / "build" / "order.mk").write_text( + "SOURCES := " + " ".join(ordered) + "\nAPPENDIX :=\n" + ) + (manual / "build" / "order.json").write_text(json.dumps(pages) + "\n") + (manual / "build" / "generated.json").write_text(json.dumps(generated) + "\n") + shutil.copyfile(source_root / "tools" / "docs-manual" / "Makefile", + manual / "manual.generated.mk") + + config["docs_dir"] = "build/html" + config["site_dir"] = "html" + config["theme"] = { + "name": None, + "custom_dir": "../mkdocs-material/material", + "language": lang, + "palette": {"primary": "indigo", "accent": "indigo"}, + "font": {"text": "Roboto", "code": "Roboto Mono"}, + "icon": "logo.png", + "logo": "logo.png", + "favicon": "logo.png", + "feature": {"tabs": True}, + } + config["extra_css"] = ["skin.css", "table-code.css"] + config["markdown_extensions"] = ["tables", "fenced_code", "admonition", + {"toc": {"permalink": True}}] + config["plugins"] = ["search"] + config["use_directory_urls"] = False + (manual / "mkdocs.yml").write_text(yaml.safe_dump(config, sort_keys=False)) + + header = (documentation_root / "wolfBoot" / "header.txt").read_text() + header = header.replace("wolfBoot Documentation", "wolfTPM Manual") + header = re.sub(r"(\\copyright\s+)\d{4}", r"\g<1>2026", header) + # Widen the PDF table-of-contents number boxes so deep multi-digit numbers + # (e.g. 19.3.13) stay clear of the entry titles instead of overlapping them. + toc_fix = ( + " - \\usepackage{tocloft}\n" + " - \\setlength{\\cftsecnumwidth}{3.0em}\n" + " - \\setlength{\\cftsubsecnumwidth}{3.8em}\n" + " - \\setlength{\\cftsubsubsecnumwidth}{4.8em}\n" + "subparagraph: yes" + ) + header = header.replace("subparagraph: yes", toc_fix) + (manual / "header.txt").write_text(header) + return manual + + +def resolve(page, md): + return os.path.normpath(os.path.join(os.path.dirname(page), md)).replace(os.sep, "/") + + +def prepare_pdf(documentation_root): + manual = documentation_root / MANUAL + pdf_dir = manual / "build" / "pdf" + pages = json.loads((manual / "build" / "order.json").read_text()) + generated = set(json.loads((manual / "build" / "generated.json").read_text())) + hand = [p for p in pages if p not in generated] + + headers = {} + for page in hand: + staged = pdf_dir / ("Home.md" if page == "index.md" else page) + found = set() + in_fence = False + for line in staged.read_text().splitlines(): + if line.lstrip().startswith(("```", "~~~")): + in_fence = not in_fence + if not in_fence: + match = HEADING.match(line) + if match: + found.add(heading_slug(match.group(2))) + headers[page] = found + + for page in hand: + staged = pdf_dir / ("Home.md" if page == "index.md" else page) + output = [f"[]{{#{page_key(page)}}}\n\n"] + in_fence = False + seen = set() + for line in staged.read_text().splitlines(keepends=True): + anchor = "" + if line.lstrip().startswith(("```", "~~~")): + in_fence = not in_fence + if not in_fence: + match = HEADING.match(line.rstrip("\n")) + if match: + slug = heading_slug(match.group(2)) + unique = slug + counter = 1 + while unique in seen: + counter += 1 + unique = f"{slug}-{counter}" + seen.add(unique) + anchor = f"[]{{#{page_key(page)}-{unique}}}\n\n" + + def rewrite(link): + md = link.group(1) + fragment = link.group(2) + if md is None and fragment is None: + return link.group(0) + target = page if md is None else resolve(page, md) + if target not in headers: + return link.group(0) + if fragment and fragment not in headers[target]: + raise RuntimeError(f"unresolved PDF link: {page} -> {target}#{fragment}") + dest = page_key(target) + (f"-{fragment}" if fragment else "") + return f"](#{dest})" + + line = LINK.sub(rewrite, line) + output.append(anchor + line) + staged.write_text("".join(output)) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("command", choices=("build", "pdf-links")) + parser.add_argument("--documentation-root", required=True, type=Path) + parser.add_argument("--source-root", type=Path) + parser.add_argument("--lang", choices=("en", "ja"), default="en") + parser.add_argument("--target", choices=("all", "html", "pdf"), default="all") + args = parser.parse_args() + documentation_root = args.documentation_root.resolve() + if args.command == "pdf-links": + prepare_pdf(documentation_root) + return + if args.source_root is None: + parser.error("build requires --source-root") + source_root = args.source_root.resolve() + manual = stage(documentation_root, source_root, args.lang) + make_args = ["make", "-C", str(manual), "-f", "manual.generated.mk", args.target, + f"WT_SOURCE={source_root}", f"PDF={PDF[args.lang]}"] + if args.lang == "ja": + make_args.append("DOC_LANG=JA") + subprocess.run(make_args, check=True) + + +if __name__ == "__main__": + main()