diff options
| author | sommerfeld <sommerfeld@sommerfeld.dev> | 2026-09-30 08:54:59 +0100 |
|---|---|---|
| committer | sommerfeld <sommerfeld@sommerfeld.dev> | 2026-09-30 08:54:59 +0100 |
| commit | c1f7133be790a972400ba63ca40f92ed699d216e (patch) | |
| tree | 12e36f95ff1e87998c1028a6e2c3242cad32aa3a /scripts/tpm_nvpcr_unmask.py | |
| parent | 76db86a22a23ccfed07d6160cfdab4ef60067ef0 (diff) | |
| download | dotfiles-c1f7133be790a972400ba63ca40f92ed699d216e.tar.gz dotfiles-c1f7133be790a972400ba63ca40f92ed699d216e.tar.bz2 dotfiles-c1f7133be790a972400ba63ca40f92ed699d216e.zip | |
Enable signed initrd and NvPCR measurements
Diffstat (limited to 'scripts/tpm_nvpcr_unmask.py')
| -rw-r--r-- | scripts/tpm_nvpcr_unmask.py | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/scripts/tpm_nvpcr_unmask.py b/scripts/tpm_nvpcr_unmask.py new file mode 100644 index 0000000..0c4ea43 --- /dev/null +++ b/scripts/tpm_nvpcr_unmask.py @@ -0,0 +1,53 @@ +"""Remove only the old NvPCR masks owned by this repository.""" + +import hashlib +import os +from pathlib import Path + +MASKS = [ + *( + Path(f"/etc/nvpcr/{name}.nvpcr") + for name in ("cryptsetup", "hardware", "login", "verity") + ), + Path("/etc/systemd/system/systemd-pcrlogin@.service"), + Path("/etc/systemd/system/systemd-pcrproduct.service"), +] +DROPIN = Path("/etc/mkinitcpio.conf.d/60-no-nvpcr.conf") +DROPIN_SHA256 = "69a242f865bbd1adee85f168f19e0f4e5b94a78b3d65e5dfa976c5e0f76deea4" +RECOVERY = Path("/boot/EFI/Linux/arch-linux-hardened-nvpcr-recovery.efi") +BACKUP = Path("/var/lib/dotfiles/tpm-nvpcr/backup") + + +def validate(paths: list[Path]) -> list[Path]: + removable = [] + for path in paths: + if not path.exists() and not path.is_symlink(): + continue + if not path.is_file() or path.is_symlink(): + raise ValueError(f"Expected a regular file: {path}") + data = path.read_bytes() + if path == DROPIN: + if hashlib.sha256(data).hexdigest() != DROPIN_SHA256: + raise ValueError(f"Old mkinitcpio drop-in was changed: {path}") + elif data: + raise ValueError(f"NvPCR mask is not empty: {path}") + removable.append(path) + return removable + + +def main() -> None: + if os.geteuid() != 0 or Path("/etc/hostname").read_text().strip() != "halley2": + raise ValueError("Run as root on Halley2") + if not RECOVERY.is_file() or not BACKUP.is_dir(): + raise ValueError("Recovery image and backup must exist before removing masks") + removable = validate([*MASKS, DROPIN]) + for path in removable: + path.unlink() + print(f"removed: {path}") + + +if __name__ == "__main__": + try: + main() + except (OSError, ValueError) as exc: + raise SystemExit(f"NvPCR unmask failed: {exc}") from exc |
