fix(pty): use OpenSSL crypto backend on Windows for curve25519 KEX - #78
Conversation
The windows build defaulted to libssh2's WinCNG backend, which only offers finite-field DH key exchange. Modern servers (OpenSSH >= 10) no longer accept those, failing with 'Unable to exchange encryption keys'. Enabling ssh2's openssl-on-win32 feature builds libssh2 against the already-vendored OpenSSL, restoring curve25519-sha256 and ecdh-sha2-nistp* offers.
There was a problem hiding this comment.
Pull request overview
This PR fixes SSH handshake failures on Windows by ensuring the ssh2/libssh2-sys build uses the OpenSSL crypto backend (rather than the WinCNG backend), restoring support for modern key exchange algorithms required by OpenSSH >= 10 defaults.
Changes:
- Enable
ssh2’sopenssl-on-win32feature for Windows builds. - Add inline documentation explaining why this feature is required (OpenSSH >= 10 KEX compatibility).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # `openssl-on-win32`: make the Windows build use the (vendored) OpenSSL | ||
| # crypto backend instead of WinCNG. WinCNG offers only finite-field DH key | ||
| # exchange, which modern servers (OpenSSH >= 10) no longer accept. |
There was a problem hiding this comment.
Good catch, thank you — you're right that WinCNG/BCrypt itself supports ECDH (NIST P-256); it's the libssh2 WinCNG backend that doesn't implement ECDH/curve25519 KEX. I've rephrased the comment in a61b77b to say exactly that.
|
hm, what do you mean when you tell windows build? otty does not have the windows support right now |
WinCNG/BCrypt itself supports ECDH; it is the libssh2 WinCNG backend that does not implement it.
|
Fair question! otty's crates (including the SSH backend in This one-line feature flag is self-contained and doesn't change anything on unix, so I figured it was worth upstreaming independently rather than as part of a larger Windows PR. For context, there's a broader |
Okay, now I get it, thx! Let me take some time to test it on my Windows VM. |
Problem
SSH sessions from a Windows build of otty fail during the handshake against modern SSH servers (OpenSSH >= 10) with:
Root cause
The server-side log (OpenSSH 10.0, Debian 13) shows what a Windows build of libssh2 actually offers:
The offer is missing
curve25519-sha256andecdh-sha2-nistp*. Reason: inlibssh2-sys'sbuild.rs, Windows targets default to the WinCNG crypto backend unless theopenssl-on-win32feature is enabled. WinCNG only supports finite-field DH key exchange. OpenSSH 10 servers by default offer onlymlkem768x25519,sntrup761x25519,curve25519andecdh-sha2-nistp*— zero intersection with WinCNG's offer, so the KEX negotiation fails.This affects any Rust project using
ssh2with default features on Windows connecting to OpenSSH >= 10 servers, not just otty.Fix
Enable
ssh2'sopenssl-on-win32feature. The crate already forces a vendored OpenSSL build (see the comment above theopenssldependency), so libssh2 now compiles against the same vendored OpenSSL on Windows and offerscurve25519-sha256/ecdh-sha2-nistp*again. On unix this feature is a no-op (the OpenSSL branch is already taken there).Verification
nmon the Windowslibssh2.aafter the change: contains_libssh2_curve25519_new/_libssh2_curve25519_gen_kand 70+EVP_*symbol references (previously none — WinCNG build)Session(-5)at handshake)cargo clippy -p otty-pty --all-targets --all-features -- -D warnings,cargo test -p otty-pty --all-features,cargo deny checkall green