aiwg
Version:
Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo
265 lines (177 loc) • 12.3 kB
Markdown
namespace: aiwg
name: auth-factor-design
platforms: [all]
description: Decision aid for authentication factor architecture — have/know/are mapping, coercion resistance, FIDO2 PIN/UV policy, and PRF hot-path anti-patterns.
# auth-factor-design
Decision aid for authentication factor architecture. Use when designing or reviewing any system whose unlock, login, or operation gating depends on more than one factor — and especially when biometrics, hardware tokens, or "something you know" enter the design.
The skill forces three explicit exercises: a **factor inventory**, a **coercion-resistance matrix**, and a **lockout/recovery policy**. Without all three, the design isn't complete.
## Triggers
- "factor design" / "MFA" / "multi-factor"
- "FIDO2 PIN" / "WebAuthn PIN"
- "biometric policy" / "uv=true"
- "coercion resistance" / "rubber-hose"
- "PRF hot path" / "hmac-secret"
- "what you know vs what you have"
- "duress code" / "duress factor"
## When NOT to use this skill
- Pure password-based authentication for low-stakes systems (use OWASP ASVS L1 guidance)
- OAuth/OIDC client design (different layer; use `sdlc-complete` security-architect for protocol selection)
- Network-layer mutual TLS (cert authentication, not user authentication)
## Section 1: The three factor classes
| Class | Examples | What "knowing it" means |
|---|---|---|
| **Have** | Hardware token, USB drive, smart card, phone with attestation | Possession demonstrates auth |
| **Know** | Password, PIN, passphrase, recovery code, pattern, security questions | Recall demonstrates auth |
| **Are** | Fingerprint, face, voice, gait, behavioral biometrics | Body demonstrates auth |
A "true" multi-factor system requires factors from at least **two distinct classes**. Three of the same class is not multi-factor — two passwords is one factor twice.
### Common misclassifications
- **SMS code**: not a "have" factor on its own — SIM-swappable, network-interceptable. Treat as a weak channel-bound code, not a possession proof.
- **TOTP from phone**: weak "have" if phone is uncontrolled (any app can read TOTP seed if leaked). Stronger if seed is in a hardware-backed enclave (Apple Secure Enclave, Android Strongbox).
- **Email confirmation link**: not a factor — it's a recovery channel that demonstrates control of the email account, which itself depends on factors.
- **"Security question" answers**: nominally "know" but socially harvestable; treat as a fallback recovery hint, not a factor.
## Section 2: Factor inventory exercise (mandatory)
Before declaring an auth design complete, fill out:
| Factor | Class | Specific instance | Required for which operations? | Lost-recovery procedure |
|---|---|---|---|---|
| YubiKey 5 OTP slot | have | hardware HMAC-SHA1 PRF | unlock, secret derivation | revoke at HQ, reissue |
| YubiKey Bio (FIDO2 PRF) | are+have | fingerprint + hmac-secret w/ uv=true | unlock, signing | revoke + reissue (≤4 weeks per fingerprint enrollment) |
| FIDO2 PIN | know | PIN on Bio key | required when `uv=true` | reset via reset-protocol; bricks key after N failures |
| Recovery passphrase | know | 6-word BIP39 phrase | emergency rotation only | offline backup at HQ |
**Required**: at least one row from each of two classes for any operation that protects high-value assets. Document operations that bypass this rule with explicit risk acceptance.
## Section 3: Coercion-resistance matrix (mandatory)
For each factor, document whether it can be coerced and what mitigates the coercion.
| Factor | Coercible? | How | Mitigation |
|---|---|---|---|
| Password / PIN | Yes — operator under duress reveals it | Mitigation: duress code that triggers fail-closed silent lockout |
| Hardware token | Yes — physical seizure | Mitigation: time-lock, witness requirement, second-factor at HQ |
| Biometric | **Always coerced**. Operator's body is present; "extracting" the biometric is trivial under duress | Mitigation: pair with a "know" factor (FIDO2 PIN) so coerced biometric alone fails |
| Geolocation | Coercible (move operator) | Mitigation: not a real factor; use as risk signal only |
### Anti-pattern: only have + are (review finding H2)
A system with hardware token + biometric and **no "know" factor** is not coercion-resistant. The attacker compels the operator to come to the device with the token in hand and the finger ready. There is nothing the operator can decline to provide.
A FIDO2 PIN as the third factor — REQUIRED for PRF assertion via `uv=true` — adds:
- A factor only the operator's mind contains (truly something they "know")
- A lockout-after-N-tries property (FIDO2 PIN bricks the key after retries; default ~8)
- Optional duress codes (some authenticators support a separate "wipe key on this PIN" entry)
Cost: zero hardware. Recommended for any production deployment of FIDO2/WebAuthn PRF.
## Section 4: FIDO2 / WebAuthn PRF design
### Suggested default
For hardware-backed authenticated key derivation:
- **FIDO2 hmac-secret extension** (PRF in WebAuthn-2 terminology) on a token with both PIN and biometric
- **`uv: required`** in the assertion — forces user verification
- **PIN required** — forces "know" alongside "have+are"
- **Per-RP credential isolation** — different RP IDs derive different PRF outputs
### Tooling
| Use case | Suggested tool | Vetted alternatives |
|---|---|---|
| Production C/C++ | **libfido2** (Yubico's reference C lib) | `python-fido2` only behind a sandbox; PyHanko/cose for high-level signing |
| FIDO2 CLI | **`fido2-token`, `fido2-assert`** (libfido2 binaries) | OpenSC for smart-card-style use |
| Browser-side WebAuthn | Web Crypto API + `navigator.credentials.create/get` | Server libs: `webauthn4j` (JVM), `simplewebauthn` (Node), `python-fido2` (server) |
| Testing | Yubico's `fido2-token -L`, virtual authenticators (Chrome devtools, soft-fido2) | Hardware test rigs only for pre-production validation |
### Anti-pattern: Python in the PRF hot path (review finding H3)
`python-fido2` in the **biometric PRF assertion path** introduces a wide attack surface for the most sensitive operation in the system:
- `python-fido2`, `cryptography`, `cffi`, `pyusb` — any of these getting a typosquat or supply-chain compromise = PRF interception
- The C path through `libfido2` is ~50KB statically linkable, audited, fewer transitive deps
**Remediation options:**
1. **Use `libfido2` C binaries** (`fido2-token`, `fido2-assert`) directly — they support `hmac-secret`. Drop Python from the hot path entirely.
2. **If Python is mandatory**: vendor and pin `python-fido2` + transitive deps with hash-locked wheels in your bootstrap; verify per-wheel SHA-256 against an offline manifest; reproducibly build the bootstrap.
3. **Either way**: run the PRF call inside a sandboxed namespace (bubblewrap, no network, no `/proc`, read-only mounts).
### RP ID guidance
`rp.id` in WebAuthn / FIDO2 is canonically a domain name. Some authenticators behave oddly with non-domain RP IDs (e.g., "agent-box"). For non-web contexts:
- Prefer a domain you control even if not actually web-served (`agent-box.example.com`)
- Test with multiple authenticator firmware versions before locking RP ID
- Document if you proceed with non-domain (review L1 finding)
## Section 5: Lockout / retry policy
| Factor | Failure response |
|---|---|
| FIDO2 PIN | Hard lockout after N failures (default ~8); brick key on M (default 3 lockout cycles); requires reset protocol with PIN+attestation |
| Biometric on hardware token | Fall back to PIN (if PIN set); on N failures of bio, force PIN; never "skip bio" |
| Application password | Rate-limit + account lock with side-channel notification; CAPTCHA after 3 failures (anti-bot, not anti-human) |
| Recovery code (single-use) | Mark used immediately; rotate active set; alert on use |
### Required exercise: document the exact behavior
For each authenticator in your system, document:
```
Factor: FIDO2 PIN on Bio key
Wrong-PIN behavior:
After 1: warning + 1-second delay
After 3: 5-second delay
After 5: 30-second delay
After 8: full lockout, requires reset
Lockout cycles before key brick: 3 (default)
Reset procedure:
fido2-token -R (factory reset, wipes credentials)
Re-enroll fingerprint, re-set PIN
Re-register with all RPs (operationally expensive — design for this)
```
If your design doesn't have this written down, it's incomplete.
## Section 6: Duress / coercion countermeasures
When the threat model includes coercion (high-value targets, journalists, security operators in hostile environments), build in:
| Countermeasure | How |
|---|---|
| **Duress PIN** | Separate PIN that triggers visible-success but secret wipe. Hardware support varies; some FIDO2 firmware supports it, most don't. Document if your hardware does. |
| **Time-lock** | Operations require N-minute delay; operator can secretly trigger a longer delay during which silent alarm fires |
| **Witness requirement** | High-value operations require a second operator present (cryptographically verified — e.g., second YubiKey assertion) |
| **Geographic / device fence** | Operations only succeed from authorized locations or hardware; revocable centrally |
| **Silent canary / heartbeat** | Operator periodically demonstrates non-coercion; missed heartbeat triggers alert (review M7: heartbeat is killable by root, mitigate via signed live image) |
**Important**: every coercion countermeasure has operational cost. A duress PIN that the operator forgets locks them out as effectively as the attacker does. Test the failure modes.
## Section 7: Worked examples
### Review finding H2 — "what you have + what you are" only
Original design: 2-of-2 with one biometric (YubiKey 5 + YubiKey Bio with fingerprint).
What this skill flags:
- Section 3 anti-pattern: no "know" factor → coercion gives the attacker everything
- Section 6: no duress countermeasure documented
Remediation:
- Set FIDO2 PIN on Bio key; require `uv=true` in PRF assertion
- Document PIN lockout policy
- Optionally add duress procedure (geographic alert, second-operator witness)
### Review finding H3 — `python-fido2` in PRF hot path
Original design: Python program calls `python-fido2` to do the biometric PRF assertion.
What this skill flags:
- Section 4 anti-pattern: Python deps in hot path → wide attack surface
Remediation:
- Replace with `libfido2` C tools (`fido2-token`, `fido2-assert -h hmac-secret`)
- If Python is mandatory: vendor + hash-lock all transitive deps; sandbox the call
### Review finding M4 — biometric retry behavior unclear
Original design: `uv: REQUIRED` documented, but lockout/fallback behavior not specified.
What this skill flags:
- Section 5 mandatory exercise: exact lockout behavior must be documented
Remediation:
- Run `fido2-token -L` against a test key, document observed behavior under N failures
- Verify Bio key was not factory-defaulted to "no PIN" (if so, set one)
- Add behavior to `factor-design-rationale.md` per-factor
## Section 8: Output format
When this skill is invoked as part of a review, produce a `factor-design-rationale.md` (template in `templates/factor-design-rationale.md`) with:
- Factor inventory table (Section 2)
- Coercion-resistance matrix (Section 3)
- Lockout/retry policy per factor (Section 5)
- Hardware/firmware constraints (FIDO2 version, PRF support, UV behavior)
If issues are found, produce findings in the standard format:
```markdown
### Finding: <SHORT-NAME>
**Severity**: BLOCK | HIGH | MEDIUM | LOW
**Section**: auth-factor-design <section reference>
**Issue**: <one paragraph>
**Remediation**: <concrete fix>
**References**: <NIST SP 800-63B, FIDO2 spec, etc.>
```
## Related
- **Companion skill**: `physical-threat-modeling` (Tier 2) — coercion is in its threat library
- **Companion skill**: `degraded-mode-design` (Tier 2) — what happens when factors fail
- **Companion skill**: `chain-of-trust-design` — the factors only matter if the verifier is trusted
- **Template**: `factor-design-rationale.md`
## Standards referenced
- NIST SP 800-63B — Digital Identity Guidelines: Authentication
- FIDO2 / CTAP2 specification
- WebAuthn Level 2 / Level 3 specifications
- OWASP ASVS 4.0 §2 (Authentication)
- libfido2 documentation