Files
IronStorage/docs/secure-secret-storage.md
Chili Palmer a3da9fda69
Some checks failed
Dependency security audit / rustsec (push) Has been cancelled
Complete SSH transport release audit (#118)
2026-08-25 22:07:47 +02:00

63 lines
3.5 KiB
Markdown

# Secure secret storage
`crates/storage` owns the complete secret-storage contract. Configuration,
password-store repositories, Git configuration, command arguments, and logs
contain only opaque identifiers; passphrases, tokens, and HTTPS passwords are
stored by the operating system.
`SecretReference` has three validated forms. OpenPGP passphrases are keyed by the
primary fingerprint. HTTPS Git credentials are keyed by purpose, server ID,
application ID, and account. The account is kept inside the protected record,
so a configured server/application pair can retrieve it without adding an
account or secret value to TOML. SSH private-key passphrases are keyed by the
key's SHA-256 fingerprint. References, locators, store state, and errors all use
redacted `Debug` output.
Stored values use a small versioned binary envelope containing their reference
and secret bytes. Retrieval validates the envelope and exact reference before
release. Malformed or ambiguous records produce a typed `Corrupted` error;
asking for another account at the same Git locator produces `Missing` without
altering the stored account. `create` refuses to overwrite, `replace` requires
an exact existing record, and missing, denied, cancelled, locked, corrupted,
unsupported-policy, and unavailable-store results remain distinct. Returned
and cached bytes use `SecretBytes`, which zeroizes its allocation when dropped.
## Operating-system adapters
The platform-selection code is isolated in
`crates/storage/src/secret_store/platform.rs` and calls only safe Rust APIs:
- macOS uses legacy Keychain for command-line-compatible device-unlocked
credentials and Protected Data for `RequireUserPresence`; iOS uses Protected
Data. User cancellation is mapped from the native Security Framework status.
- Windows uses Credential Manager. Store operations are serialized because the
upstream adapter documents unreliable same-entry sequencing across threads.
- Linux uses Secret Service through zbus with the Rust cryptography feature. It
does not launch `secret-tool`, a shell, or any other helper. A missing session
service is a typed `Unavailable` result.
IronStorage contains no direct platform FFI or unsafe Rust. The selected adapter
crates own their OS calls, so there is no project-local FFI safety contract
beyond providing validated UTF-8 identifiers and bounded byte slices.
## Locking and caching
A new store starts logically locked. `unlock` must succeed before create,
retrieve, replace, or delete; `lock` immediately clears all cached values even
if the platform lock operation reports an error. Caching is disabled unless a
caller explicitly selects `SecretCachePolicy::Timed`. Timed policies are capped
at 128 entries and 15 minutes, expire lazily, and are always cleared on lock.
The same unlocked store implements the OpenPGP `SecretProvider`, HTTPS Git
`GitCredentialProvider`, and SSH `SshPassphraseProvider`. CLI, TUI, and desktop
pass one prompted SSH passphrase as zeroizing bytes for one retry. Storage binds
that override to the requested key fingerprint, and the authentication handle
persists it only after the Git operation succeeds; cancellation, rejection, and
other failures never create or replace a record. Prompts are hidden or masked,
and secret values are excluded from arguments, history, normal output, debug
models, notifications, and the clipboard. Tests inject a memory backend and
never access a developer or CI user keyring.
The SSH release audit in `ssh-transport-audit.md` ties this passphrase contract
to the complete host-trust, retry, failure, frontend, and artifact matrix.