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:
@@ -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.
|
||||
Reference in New Issue
Block a user