# DF-3301 — CARP HMAC key used raw (no KDF); ifconfig copies ASCII passphrase — STATIC ANALYSIS

Not guest-verified (Low severity); basis is source analysis.

## Claim

The CARP HMAC treats `carpr_key[20]` as a ready-to-use HMAC key:

- sys/netinet/ip_carp.c:2476 — `bcopy(carpr->carpr_key, sc->sc_key,
  sizeof(sc->sc_key))` — stored and used verbatim
  (carp_hmac_prepare(), ip_carp.c:519-527).

The stock configuration front-end does NOT hash the passphrase:

- sbin/ifconfig/ifcarp.c:95-111 —
  `/* XXX Should hash the password into the key here, perhaps? */`
  `strlcpy(carpr.carpr_key, val, CARP_KEY_LEN);`

So the effective HMAC key is the zero-padded ASCII passphrase
(e.g. "pocpass\0\0...\0").  OpenBSD and FreeBSD ifconfig both hash the
passphrase with SHA-1 before handing it to the kernel
(carpr_key = SHA1(passphrase)); DragonFly's comment shows the
divergence is known but never fixed.

## Impact

Any captured CARP advertisement (multicast 224.0.0.18, TTL 255, sent
every advbase seconds) is an *offline-verifiable* HMAC guess oracle:
an attacker can dictionary/brute-force the passphrase at full speed.
Human-chosen passphrases routinely fall to GPU dictionaries.  With the
key recovered, the attacker can forge advertisements — combined with
the known missing replay protection (DF-0301) and unsynchronized input
state machine (DF-0302) this converts a passive position into active
failover hijack (gratuitous-ARP-level traffic blackhole / MITM of the
virtual IP).

Severity: Low (requires capture + offline attack and a weak passphrase;
defense-in-depth), CWE-321/CWE-916-class.

## Fix

Hash at the configuration boundary, as OpenBSD/FreeBSD do — either in
ifconfig (SHA-1 of the passphrase into carpr_key), or better, in the
kernel's SIOCSVH handler (derive `sc_key = SHA1(carpr_key)` when a new
key is supplied) so every configuration path benefits.
