Remove Legacy Credential Bootstrap Paths

Decouple user provisioning from HTTPS identity storage while retaining
compatible v1 user records and migrating TLS material to the
credential-free
v2 format. Add focused security regression coverage and update operator
documentation.
This commit is contained in:
2026-09-08 19:09:26 +02:00
parent 82f21d6116
commit ac80863d80
26 changed files with 1013 additions and 583 deletions
+39
View File
@@ -0,0 +1,39 @@
# Legacy credential removal
## Scope and status — 2026-09-08
Agreed removal of the obsolete shared web credential, user bootstrap/migration/synchronization paths, and related public APIs/commands. User-generated passwords and HTTPS certificate rotation remain supported. Implementation and integration are complete, host-tested and build-verified; target validation remains pending. No device operation, factory erase, commit or asset generation was performed.
Separately, the user reported and accepted that ordinary HTTPS idle cleanup worked. This is a scoped functional report, not an invented soak, individual checklist execution, memory reserve approval, broader 8D.11/M3 sign-off or target validation of this credential removal. Prior measurements remain in [the idle-cleanup record](https_idle_cleanup.md).
## User database
- `user_database_init(load_result)` takes no legacy credential. Missing `user_db/database` storage is committed as an empty v1 database; no account/password is imported.
- Create the first administrator on physical UART0 with `user add <username> admin`, optionally `--generate`. Entered passwords use hidden confirmation; generated passwords are shown once. There is no reserved bootstrap account or public bootstrap state.
- `user recover --force` is UART0-only, calls `user_database_recover_empty()`, and destructively rebuilds only an unavailable database empty. It refuses a healthy initialized database, including an empty one. Follow with normal `user add`; unrelated configuration and TLS/SSH identities are untouched.
- Valid existing v1 database bytes load without rewriting or changing accounts, roles, IDs, authentication generations, verifiers or authorized keys. Previously migrated role-`user` accounts are not automatically promoted. The private `v1_admin_marker` preserves the old wire byte and is derived from administrator count during mutations; it is not a new role, public bootstrap field or schema change.
- No public bootstrap, legacy user migration or synchronization API remains. Final-admin protection, conditional mutations, copied principal currentness and target-only revocation remain the canonical account contracts.
## HTTPS identity storage
`web_security` owns only TLS material. At the unchanged `web_sec/material` key, a private byte-oriented reader validates the shipped **1,392-byte v1** layout and builds **1,340-byte TLS-only v2**. It retains the **exact private-key DER, certificate DER, SHA-256 fingerprint and material generation**: this migration is not certificate rotation.
The v2 candidate is validated and committed before live publication. Temporary credential-bearing v1 input is wiped. No public legacy credential reader/type, display, rotation or authentication path remains. Unknown/malformed material, read failures, invalid cryptographic identity and migration write/commit failures fail closed; they do not trigger fallback regeneration or overwrite of rejected material. Truly missing material may be generated and saved normally.
`web credentials show`, `web credentials rotate --force` and `user bootstrap` (including its generated form) are removed. `web certificate info` and `web certificate rotate --force` remain subject to existing frontend policy. `web reset --force` explicitly replaces TLS certificate/private key only; it does not reset passwords, import accounts or synchronize verifiers. TLS replacement/restart can close browser sessions and requires renewed certificate trust/login, without changing user credentials or revoking unrelated SSH sessions.
## Compatibility and physical-security limits
**Older v1-only firmware cannot read v2 HTTPS storage.** Do not assume a downgrade preserves usable HTTPS or restores removed credentials. Existing user database v1 compatibility is separate from this HTTPS downgrade incompatibility.
Replacing an NVS blob logically removes credential fields from the current record; it is **not secure flash wiping**. Append-oriented historical copies may retain plaintext legacy credentials, and current Wi-Fi secrets/TLS/SSH private keys remain unencrypted. PBKDF2 verifiers remain subject to offline guessing. No factory/partition erase is required or authorized by this cleanup.
## Evidence and handoff
- Parent reran successfully: `python3 tests/web_security/run.py` (**15 production groups**, real installed host mbedTLS plus public-surface checks), `tests/admin_console_boundary/accounts.py`, `tests/admin_ssh_policy/run.py`, `tests/admin_console_boundary/lifecycle.py`, `tests/web_cookie_auth/run.py --accounts`, and `tests/web_httpd_idle/run.py` (**18 + SDK guards**).
- Integration agent additionally reports PASS for console boundary, auth parser, cookie default/admin/settings/serial-settings, session-store/default/serial, admin transport/tickets, server lifecycle, diagnostics, login UI and browser UI (68 + renderer/CSP). These are attributed agent runs, not additional parent reruns.
- Startup now uses credential-free initialization and explicit TLS migration-source logging; SSH no longer depends on HTTPS identity readiness. Policy tests cover 64 service-gate combinations and RNG failure. Removed command/completion entries are tested; browser restrictions and UART0-only recovery remain.
- Independent review found no actionable regression. A subsequent agent test extension verifies populated sparse key slots 0/2 across persisted v1 reload, unchanged entire records/no writes, fingerprint snapshots, retained-key authorization and rejection of the removed key; canonical accounts tests and scoped diff check passed. This final extension changes tests only.
- Parent `pio run` **PASS, 3.93 s**, **99,260 B RAM / 1,705,781 B flash**, **56 B RAM / 3,200 B flash** versus the recorded idle-cleanup baseline. Parent `git diff --check` passed before final test/documentation additions.
- Host NVS doubles do not prove actual flash durability or power-loss behavior; TLS v1 fixture uses current-generated identity wrapped in the historical layout rather than an independently captured old-device blob. Device upgrade, persistence, failure-injection, frontend command removal and TLS-reset isolation checks remain manual validation procedures, not claimed passes; see [user administration tests](user_administration_tests.md).
- Earlier phase records retain their historical evidence and procedures. Their legacy credential/bootstrap/reconciliation instructions are superseded by this record and the current command reference, not rewritten as if the old behavior never existed.