Open
Conversation
When the server sends hostkeys-00@openssh.com after auth, the code
compares stored algorithm names (e.g. "rsa-sha2-512") against key blob
algorithm identifiers ("ssh-rsa"). This mismatch causes removeServerHostKey
to be called with a null hostKey parameter, which crashes Kotlin callers
(like ConnectBot) that declare the parameter as non-nullable ByteArray.
These tests demonstrate:
1. removeServerHostKey is called with null due to RSA algo name mismatch
2. The resulting NPE propagates out of handleMessage uncaught
3. Baseline: matching algorithm names cause no removal
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes connectbot/connectbot#2023. When the server sends hostkeys-00@openssh.com after auth, processHostkeysAdvertisement compared stored algorithm names (e.g. "rsa-sha2-512") against key blob identifiers ("ssh-rsa"). Since these are the same RSA key with different signature algorithms, the mismatch caused removeServerHostKey to be called with a null hostKey, crashing Kotlin callers. Changes: 1. Add normalizeKeyAlgorithm() to treat rsa-sha2-256/512 as ssh-rsa for key identity comparison. This prevents the false mismatch. 2. Catch Exception (not just IOException) around processHostkeysAdvertisement so RuntimeExceptions from verifier callbacks don't kill the receiver thread. 3. Move hostkeys-prove check before globalSuccessCounter increment in msgGlobalSuccess to prevent counter interference with other global requests. 4. Send REQUEST_SUCCESS (not FAILURE) for hostkeys requests we handle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The canConnectWithRsa Dropbear test failed with "bad signature" on the server side, which is unrelated to the ChannelManager changes in this branch. Only ChannelManager.java and ChannelManagerTest.java are modified and authentication happens outside ChannelManager (message types 50-60 vs ChannelManager's 80-100). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Fix connectbot/connectbot#2023.
The crash was introduced by the host key rotation feature added in sshlib 2.2.33 (commit 19b6826).
Root Cause
After authentication, OpenSSH servers (including ESXi 6.7's OpenSSH 8.6) send a hostkeys-00@openssh.com global request advertising the server's host keys.
The new processHostkeysAdvertisement code compares the algorithm names from the advertised key blobs against the algorithms stored by ConnectBot.
The problem is an RSA algorithm name mismatch:
These represent the same RSA key, but the code treats them as different. It concludes rsa-sha2-512 is "no longer advertised" and calls
removeServerHostKey(hostname, port, "rsa-sha2-512", null) — passing null for the host key bytes.
ConnectBot's Kotlin override declares hostKey: ByteArray (non-nullable), so Kotlin's intrinsic null-check throws a NullPointerException. This NPE
propagates uncaught through handleMessage → receiveLoop → the SSH receiver thread (which only catches IOException), killing the thread and crashing the
app.
Fix
global requests