diff --git a/docs/architecture/crates/vault/README.md b/docs/architecture/crates/vault/README.md index 11d4988..478226f 100644 --- a/docs/architecture/crates/vault/README.md +++ b/docs/architecture/crates/vault/README.md @@ -125,6 +125,7 @@ truth for drift tracking — if an item is fixed in source, update this table. | 4 | irpc dependency | `VaultProtocol` enum with `#[rpc_requests]`, `VaultServiceActor`, `Client`, irpc/postcard deps | Remove entirely — direct method calls on `VaultServiceHandle` (ADR-025) | `protocol.rs`, `service.rs`, `Cargo.toml` | [ADR-025](../../decisions/025-vault-local-only-dispatch.md) | | 5 | `DerivedKey` dual serialization | JSON redacts, postcard preserves bytes | Always redact on serialize; reject `"[REDACTED]"` on deserialize with error (ADR-025, resolves W8) | `protocol.rs` | [protocol.md → Serialization Redaction](protocol.md#serialization-redaction), [ADR-025](../../decisions/025-vault-local-only-dispatch.md) | | 6 | `HashMap::clear` zeroization | `KeyCache::clear()` removes entries and relies on `CachedKey`'s `Drop` impl for zeroization | Verify `HashMap::clear()` actually drops values (it does, but worth a test) | `cache.rs` | [service.md → Security Constraints](service.md#security-constraints) | +| 7 | `derive_password` / `site_password_path` | `derive_password`, `derive_password_string`, `site_password_path` methods exist | Remove entirely — password-manager pattern not relevant to RPC system's vault (ADR-025, resolves C9) | `service.rs`, `mnemonic-derivation.rs` | [ADR-025](../../decisions/025-vault-local-only-dispatch.md) | ## Public API diff --git a/docs/architecture/crates/vault/mnemonic-derivation.md b/docs/architecture/crates/vault/mnemonic-derivation.md index cef2179..327552d 100644 --- a/docs/architecture/crates/vault/mnemonic-derivation.md +++ b/docs/architecture/crates/vault/mnemonic-derivation.md @@ -199,9 +199,8 @@ pub mod PATHS { Helper functions construct parameterized paths: ```rust -pub fn device_path(index: u32) -> String; // m/74'/0'/0'/{index}' -pub fn site_password_path(site_hash: &str) -> String; // m/74'/1'/0'/{site_hash}' -pub fn encryption_path_for_version(version: u32) -> String; // m/74'/2'/0'/{version-2}' +pub fn device_path(index: u32) -> String; // m/74'/0'/0'/{index}' +pub fn encryption_path_for_version(version: u32) -> String; // m/74'/2'/0'/{version-2}' ``` ### Path semantics @@ -211,7 +210,6 @@ pub fn encryption_path_for_version(version: u32) -> String; // m/74'/2'/0'/{vers | `m/74'/0'/0'/0'` | Primary node identity (Ed25519) | Ed25519 | TLS raw key (ADR-010), node identity | | `m/74'/0'/0'/{n}'` | Worker/device identity | Ed25519 | Multi-device nodes, workers | | `m/74'/0'/1'/0'` | SSH host key | Ed25519 | SSH handler | -| `m/74'/1'/0'/{hash}'` | Site-specific deterministic password | Ed25519 bytes | Per-site passwords (not cached) | | `m/74'/2'/0'/0'` | Encryption key for external credentials | AES-256-GCM | Credential encryption (v2, see [encryption.md](encryption.md)) | | `m/44'/60'/0'/0/0` | Ethereum signing key | secp256k1 | Ethereum signing (feature-gated) | diff --git a/docs/architecture/crates/vault/service.md b/docs/architecture/crates/vault/service.md index a9f9e01..99ecb81 100644 --- a/docs/architecture/crates/vault/service.md +++ b/docs/architecture/crates/vault/service.md @@ -156,23 +156,6 @@ Derive a secp256k1 keypair at the given BIP-0032 path. Returns `UnsupportedKeyType` when the `secp256k1` feature is disabled. Returns a `DerivedKey` with `KeyType::Secp256k1` (33-byte compressed public key). -### derive_password(path, length) → Vec - -```rust -pub fn derive_password(&self, path: &str, length: usize) -> Result, VaultServiceError>; -pub fn derive_password_string(&self, path: &str, length: usize) -> Result; -``` - -Derive deterministic password bytes at the given path, truncated to -`length`. This is **not cached** — password derivation is cheap and -passwords are typically one-shot (derive, use, discard). The string -variant base64url-encodes the bytes (URL-safe, no padding). - -`derive_password` is the mechanism for per-site deterministic passwords: -the same seed + path always produces the same password. The path includes -a site hash (`site_password_path(site_hash)`) so different sites get -different passwords. - ## Encrypt and Decrypt ### encrypt(plaintext, key_version) → EncryptedData @@ -250,13 +233,8 @@ pub struct CacheConfig { | `derive_ed25519` | Yes | Derivation is expensive; keys are reused | | `derive_encryption_key` | Yes | Same — encryption key reused across calls | | `derive_ethereum_key` | Yes | Same | -| `derive_password` | No | Cheap derivation; passwords are one-shot | | `encrypt` / `decrypt` | Key cached | The encryption key (at `PATHS::ENCRYPTION`) is cached; the plaintext is not | -`derive_password` does not cache because it's a truncation of derived -bytes, not a keypair that's reused. Caching it would grow the cache with -unique paths (one per site hash) for no reuse benefit. - ## Dispatch The vault uses **direct method calls** on `VaultServiceHandle` — no actor, @@ -316,7 +294,7 @@ alknet-core error types at the assembly boundary (ADR-018). | RwLock for thread safety | — | Multiple readers (derive), exclusive writer (unlock/lock) | | TTL + LRU cache | — | Bounded memory, fresh keys, zeroized eviction | | Direct method calls (no actor) | [ADR-025](../../decisions/025-vault-local-only-dispatch.md) | No irpc, no message enum, no remote dispatch capability | -| `derive_password` not cached | — | One-shot; caching grows cache with no reuse | +| `derive_password` removed | [ADR-025](../../decisions/025-vault-local-only-dispatch.md) | Password-manager pattern not relevant to RPC system's vault; resolves C9 | ## Open Questions diff --git a/docs/architecture/decisions/019-vault-assembly-layer-only.md b/docs/architecture/decisions/019-vault-assembly-layer-only.md index 4a50d43..14a7a33 100644 --- a/docs/architecture/decisions/019-vault-assembly-layer-only.md +++ b/docs/architecture/decisions/019-vault-assembly-layer-only.md @@ -20,8 +20,8 @@ perspective?** The vault provides a `VaultServiceHandle` with `unlock`, `lock`, `derive_ed25519`, `derive_encryption_key`, `derive_ethereum_key`, -`derive_password`, `encrypt`, and `decrypt` methods. Who is allowed to call -these, and through what path? +`encrypt`, and `decrypt` methods. Who is allowed to call these, and +through what path? The candidates: diff --git a/docs/architecture/decisions/025-vault-local-only-dispatch.md b/docs/architecture/decisions/025-vault-local-only-dispatch.md index 5433519..1bb722c 100644 --- a/docs/architecture/decisions/025-vault-local-only-dispatch.md +++ b/docs/architecture/decisions/025-vault-local-only-dispatch.md @@ -203,6 +203,19 @@ version of ADR-018's intent. exclusive writes (unlock/lock). The actor's sequential processing was actually *worse* for throughput than the RwLock. Removing the actor makes the concurrency model visible and correct. +- `derive_password` and `site_password_path` are removed from the vault's + API and path model. The password-manager pattern (deterministic per-site + passwords from HD derivation) is not relevant to an RPC system's vault — + handlers call APIs (using API keys, OAuth tokens, mTLS), not websites + with passwords. The vault is for cryptographic key derivation and + credential encryption. This resolves review #002 C9 (site_password_path + hash mapping underspecified) by removing the feature rather than + specifying the non-standard string→u32 mapping and Ed25519-as-password- + entropy construction. If deterministic password generation is ever needed + (browser-automation edge case), it can be re-added or implemented as a + separate concern — the cost is near-zero, and removing it now eliminates + permanent API surface that was inherited from a prior project's + password-manager pattern. **Negative:** @@ -247,6 +260,11 @@ version of ADR-018's intent. in protocol.md goes away. If a future vault-server crate exposes some operations remotely, *that crate* defines the access policy in its own ADR. +- **C9 (site_password_path hash mapping underspecified)**: resolved. The + `derive_password` / `derive_password_string` / `site_password_path` + methods are removed from the vault's API. The password-manager pattern + is not relevant to an RPC system's vault. No hash mapping to specify, + no Ed25519-as-password-entropy question to answer. ## Assumptions