fix(server): properly unwrap signature blob per RFC 8332 - #1507
Open
Luwdo wants to merge 1 commit into
Open
Conversation
RFC 8332 Section 3 allows the signature blob's algorithm identifier to differ from the packet-level algorithm field. For example, a client may put 'ssh-rsa' in the packet algorithm field but sign with 'rsa-sha2-256', embedding that algorithm name in the signature blob. Previously, the signature header was only stripped when the embedded algorithm exactly matched keyAlgo. This caused signature verification failures for clients (e.g., TablePlus/libssh) that advertise 'ssh-rsa' in the packet but sign with 'rsa-sha2-256'. The fix reads the actual algorithm from the signature blob and strips the header for any known SSH algorithm. It also derives hashAlgo from the signature's embedded algorithm when the packet didn't set one. Applies to both publickey and hostbased authentication methods.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The server fails to verify public key signatures from clients that put
ssh-rsain the userauth packet's algorithm field but embedrsa-sha2-256(orrsa-sha2-512) as the algorithm inside the signature blob. This is permitted by RFC 8332 Section 3:The current signature header stripping logic only removes the wrapper when the signature blob's embedded algorithm exactly matches
keyAlgo(the packet-level algorithm). When they differ, the header bytes are left intact in the signature buffer, causingverify()to fail on corrupted input.Example client exhibiting this behavior: TablePlus (which uses libssh internally). It sends
ssh-rsaas the packet algorithm but signs withrsa-sha2-256, embedding that in the signature blob. This works against OpenSSH servers (which handle the mismatch internally) but fails against ssh2-based servers.Fix
Instead of comparing the signature blob's algorithm against
keyAlgo, the fix reads the actual algorithm identifier from the signature blob and strips the header whenever a known SSH algorithm is detected (ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ssh-ed25519,ecdsa-sha2-*).Additionally, when
hashAlgowas not derived from the packet-level algorithm (because the packet saidssh-rsa), the fix now derives it from the signature blob's embedded algorithm:rsa-sha2-256→sha256rsa-sha2-512→sha512This ensures
ctx.hashAlgois correctly populated for the server'sverify()call.Applied to both
publickeyandhostbasedauthentication handlers.Changes
lib/protocol/handlers.misc.js: Replaced the signature header stripping logic for both publickey and hostbased auth methodstest/test-userauth-rfc8332.js: Added regression tests for RSA auth paths through the new unwrapping logicTesting
npm test)test-userauth-rfc8332.jsverifies bothrsa-sha2-256and plainssh-rsaauth succeed through the new logicReferences