Lab 02 — Secure Firmware Update with Anti-Rollback

Difficulty: 4/5 | Runs locally: yes, standard library only

Pairs with the Phase 13 WARMUP Chapter 8 (secure firmware update and anti-rollback).

Why This Lab Exists (Purpose & Goal)

The firmware-update path is the most dangerous mechanism a device fleet operates: it is designed to replace the most privileged code on the device, so a single accepted malicious "update" is persistent, invisible, kernel-or-below compromise of every device that takes it. The goal of this lab is to build the verifier a real secure-OTA / Verified-Boot update path must run — enforcing authenticity, integrity, device-model binding, and (the subtle one) anti-rollback — and to commit the monotonic version counter only after a fully verified apply.

The Concept, In the Weeds

A signature proves authenticity, but not freshness — and freshness is where firmware updates are attacked. The five controls (this is verify_update / apply_update):

  1. Authenticity — signed by a key chained to the device's root of trust (untrusted signer → reject outright).
  2. Integrity — the delivered payload hashes to the value the signature covers (no bit-flips after signing).
  3. Model binding — the image is for this device model, so an attacker can't flash a weaker model's validly-signed image (a cross-model downgrade).
  4. Anti-rollback — the crux. An attacker takes a validly signed but old, vulnerable image and tries to flash it to re-open a patched bug. The device refuses any image whose rollback index is a monotonic counter stored in hardware (eFuses/RPMB) that can only ever increase.
  5. Commit safety — advance the counter (and A/B-swap the active slot) only after a successful verified apply, so an interrupted/failed update can't brick the device or silently roll back.

Why This Matters for Protecting the Company

Downgrade attacks are how attackers defeat your patch program without finding a new bug — they just re-install the old, vulnerable, still-validly-signed firmware. Android Verified Boot, ChromeOS, and automotive TUF/Uptane all enforce hardware anti-rollback precisely because signing alone is insufficient. When you can design and verify a secure-update path with a hardware-backed monotonic counter, model binding, and commit-on-success, you protect every device the company ships from the most persistent class of compromise — and you keep your patches stuck, so a fixed vulnerability stays fixed.

Secure Implementation Patterns

The anti-pattern. Accept any validly-signed image:

if verify_signature(image): flash(image)     # a signed OLD image re-opens a patched CVE (downgrade)

The secure pattern — five controls, commit only on success (mirrors solution.py):

def verify_update(image, device):
    if image.signer_key not in device.trusted_keys:          # 1. authenticity (root of trust)
        return False, ("untrusted-signer",)
    reasons = []
    if not hmac.compare_digest(_sign(image.signer_key, _manifest(image)), image.signature):
        reasons.append("invalid-signature")
    if not hmac.compare_digest(sha256(image.payload), image.payload_hash):
        reasons.append("payload-hash-mismatch")              # 2. integrity
    if image.device_model != device.model:
        reasons.append("model-mismatch")                     # 3. no cross-model flash
    if image.version <= device.rollback_index:               # 4. ANTI-ROLLBACK (monotonic, hardware)
        reasons.append("rollback-blocked")
    return (not reasons), tuple(reasons)

def apply_update(image, device):
    ok, reasons = verify_update(image, device)
    if not ok:
        raise ValueError(",".join(reasons))                  # never advance on failure
    device.rollback_index = image.version                    # 5. commit the counter on success
    return device.rollback_index

Production practices to carry forward:

  • Store the rollback index in hardware (eFuses/RPMB), so software can't decrement it — the same "append-only in hardware" property as TPM PCRs.
  • Use A/B slots + a recovery path so a bad update falls back to the known-good slot, not a brick.
  • Bind to model and (ideally) device class/region to stop cross-image attacks.
  • Sign the whole manifest (model, version, payload hash), not just the payload, so version and binding are authenticated too.

Validation — What You Should Be Able to Do Now

  • Explain why a signed image is not a safe image, and what anti-rollback adds.
  • Implement the five controls and block an untrusted signer, a tampered payload, a forged signature, a cross-model flash, and a downgrade.
  • Explain why the monotonic counter must be hardware-backed and why you commit only on success.

The Broader Perspective

This lab teaches freshness and monotonicity as security primitives — the recognition that valid and current are different, and that defeating replay/downgrade requires an append-only, hardware-rooted notion of "newest." It is the firmware twin of the attestation nonce (Lab 01), the OIDC single-use transaction (Phase 02), the agent replay-id check (Phase 11), and the FedRAMP scan-freshness clock (Phase 15). Across the whole curriculum, a recurring attacker move is "reuse something that was valid"; the recurring defense is a monotonic, append-only anchor — here, burned into silicon.

Interview Q&A

  • "Why isn't a signed firmware image enough?" — A signature proves authenticity, not freshness; an attacker flashes a validly-signed old image to re-open a patched bug. Anti-rollback enforces a hardware monotonic counter (refuse version ≤ stored, advance only on success), with the counter in fuses/RPMB so software can't decrement it.
  • "How do you avoid bricking a device on a bad update?" — A/B slots and a recovery path: verify into the inactive slot, commit/swap only on a successful verified apply, fall back to the known-good slot on failure.

Extension (Stretch)

Model A/B slot swapping and a recovery slot; add TUF/Uptane-style role separation (root, targets, snapshot, timestamp) for the update repository; explore fwupd/LVFS for real firmware delivery.

References

  • Android Verified Boot (rollback protection); ChromeOS verified boot; Uptane/TUF specifications.
  • Phase 13 WARMUP Chapter 8; fwupd/LVFS documentation.