fix(security): don't penalise a correct PIN after a passphrase change
A passphrase change left the PIN vault sealing the old passphrase. The next PIN unlock opened the vault, walletpassphrase answered RPC -14, and the generic catch ran the lockout curve on a correct PIN, while Settings kept showing the PIN as active. - Passphrase change: when the active wallet's vault exists at completion (same vault path as at dispatch, passphrase actually changed), the vault is marked out of date for the session and kept on disk: PIN entry is no longer offered, a warning toast says so, and Settings shows "PIN out of date" with a tooltip on how to fix it. The Change Passphrase dialog notes beforehand that a PIN will go out of date. - PIN unlock: RPC -14 after the vault opened is treated as "PIN out of date": passphrase entry, a message, no attempt counted, no lockout, and the vault is not deleted (-14 is only the daemon's answer; the vault may hold the only copy of a passphrase that opens an older backup). After a restart Settings shows the PIN as active until the first PIN attempt. - A malformed vault (zero-filled by a removeVault() whose unlink failed, truncated, unknown version) is treated as missing: passphrase entry, "PIN file unreadable", no penalty. New SecureVault::isWellFormed(). - Race guards: Set/Change/Remove PIN are disabled while a passphrase change runs, and Change Passphrase while a PIN operation runs. - Setting or removing the PIN, or switching wallets, clears the mark; setting a PIN offers PIN entry again. Change PIN keeps the mark (the vault still seals the same passphrase). - Pure decisions in data/pin_vault_policy.h, unit-tested. New strings in all 8 languages. No vault, wallet or settings format change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -766,6 +766,11 @@ public:
|
||||
void showPinChangeDialog() { show_pin_change_ = true; pin_status_.clear(); }
|
||||
void showPinRemoveDialog() { show_pin_remove_ = true; pin_status_.clear(); }
|
||||
bool hasPinVault() const;
|
||||
// The PIN vault seals a passphrase the wallet no longer accepts (C87): changed in this session, or a
|
||||
// PIN unlock got RPC -14. Session-only; the vault file is kept. Settings shows "PIN out of date".
|
||||
bool isPinVaultStale() const { return pin_vault_stale_; }
|
||||
// A wallet encrypt / passphrase change is in flight (PIN controls stay disabled meanwhile).
|
||||
bool isEncryptInProgress() const { return encrypt_in_progress_; }
|
||||
|
||||
// Debug-options gate: does revealing the debug dropdown need re-authentication (a PIN vault or
|
||||
// an encrypted wallet)? And verify the entered PIN/passphrase — cb(ok) is invoked on the main
|
||||
@@ -1859,6 +1864,10 @@ private:
|
||||
// Lock screen state
|
||||
bool lock_screen_was_visible_ = false; // tracks lock→unlock transitions for auto-focus
|
||||
bool lock_use_pin_ = true; // true = PIN input, false = passphrase input
|
||||
// The active wallet's PIN vault holds an outdated passphrase (see isPinVaultStale()). Cleared when a
|
||||
// PIN is set (which also re-offers PIN entry) or removed and on a wallet switch; a Change PIN keeps it
|
||||
// (same sealed passphrase).
|
||||
bool pin_vault_stale_ = false;
|
||||
char lock_pin_buf_[16] = {};
|
||||
char lock_passphrase_buf_[256] = {};
|
||||
std::string lock_error_msg_;
|
||||
|
||||
Reference in New Issue
Block a user