NK-WP-0049-T42: isolated existing-token MFA stage, fixture-tested
isolated-privacyidea-mfa.py restores the privacyIDEA database in the accepted network-none stage and runs privacyIDEA's own check_serial_pass three times in separate processes: wrong key, wrong code, the owner's code. The serial list is terminal-only; receipts carry booleans, categories and a serial hash. A first fixture run was vacuous (PRIVACYIDEA_CONFIGFILE overrode the wrong-key config); the probe now fixes the variable and asserts the key path. Eight native fixture tests pass (HOTP, TOTP with PIN, negatives, encrypted bundle). The user-to-token resolver is not proven here and is recorded as such. T19 awaits the founder run. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 328925@bnt-lap001 Assistant-Session: 14b795fd-c632-4c01-8d28-e7e490c7b0ed
This commit is contained in:
parent
1959a184cb
commit
1f04c23392
7 changed files with 551 additions and 2 deletions
|
|
@ -255,6 +255,52 @@ T20/T31 are done. Source/ciphertext/target bindings and the safe receipt are in
|
|||
`evidence/2026-10-16-identity-outage-recovery/actual-isolated-privacyidea-review.json`.
|
||||
Existing-token MFA remains T19; event completeness is not claimed.
|
||||
|
||||
## Prepared owner step: isolated existing-token MFA (T19)
|
||||
|
||||
Prepared and fixture-tested 2026-10-24 under T42; not yet run on the actual
|
||||
backup. Execute in your own terminal with a verified transfer receipt (the T23
|
||||
procedure) and your authenticator ready:
|
||||
|
||||
```bash
|
||||
bash tools/bootstrap-recovery/run-isolated-privacyidea-mfa.sh /path/to/verified/transfer.json
|
||||
```
|
||||
|
||||
Prompts, in order: the `railiance-backup` age key (hidden); a token serial chosen
|
||||
from the list printed on your terminal (serial, type, usable flag; the list never
|
||||
enters the receipt); then that token's PIN plus current code exactly as typed at
|
||||
login (hidden). Pick a token you hold and whose PIN you know. A TOTP code is valid
|
||||
for tens of seconds, so enter it only when asked and keep the authenticator open.
|
||||
|
||||
The restore is the privacyIDEA stage's: restored database and original keys in
|
||||
`--network none` containers, read-only, capabilities dropped, user 1000, tmpfs
|
||||
only, isolation inspected before private import. Three checks then run through
|
||||
privacyIDEA's own `check_serial_pass`, each in a separate process:
|
||||
|
||||
1. **Wrong key.** The application is pointed at a random key file; the run asserts
|
||||
the configuration really names it. The typed code must be refused (native
|
||||
decryption raises). This is the discriminating step: the same code is accepted
|
||||
with the original key in step 3.
|
||||
2. **Wrong code.** The final digit of what you typed is changed; it must be refused.
|
||||
3. **Your code.** Accepted by the original key and retained token material.
|
||||
|
||||
The order is deliberate. Only the last step can spend a counter or replay-protected
|
||||
code. A first fixture run showed why: when the wrong-key step silently used the
|
||||
original key, it accepted the code and the real check was then refused. The
|
||||
configuration assertion now prevents that vacuous result, and the receipt only
|
||||
claims proof when all three outcomes line up.
|
||||
|
||||
The receipt carries booleans, bounded refusal categories, token type, a SHA-256 of
|
||||
the serial, counts and source hashes only. No serial, PIN or code is recorded, and
|
||||
the disposable copy is destroyed. Fixture tests cover HOTP and TOTP-with-PIN, a
|
||||
wrong code alone, an unknown serial, a malformed original key and an encrypted
|
||||
bundle through `main()`.
|
||||
|
||||
**Not proven here:** the user-to-token path. KeyCape calls `/validate/check` with
|
||||
user, realm and pass, so the restored LDAP resolver, its encrypted bind password
|
||||
and the LLDAP lookup are exercised only by a chained run (T18 phase B). A policy
|
||||
such as `otppin=userstore` would not apply to a serial-based check. The receipt
|
||||
therefore records `user_to_token_resolver_proven: false`.
|
||||
|
||||
## Unresolved inputs before execution
|
||||
|
||||
- Named immutable disposable target, approved private browser route if required,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue