fix(ssh): wrap agent signers to continue to next identity on signing failure#3401
fix(ssh): wrap agent signers to continue to next identity on signing failure#3401Jason-Shen2 wants to merge 2 commits into
Conversation
…failure When an SSH agent signer fails to sign (e.g. user cancels a FIDO2/security-key user-presence prompt), golang.org/x/crypto/ssh treats the error as fatal and aborts the entire publickey authentication, preventing remaining identities from being tried. This deviates from OpenSSH behavior where a declined signature simply moves on to the next key. This change wraps agent-backed signers in a failoverSigner that returns a deliberately invalid signature on signing failure instead of propagating the error. The server rejects the invalid signature as a normal auth failure, allowing RetryableAuthMethod to continue with the next identity. Also adds conndebug logging for: - Agent socket dial failures - Agent key listing errors - Number of identities provided by the agent - Each agent identity being attempted - Per-key signing failures Fixes wavetermdev#3365
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughA new Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/remote/sshsigners.go`:
- Around line 39-49: The failover path in failoverSigner.SignWithAlgorithm is
returning a signature whose Format is based on the key type instead of the
requested signing algorithm. Update invalidSignature (and its call site in
SignWithAlgorithm) so the fallback signature preserves the algorithm passed into
SignWithAlgorithm, using that value for Signature.Format rather than
signer.PublicKey().Type().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: e89d98ce-5add-43a8-86ec-6f94637a33b3
📒 Files selected for processing (2)
pkg/remote/sshclient.gopkg/remote/sshsigners.go
- invalidSignature now accepts a format parameter - SignWithAlgorithm passes the requested algorithm instead of key type - Add docstrings for failoverSigner and all methods to meet coverage Addresses CodeRabbit review comment on PR wavetermdev#3401
Fixes #3365
Problem
When an SSH agent-backed key fails to sign (e.g. user cancels a FIDO2 / security-key user-presence prompt), the
crypto/sshpublickey callback returns an error. The SSH library treats any callback error as fatal and aborts the entire authentication flow — it does not try any remaining agent identities or keyfiles. This differs from OpenSSH, which moves on to the next key when a signing request is declined.For users with multiple identities in their agent (e.g. a YubiKey/FIDO2 key first, then a regular ed25519 key), tapping "decline" on the hardware key prompt prevents any subsequent key from being attempted, even when the server would accept it.
Root cause
agentClient.Signers()returns[]ssh.Signerthat call through to the agent. IfSign()returns an error (e.g.agent.errNoMoreKeys/user cancellation),ssh.PublicKeysCallbackpropagates that error andRetryableAuthMethodstops retrying because the method itself failed, not because authentication was rejected.Fix
Wrap each agent-backed signer in a new
failoverSigner(sshsigners.go) that:ssh.Signerandssh.AlgorithmSigner.Sign/SignWithAlgorithmfailure, logs a[conndebug]message and returns a deliberately invalid signature (a blob that cannot verify) instead of an error.sshtreats as a normal per-key failure, allowingRetryableAuthMethodto continue with the next identity — exactly matching OpenSSH's behavior.Also adds [conndebug] logging to aid troubleshooting:
Testing
go build ./...passesgo vet ./pkg/remote/passesgo test ./pkg/remote/passes (includesTestDialIdentityAgentUnix)No behavioral change when signers succeed; only the error path changes so that a rejected hardware-key prompt no longer blocks fallback to other identities.