fleet-enrol: content-aware NV check (-check-only), not blind "index defined"
The enrol trigger keyed on "is NV 0x01800001 defined/readable", so leftover state (an earlier tpm-provision run — bench-seen on the 820: "cert present — normal boot" with no real identity) or random bytes (tpm-selftest) silently suppressed enrolment. Now content-aware: - tpmkey.ReadNVCert reads the full NV contents (chunked). - classifyNVCert (TPM-agnostic, unit-tested): parses X.509, checks validity window, and when a real fleet CA bundle is present verifies the cert chains to it. Only a valid fleet cert = enrolled. - New `fleet-enrol -check-only` (no network/no key-gen) exits 0=valid cert, 20=enrol needed, 1=error. The full enrol path uses the same classification instead of NVPresent. - The dracut hook calls -check-only as the single gate, replacing the blind tpm2_nvread (and its now-dead TPM2TOOLS_TCTI export). tpm2_nvread stays in the initramfs for the secure path (dot1x-macsec-up.sh). Lab fallback: the shipped radius-ca.pem is a placeholder (not a cert) -> loadCAPool returns nil -> chain-less "parseable + unexpired" acceptance, so reboot-converge doesn't loop; production replaces radius-ca.pem with the real fleet CA for strict chaining. Tests: classifyNVCert table (valid/expired/garbage/foreign/no-CA) + simtest ReadNVCert roundtrip across the 512B chunk. All pass; packer validate clean.
This commit is contained in:
@@ -26,7 +26,6 @@ type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
|
||||
STAMP=/run/dot1x/.enrol-done
|
||||
[ -e "$STAMP" ] && exit 0
|
||||
mkdir -p /run/dot1x
|
||||
export TPM2TOOLS_TCTI="device:/dev/tpmrm0"
|
||||
|
||||
# --- skip conditions --------------------------------------------------------
|
||||
if [ "$(getarg rd.fleet.enrol=)" = "0" ]; then
|
||||
@@ -55,16 +54,21 @@ while [ ! -e /dev/tpmrm0 ] && [ "$i" -lt 10 ]; do sleep 1; i=$((i + 1)); done
|
||||
# --- already enrolled? then this is a normal boot — do NOT touch the network -
|
||||
# (Bringing up en* here would fight the secure path, which needs it UNMANAGED for
|
||||
# wpa_supplicant. So gate on NV BEFORE any network action.)
|
||||
if tpm2_nvread "$NVINDEX" -o /run/dot1x/nvprobe.der >/dev/null 2>&1 \
|
||||
&& [ -s /run/dot1x/nvprobe.der ]; then
|
||||
info "tpm-enrol: client cert present at NV $NVINDEX — normal boot"
|
||||
rm -f /run/dot1x/nvprobe.der
|
||||
exit 0
|
||||
fi
|
||||
# CONTENT-AWARE gate (fleet-enrol -check-only, no network/no key-gen): reads NV,
|
||||
# parses the cert, and — when the fleet CA is bundled — verifies it chains, so a
|
||||
# leftover/foreign/expired cert (or garbage) does NOT masquerade as enrolled.
|
||||
# rc: 0 = valid fleet cert (normal boot); 20 = enrolment needed; other = error.
|
||||
/usr/sbin/fleet-enrol -check-only -nvindex "$NVINDEX" -handle "$HANDLE"
|
||||
rc=$?
|
||||
case "$rc" in
|
||||
0) info "tpm-enrol: valid fleet cert at NV $NVINDEX — normal boot"; exit 0 ;;
|
||||
20) : ;; # fall through to enrolment
|
||||
*) warn "tpm-enrol: NV check failed (rc=$rc) — leaving to the secure path"; exit 0 ;;
|
||||
esac
|
||||
|
||||
# Committed to enrolling — one attempt per boot.
|
||||
: > "$STAMP"
|
||||
warn "tpm-enrol: NV $NVINDEX empty — starting FIRST-TIME TPM enrolment"
|
||||
warn "tpm-enrol: no valid fleet cert in NV $NVINDEX — starting FIRST-TIME TPM enrolment"
|
||||
|
||||
# NIC: explicit rd.dot1x.if=, else first non-loopback, non-macsec interface.
|
||||
NIC=$(getarg rd.dot1x.if=)
|
||||
|
||||
Reference in New Issue
Block a user