Repository navigation
wiki: align TPM PCR and sealing docs with code - #249
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
The change is documentation-only and corrects an inaccurate description; the remaining feedback is a minor consistency tweak (PCR label/“TPM 1/2” spacing).
Pull request overview
Updates the Heads wiki TPM PCR documentation to correct the historical description of PCR 16 and align it with how calcfuturepcr evolved over time.
Changes:
- Replaces the outdated PCR 16 description (“Used for TPM futurecalc of LUKS header…”) with a short history explaining its former scratch usage and current non-use.
- Clarifies the TPM 1 vs TPM 2 PCR choice used historically for
calcfuturepcr, and notes the later shift to replaying fromcbmem -L.
File summaries
| File | Description |
|---|---|
| About/Keys.md | Corrects PCR 16 documentation to reflect historical usage and current behavior (unused). |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
e843917 to
e99fc38
Compare
e99fc38 to
eb25e02
Compare
eb25e02 to
a169dd7
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The remaining findings are minor documentation nits and do not block approval.
Review details
Suppressed comments (4)
About/Heads-threat-model.md:305
- The sealing scripts read PCR 0 when constructing the policy, so it is not unconditionally anchored to zero: an enabled BootGuard Measured-Boot policy makes PCR 0 nonzero and that measured value is what the policy captures. Please qualify the zero case; otherwise this note says a BootGuard-enabled machine seals against zero and can mislead users diagnosing unseal failures.
anchored as zero in Heads' sealing policies; BootGuard only populates it when
Measured Boot is enabled.
Installing-and-Configuring/install-os.md:200
- This paragraph makes both files sound mandatory for every installation, but rollback-counter enforcement is opt-in (
CONFIG_BOOT_REQ_ROLLBACK) and the HOTP counter exists only in HOTP builds; the prerequisite page explicitly calls HOTP optional. On a non-HOTP or non-rollback build, telling users that both files need to be created is inaccurate.
Heads keeps the TPM rollback counter in TPM NVRAM, storing only a SHA-256 hash
of it under /boot (`kexec_rollback.txt`). The HOTP counter is a plain file
under /boot (`kexec_hotp_counter`). Since we just installed, those doesn't exist and we need to create them.
Installing-and-Configuring/install-os.md:200
- The new installation instruction uses the ungrammatical phrase
those doesn't existfor the two files just listed. Please change it tothose don't existso the user-facing sentence agrees with the plural subject.
under /boot (`kexec_hotp_counter`). Since we just installed, those doesn't exist and we need to create them.
index.md:97
- The new clause correctly says the current coreboot SRTM chain is measured into PCR 2, but the same sentence still says coreboot uses different PCRs for different stages. The SRTM stages are cumulative in PCR 2; the separate PCR 4–7 extenders are Heads, not coreboot. Please reword the parenthetical so this historical abstract does not retain the opposite PCR mapping.
Kyle Rankin (Purism CSO) presents Heads' tamper-evident boot model: unlike UEFI Secure Boot which blocks untrusted code using vendor-controlled keys, Heads detects tampering and alerts. "Heads does not provide tamper proofing — it makes it difficult to tamper in an undetectable way," analogous to a tamper-evident seal that a box cutter can defeat, but not without leaving evidence. Stage one — BIOS integrity via TPM + TOTP/HOTP. coreboot measures each boot stage into TPM PCRs (different PCRs for different stages, cumulative hashing; the current implementation measures the coreboot SRTM chain into PCR 2). During setup, Matthew Garrett's tpmtotp generates a TOTP/HOTP secret, seals it in the TPM, and displays a QR code. The user photographs the QR code with a standard authenticator app — the system now authenticates itself to the user. At each boot, Heads displays a 6-digit code on screen; the user compares against their phone. For the Purism Librem Key (developed with Nitrokey), the secret is stored on the key over USB; the key independently computes the expected HOTP code; if it matches, the key blinks green; if not, it blinks red continuously (colorblind-differentiated). Crucially, when tampering is detected, Heads shows a red screen but does not lock the user out — "it's more alerting you to tampering." The key, not the screen, is the trusted element — "you can't trust the computer. What you can trust is this key." Stage two — /boot file integrity via GPG. A full GPG keyring is embedded in the 4-16 MB SPI flash. Heads stores checksums of every file in /boot (kernel, initrd, GRUB config) in a GPG-signed manifest. On legitimate kernel updates, the user plugs in a hardware OpenPGP smart card (Librem Key, Nitrokey, YubiKey) to re-sign changed files. If an attacker implants a kernel rootkit or backdoored initrd, the signature check fails before kexec. Hardware: ThinkPad X200 flashed via Pomona clip + Raspberry Pi, Purism Librem laptops. Also covers fleet deployment (multiple GPG keys for shared enterprise management), TPM-based LUKS secret unlocking, and the trade-off between fuse-blowing for read-only firmware versus retaining update capability.
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Address the outstanding PCR wording and feature-specific file-creation documentation corrections.
Review details
Suppressed comments (4)
About/Keys.md:175
- PCR 0 is included in both sealing policies listed below, so labeling it “Not used” is misleading: when BootGuard populates it, that value becomes part of the unseal policy. Please describe it as not extended by Heads while retaining that it is read and sealed, so readers do not mistake “not extended” for “not security-relevant.”
0: Not used — read from hardware at seal time; normally zero, but populated
before coreboot where Intel BootGuard Measured Boot is enabled.
About/Keys.md:180
- PCR 1 is also included in both seal sets at lines 217-218 even though current builds leave it zero. Calling it “Not used” contradicts that policy; please say that Heads does not extend/populate it instead of implying it is excluded from sealing.
1: Not used — remains zero and is read at seal time. `CONFIG_PCR_HWID=1` and
`CONFIG_PCR_BOOT_MODE=1` in `config/coreboot-*.config` are slot assignments
for optional coreboot features that are not enabled, not evidence that PCR 1
is populated.
About/Keys.md:218
- This also includes PCR 2, but the preceding lines identify PCR 2 as coreboot's measured-boot register and it is part of both sealing policies. Saying PCRs 0–3 are normally zero contradicts that and misstates the value that gates unseal; limit the zero-value claim to PCRs 0, 1, and 3 and identify PCR 2's SRTM measurement.
0,1,2,3,4,5,6,7; PCRs 0-3 are read from hardware and are normally zero.
Installing-and-Configuring/install-os.md:202
- This says both files need to be created even when their features are disabled: rollback enforcement is opt-in, and the HOTP counter exists only in HOTP builds. Qualify this instruction so a fresh-install user creates only the file(s) required by the enabled feature(s).
file under /boot (`kexec_hotp_counter`). After a fresh install these do not
exist yet and need to be created.
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Final comments leave documentation clarifications outstanding in About/Keys.md and Installing-and-Configuring/install-os.md.
Review details
Suppressed comments (4)
About/Keys.md:175
- “Not used” is misleading here: PCR 0 is included in both sealing policies below, so it is used as a policy input even though Heads does not extend it. Describe it as not extended by Heads so readers do not infer that BootGuard PCR 0 changes are ignored.
0: Not used — read from hardware at seal time; normally zero, but populated
before coreboot where Intel BootGuard Measured Boot is enabled.
About/Keys.md:180
- The same wording is misleading for PCR 1: it is part of both sealing policies listed below, despite not being extended by Heads. Please distinguish “not extended” from “not used” here so the table agrees with the documented policy inputs.
1: Not used — remains zero and is read at seal time. `CONFIG_PCR_HWID=1` and
`CONFIG_PCR_BOOT_MODE=1` in `config/coreboot-*.config` are slot assignments
for optional coreboot features that are not enabled, not evidence that PCR 1
is populated.
About/Keys.md:191
- The “once per boot” claim is too strong: the listed extend sites can produce more than one PCR 4 extension on an error/recovery path—for example,
usb-init.shextends"usb"before handing off to recovery, which then extends"recovery". Describe the values and call sites without promising a single extension, otherwise readers may reproduce the wrong PCR 4 value.
4: Boot path. Extended once per boot with the path taken — `"usb"` for USB boot,
`"generic"` for normal boot, `"recovery"` for the recovery shell — by
`usb-init.sh`, `kexec-insert-key.sh`, `kexec-select-boot.sh`,
`initrd/etc/functions.sh`.
Installing-and-Configuring/install-os.md:203
- The preceding sentence makes both rollback protection and HOTP conditional, but this unqualified singular instruction says a counter file is always required. A plain non-HOTP build with rollback ignored has neither file to create; please qualify this by feature and identify that the applicable metadata is created during OEM Factory Reset.
(plain file under /boot, `kexec_hotp_counter`). After a fresh install the
counter file for the configuration in use does not exist yet and must be
created.
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Moderate rollback-documentation issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (5)
Previously missed (1) — in code that hasn't changed since the last review.
About/FAQ.md:170
- On ROM-hash HOTP configurations such as the no-TPM boards listed in
About/Heads-threat-model.md:211-217, there is no TOTP to confirm; the corresponding Heads path reportsNO TPMwhenCONFIG_TPMis disabled. Qualify this as continuing after reviewing the warning, or after confirming TOTP on TPM-backed builds.
About/FAQ.md:170
- The implementation distinguishes a rejected/invalid HOTP code from token absence or transient communication errors: only the invalid-code branch sets the error/red state, while the other branches use a warning and may not have an LED state at all. This sentence therefore overstates the UI for every failure; describe the error and warning paths separately while retaining the non-halting behavior.
**Heads generates HOTP codes** and sends them to your USB Security dongle. The dongle verifies these codes automatically. If verification succeeds, Heads boots normally. If it fails, the dongle's LED shows red and Heads shows an error/red screen; the user may continue after confirming TOTP — Heads alerts rather than locks the user out.
About/Keys.md:219
- These seal sets apply only to TPM-backed builds. Heads also supports HOTP configurations without a TPM, where
unseal-hotp.shderives the secret from the ROM hash rather than sealing it against PCRs; presenting this as universal makes the no-TPM HOTP path inaccurate. Scope the policy to TPM builds and mention the ROM-hash exception.
TOTP/HOTP are sealed against PCRs 0,1,2,3,4,7 and the Disk Unlock Key against
0,1,2,3,4,5,6,7; PCRs 0, 1 and 3 are read at seal time and are normally zero,
while PCR 2 carries coreboot's SRTM measurement.
About/Keys.md:277
- LUKS headers are external disk data that Heads measures into PCR 6; they are not content "from the firmware." This wording can mislead readers about what is protected and where the measured value comes from. Rephrase this as measurements of external content, such as the LUKS headers.
The Disk Unlock Key is sealed in TPM NV memory with PCRs 0,1,2,3,4,5,6,7, which
includes external content from the firmware, like your LUKS header
measurements.
Installing-and-Configuring/install-os.md:199
kexec_rollback.txtis not only a digest: thesha256sumline also carries the/tmp/counter-<id>pathname, and boot verification parses that pathname to recover the TPM counter identifier. Without documenting that identifier, this installation guidance does not accurately describe the file's required contents. Mention both the checksum and the identifier.
The TPM rollback counter lives in TPM NVRAM; only a SHA-256 hash of it is kept
under /boot (`kexec_rollback.txt`). Rollback enforcement is optional
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
f19f1ce to
ff78791
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Resolve the documented HOTP, PCR mapping, and rollback-counter guidance inconsistencies.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
About/Heads-threat-model.md:304
- This new PCR0/PCR2 model conflicts with the later "critical architectural point" in the same document (lines 384-392), which still says that the bootblock performs the initial
extend()into PCR0 and that the measured chain depends on it. Please update that stale explanation as part of this correction; otherwise the threat model asserts both PCR0 and PCR2 as Heads' SRTM chain.
Note: Heads' own coreboot SRTM chain measures into PCR 2 (`CONFIG_PCR_SRTM`),
not PCR 0. PCRs 0 and 1 are not extended by Heads; both are read at seal time
and are normally zero (PCR 0 is populated before coreboot where Intel
BootGuard Measured Boot is enabled).
Installing-and-Configuring/install-os.md:202
- These files are not created by manually choosing a “counter file”:
kexec_rollback.txtis the SHA-256 hash generated when the rollback counter is signed, whilekexec_hotp_counteris initialized by the HOTP sealing flow. As written, a new user has no way to know what to create and could write an invalid rollback hash; describe the corresponding setup/signing flows instead.
(`CONFIG_BOOT_REQ_ROLLBACK`), and the HOTP counter exists only on HOTP builds
(plain file under /boot, `kexec_hotp_counter`). After a fresh install, create
only the counter file required by the enabled features.
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
ff78791 to
63f3919
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Clarify rollback-file creation and the configuration enabling the optional rollback path.
Review details
Suppressed comments (1)
Installing-and-Configuring/install-os.md:208
- The reset script only resets TPM ownership; it does not itself create
/boot/kexec_rollback.txt. That hash file is produced when Heads signs the boot configuration (typically while setting a default boot), and the rollback path is optional. As written, users may expect both files immediately after TPM reset/re-ownership and skip the signing/default-boot step that creates the boot-side state; please qualify this with the actual creation step and enabled configuration.
Heads creates these files for you: the TPM reset flow and OEM Factory Reset /
Re-Ownership create the TPM counter and `kexec_rollback.txt`, and HOTP builds
also get `kexec_hotp_counter`. Do not create or edit them by hand: the counter
can only be created through the TPM, and the hash must match the current counter
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
c9298da to
3026a3d
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Documentation inaccuracies remain in HOTP flows, measured-boot terminology, and rollback-counter behavior.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (5)
About/Heads-threat-model.md:597
- Boot Guard measured boot measures the Initial Boot Block (IBB) identified by the firmware/FIT descriptors into PCR 0, rather than an "initial firmware descriptor" by itself. Please use the IBB terminology here so the threat model accurately describes which firmware is covered by the PCR 0 measurement.
* Measured Boot (where enabled on the platform): Boot Guard measures the initial boot block (IBB) into [TPM](https://trustedcomputinggroup.org/resource/tpm-library-specification/) PCR 0; the coreboot SRTM chain measures into PCR 2.
About/Heads-threat-model.md:390
- This paragraph assumes every platform has an initial PCR 2 measurement, but some supported/legacy ports have TPM initialization without coreboot SRTM and no-TPM ports have no PCR chain at all. Qualify the statement to boards with coreboot measured boot/SRTM and describe the alternative trust basis for other ports.
A critical architectural point: the security of the entire measured boot
chain depends on the integrity of the *first* measurement -- the code
that performs the initial `extend()` into PCR 2. If an attacker can modify
that initial measurement code (the bootblock), they can forge all
About/Keys.md:281
- Boot Guard measured boot measures the Initial Boot Block (IBB) identified by the firmware/FIT descriptors into PCR 0; it does not measure only a "firmware descriptor." This wording understates what PCR 0 represents and differs from the IBB description used by the aligned Heads documentation.
covers firmware and ROM measurements (PCR 2 and PCR 7, plus the Boot Guard
initial boot block (IBB) measurement in PCR 0 on systems where Measured Boot is
About/Keys.md:220
- PCR 2 is not populated on every TPM build: current/legacy ports include configurations where coreboot measured boot is disabled or uses a different legacy path, leaving PCR 2 at zero. The unconditional wording that a TPM build has coreboot SRTM coverage overstates the guarantee; qualify this policy by coreboot SRTM/measured boot being enabled and note the behavior otherwise.
On builds with a TPM, TOTP/HOTP are sealed against PCRs 0,1,2,3,4,7 and the
Disk Unlock Key against 0,1,2,3,4,5,6,7; PCRs 0, 1 and 3 are read at seal time
and are normally zero, while PCR 2 carries coreboot's SRTM measurement where
Installing-and-Configuring/install-os.md:210
CONFIG_BOOT_REQ_ROLLBACKcontrols whether a valid rollback record is required for boot, but the current signing paths add-rbased onCONFIG_IGNORE_ROLLBACKand can writekexec_rollback.txteven when the boot requirement is not enabled. This conflates enforcement with counter maintenance and can mislead users about when the file is updated.
(`kexec_rollback.txt`). Signing a boot configuration, for example when setting
a default boot, also updates that record because the signing step is invoked
with `-r` unless `CONFIG_IGNORE_ROLLBACK=y`. `CONFIG_BOOT_REQ_ROLLBACK`
controls only whether boot requires the rollback counter state; it does not
- Files reviewed: 8/8 changed files
- Comments generated: 2
- Review effort level: Lite
Align the rendered wiki with the code: the Disk Unlock Key seals against PCRs 0-7 and the TOTP/HOTP shared secret against PCRs 0,1,2,3,4,7, with PCR 4 as the boot path, PCR 2 as the coreboot SRTM chain, and PCRs 0, 1 and 3 read at seal time and normally zero. Boot Guard measures into PCR 0 only when the platform is provisioned with a profile that includes measurement, and Purism ships unfused keys while NovaCustom units can. Rollback record creation is gated by CONFIG_IGNORE_ROLLBACK and boot enforcement by CONFIG_BOOT_REQ_ROLLBACK. HOTP reuses the TOTP sealed secret, and a verification failure alerts rather than halting boot. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
3026a3d to
f2fdedf
Compare
Compound adjectives such as GPG signed, TPM based, pass through and clean room are written as plain prose to match the rest of the page, while TPM2 keeps its product-token spelling. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1a6c995 to
3aa5266
Compare
3aa5266 to
29a584f
Compare
29a584f to
09265b4
Compare
09265b4 to
1e15880
Compare
The claim that most client machines ship verified boot only, so PCR 0 stays zero, is not backed by any code or source. No code in initrd/ relies on it and the document cites nothing that states it, so remove it rather than reword it into another generalization. What remains is checkable: PCR 0 receives a Boot Guard ACM measurement when the platform is provisioned with a profile that includes measurement, and a platform provisioned without such a profile leaves PCR 0 unchanged. The wording originated in linuxboot/heads-wiki#249 and was propagated into doc/tpm.md by linuxboot#2203. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
… claim NovaCustom does not always ship unfused keys: units can ship unfused, but production TrustRoot units are provisioned and only accept firmware signed for the provisioned Boot Guard profile. Remove the assertion that most client machines ship verified boot only and therefore leave PCR 0 zero. Nothing supported that sentence, so it is deleted rather than reworded into another generalization. PCR 0 is now described only as receiving an ACM measurement when the platform is provisioned with a Boot Guard profile that includes measurement. The sentence was introduced by this work as linuxboot#249 and propagated into heads doc/tpm.md by linuxboot/heads#2203. Documentation only. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
Documentation only: no code change. Both commits are GPG signed, each carrying a
Signed-off-by:trailer.Corrects the TPM documentation so the rendered wiki matches Heads code (code counterpart: linuxboot/heads#2203). The wrong wording was introduced by the earlier
wiki: align TPM documentation with codecommit; the corrections are folded into it, so no commit in the branch contradicts a later one. Two commits overmaster, tip1e15880.b94285fwiki: correct TPM PCR, Boot Guard, HOTP and rollback documentationAbout/Keys.md,About/FAQ.md); TOTP and HOTP share one sealed secret,seal-hotpkey.shseals nothing, and a HOTP verification failure alerts rather than halting boot.About/Heads-threat-model.md).CONFIG_IGNORE_ROLLBACK, versus boot enforcement, gated byCONFIG_BOOT_REQ_ROLLBACK(Installing-and-Configuring/install-os.md).1e15880index.md: remove prose hyphens from the conference abstracts — style only.Related: earlier wiki PCR sweep #246.