Skip to content

Conversation

scott-xu
Copy link
Collaborator

@scott-xu scott-xu commented Sep 22, 2025

Beginning in Windows 10, CNG provides support for Curve25519.
See https://learn.microsoft.com/en-us/windows/win32/seccng/cng-named-elliptic-curves

@scott-xu scott-xu changed the title Use BCL Curve25519 when possible Use BCL Curve25519 for windows 10+ Sep 22, 2025
@scott-xu scott-xu changed the title Use BCL Curve25519 for windows 10+ Use BCL Curve25519 for Windows 10+ Sep 22, 2025
@scott-xu scott-xu marked this pull request as ready for review September 22, 2025 12:36
@scott-xu scott-xu marked this pull request as draft September 22, 2025 13:07
@scott-xu scott-xu marked this pull request as ready for review September 22, 2025 13:58
@scott-xu scott-xu marked this pull request as draft September 22, 2025 14:06
@scott-xu scott-xu marked this pull request as ready for review September 23, 2025 11:51
Copy link
Collaborator

@Rob-Hague Rob-Hague left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm otherwise

@Rob-Hague
Copy link
Collaborator

Rob-Hague commented Sep 26, 2025

actually, it is not working on my win10 22H2 machine (connected aborted). develop branch works fine, using curve25519-sha256

Co-authored-by: Rob Hague <rob.hague00@gmail.com>
@scott-xu scott-xu marked this pull request as draft September 27, 2025 00:58
@scott-xu
Copy link
Collaborator Author

actually, it is not working on my win10 22H2 machine (connected aborted). develop branch works fine, using curve25519-sha256

Based on your description, it does not throw exception when get the named curve. May related to agreement derivation.

@Rob-Hague
Copy link
Collaborator

Right, see wireshark.zip. I see the bad capture (on this branch) is sending ECDH init with a key length of 65 bytes (containing 32 trailing zeroes), and the server closes the connection. The good capture (on develop) is sending with 32 byte key, and everything works fine

@Rob-Hague
Copy link
Collaborator

this works

diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.BclImpl.cs b/src/Renci.SshNet/Security/KeyExchangeEC.BclImpl.cs
index 54757719..571614f6 100644
--- a/src/Renci.SshNet/Security/KeyExchangeEC.BclImpl.cs
+++ b/src/Renci.SshNet/Security/KeyExchangeEC.BclImpl.cs
@@ -23,17 +23,15 @@ public override byte[] GenerateClientECPoint()

                 var q = _clientECDH.PublicKey.ExportParameters().Q;

-                return EncodeECPoint(q);
+                return q.X;
             }

             public override byte[] CalculateAgreement(byte[] serverECPoint)
             {
-                var q = DecodeECPoint(serverECPoint);
-
                 var parameters = new ECParameters
                 {
                     Curve = _curve,
-                    Q = q,
+                    Q = new ECPoint { X = serverECPoint, Y = new byte[serverECPoint.Length] },
                 };

                 using var serverECDH = ECDiffieHellman.Create(parameters);

@scott-xu
Copy link
Collaborator Author

That's really strange. Not sure why integration test passes.

@scott-xu scott-xu marked this pull request as ready for review September 28, 2025 00:45
@scott-xu scott-xu marked this pull request as draft September 28, 2025 05:27
@mus65
Copy link
Contributor

mus65 commented Sep 28, 2025

That's really strange. Not sure why integration test passes.

CI only tests Windows with .NET Framework, not Windows with .NET . I guess we should add that?

@Rob-Hague
Copy link
Collaborator

Agreed. Unfortunately though, the tests still pass locally (on the earlier commit), so it seems like OpenSSH is more forgiving than this particular server.

On a similar note, we will need to consider that #1619 is set to leave a netstandard-only path without any coverage. And in #1659 it will be difficult to tell whether the BouncyCastle fallback is in use, based on the BCL's somewhat opaque MLKem.IsSupported. BouncyCastle addresses the former problem like this: https://github.com/bcgit/bc-csharp/blob/0c87b54b4b78e95eb80db716e1ac57f2e7875d21/crypto/test/BouncyCastle.Crypto.Tests.csproj#L42-L44. Potentially, the second problem could be addressed by running a test build using only the BouncyCastle fallbacks (putting the BCL paths under a compilation flag)

mus65 added a commit to mus65/SSH.NET that referenced this pull request Sep 28, 2025
@mus65
Copy link
Contributor

mus65 commented Sep 28, 2025

Agreed.

Opened #1704

On a similar note, we will need to consider that #1619 is set to leave a netstandard-only path without any coverage.

I wish MS would just deprecate .NET Standard. I'm personally not sure it's even worth adding coverage for Xamarin/Mono/UWP/Unity, most if which are EOL...

@Rob-Hague
Copy link
Collaborator

I am less concerned about those platforms and more concerned about being in a chain of dependencies where even a netcore app could be referencing the netstandard build. One of the highest listed "Used by" libraries on the SSH.NET page is netstandard only: https://www.nuget.org/packages/MongoDBMigrations/2.2.0#dependencies-body-tab

@mus65
Copy link
Contributor

mus65 commented Sep 28, 2025

NuGet would still pick the most appropriate .NET assembly in this case, I just double-checked this locally. If you have a net48 project targeting MongoDBMigrations, the published app will contain the net40 assembly of SSH.NET, not the netstandard2.0 assembly.

If you target MongoDBMigrations from a net9.0 app, it would use netstandard2.0, but only because the SSH.NET version referenced by MongoDBMigrations doesn't even have targets for modern .NET . If you reference a newer version of SSH.NET in the app itself, it will also use the net9.0 assembly.

@scott-xu scott-xu marked this pull request as ready for review September 28, 2025 13:42
@scott-xu
Copy link
Collaborator Author

Agreed. Unfortunately though, the tests still pass locally (on the earlier commit), so it seems like OpenSSH is more forgiving than this particular server.

It fails if incorrectly implemented. See https://github.com/scott-xu/SSH.NET/actions/runs/18098643073/job/51495598766

@Rob-Hague
Copy link
Collaborator

It fails if incorrectly implemented.

Indeed, thanks. I think I must have run the net48 tests...

NuGet would still pick the most appropriate .NET assembly in this case

Indeed, thanks. I never realised that

This reverts commit 3269626.
@Rob-Hague Rob-Hague merged commit 081d305 into sshnet:develop Oct 1, 2025
2 of 3 checks passed
@scott-xu scott-xu deleted the bcl-curve25519 branch October 2, 2025 02:36
Rob-Hague added a commit that referenced this pull request Oct 4, 2025
* CI: add Windows Integration Tests for .NET

see #1702 (comment)

* fix podman setup with Windows and .NET

* debug

* x

* x

* x

* revert

* Run Windows .NET tests in separate job

so they run in parallel and we avoid the Common_CreateMoreChannelsThanMaxSessions test failure.

* fix coverlet artifacts

* fix missing PermitTTY in RemoteSshdConfig Reset

this fixes a test failure in Common_CreateMoreChannelsThanMaxSessions
when running the tests multiple times against the same SSH server
instance.

see #1704 (comment)

* speed up Windows tests

turns out this is caused by DNS resolution taking about
2 seconds on every new connection...

* add windows integration tests to Publish needs:

---------

Co-authored-by: Rob Hague <rob.hague00@gmail.com>
Co-authored-by: Robert Hague <rh@johnstreetcapital.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants