Giter VIP home page Giter VIP logo

dev-tunnels-ssh's Introduction

npm version NuGet version

Project

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

Dev Tunnels SSH Library

A Secure Shell (SSH2) client and server protocol library, implemented in both C# and TypeScript.

Feature Highlights

  • SSH over any .NET Stream or JavaScript stream (including but not limited to TCP socket streams)
  • Configurable, extensible, negotiated algorithms for key-exchange, encryption, integrity (HMAC), and public-key authentication
  • Channel multiplexing, with ability to stream data to/from channels
  • Port-forwarding, with ability to stream data to/from remote ports
  • Piping between two sessions can relay all channels and port-forwarding
  • Extensible channel request handling (for "exec", "shell", or custom requests)
  • Supports reconnecting a disconnected session without disrupting channel streams.
  • Compatible with common SSH software. (Tested against OpenSSH.)
  • Supports importing and exporting several key formats, including password-protected keys.

Limitations

The following features are not implemented in this library, though they could be built on top of it:

  • Allowing a client to login to a user account on the server
  • Connecting to a shell on the server
  • Invoking shell commands on the server
  • Transferring files (SCP or SFTP)
  • Rendering a terminal on the client side

Future development may add support for some of these capabilities, likely in the form of additional optional packages.

C# (.NET Framework, .NET Core, .NET 6)

The C# library targets .NET Framework 4.8, .NET Standard 2.1 (.NET Core 3.1, .NET 5), and .NET 6. It's tested on Windows, Mac, & Ubuntu. For details about the .NET library, see src/cs/Ssh/README.md.

TypeScript (Node.js or Browser)

The TypeScript implementation supports either Node.js (>= 14.x) or a browser environment. The Node.js version is tested on Windows, Mac & Ubuntu; the browser version is tested on Chrome & Edge Chromium, though it should work in any modern browser that supports the web crypto API. Note that since script on a web page cannot access native TCP sockets, the standard use of SSH over TCP is not possible; some other stream transport like a websocket may be used. For details about the TypeScript library, see src/ts/ssh/README.md.

Packages

C# NuGet package TS npm package
SSH core protocol and crypto Microsoft.DevTunnels.Ssh @microsoft/dev-tunnels-ssh
SSH public/private key import/export Microsoft.DevTunnels.Ssh.Keys @microsoft/dev-tunnels-ssh-keys
SSH TCP connections and port-forwarding Microsoft.DevTunnels.Ssh.Tcp @microsoft/dev-tunnels-ssh-tcp

The optional "keys" and "TCP" packages depend on the core package. All SSH packages in an app must be the same major and minor version; the patch version (3rd component) may differ if necessary. In other words, any changes that impact cross-package dependencies will increment at least the minor version.

Development

See README-dev.md.

SSH Algorithms Support

Crypto algorithms below rely on platform APIs in .NET (System.Security.Cryptography), Node.js (crypto module) or browsers (web crypto). There is one use of a 3rd-party library: the diffie-hellman package is required in browsers because there is no corresponding web crypto API.

Legend:
✔✔✔ - Enabled and preferred in default session configuration.
✔✔ - Enabled (but not preferred) in default session configuration.
✔ - Supported and can be enabled in custom session configuration.
☑ - Coming soon (working in a branch or PR).
?? - Under consideration for the future.

Type Algorithm Name Status
key-exchange diffie-hellman-group16-sha512 ✔✔
key-exchange diffie-hellman-group14-sha256 ✔✔
key-exchange ecdh-sha2-nistp521
key-exchange ecdh-sha2-nistp384 ✔✔✔
key-exchange ecdh-sha2-nistp256 ✔✔
key-exchange curve25519-sha256 ?? [1]
public-key rsa-sha2-512 ✔✔✔
public-key rsa-sha2-256 ✔✔
public-key ecdsa-sha2-nistp256 ✔✔
public-key ecdsa-sha2-nistp384 ✔✔
public-key ecdsa-sha2-nistp521
public-key ssh-ed25519 ?? [1]
public-key *[email protected] ?? [2]
cipher aes256-cbc ✔✔ [3]
cipher aes256-ctr ✔✔
cipher aes192-cbc
cipher aes192-ctr
cipher aes128-cbc
cipher aes128-ctr
cipher [email protected] ✔✔✔
cipher [email protected]
cipher [email protected] ?? [1]
mac hmac-sha2-512 ✔✔
mac hmac-sha2-256 ✔✔
mac [email protected] ✔✔✔
mac [email protected] ✔✔

[1] May require use of 3rd-party libs, though Curve25519 APIs are under consideration for .NET and web crypto.
[2] OpenSSH certificate support should be possible with some work.
[3] AES-CBC is not supported in browsers due to a limitation of the web crypto API. AES-CTR or AES-GCM works fine.

There is no plan to have built-in support for older algorithms known to be insecure (for example SHA-1), though in some cases these can be easily added by the application.

Key Format Support

Support for importing and exporting keys in various formats is provided in NuGet/npm packages separate from the core SSH functionality. Some key formats are only implemented in either the C# or TS libraries, not both. See also src/cs/SSH.Keys/README.md or src/ts/ssh-keys/README.md.

Key Format Key Algorithm Password Protection Format Description
SSH public key RSA
ECDSA
N/A Single line key algorithm name, base64-encoded key bytes, and optional comment. Files conventionally end with .pub.
PKCS#1 RSA import only Starts with one of:
-----BEGIN RSA PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
SEC1 ECDSA import only Starts with:
-----BEGIN EC PRIVATE KEY-----
PKCS#8 RSA
ECDSA
Starts with one of:
-----BEGIN PUBLIC KEY-----
-----BEGIN PRIVATE KEY-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
SSH2
C# only
RSA Starts with one of:
---- BEGIN SSH2 PUBLIC KEY ----
---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
OpenSSH
C# only
RSA
ECDSA
Starts with one of:
-----BEGIN OPENSSH PUBLIC KEY-----
-----BEGIN OPENSSH PRIVATE KEY-----
JWK
TS only
RSA
ECDSA
N/A JSON with key algorithm name and parameters

References

The following RFCs define the SSH protocol:

dev-tunnels-ssh's People

Contributors

aixiao0621 avatar anvar-ramazanov avatar dependabot[bot] avatar derekbekoe avatar ilyabiryukov avatar jasongin avatar jeanp413 avatar jessetrinity avatar jfullerton44 avatar joshaber avatar jramsay avatar klvnraju avatar microsoftopensource avatar mustard-mh avatar setaskin avatar taiyosogawa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

dev-tunnels-ssh's Issues

Correctly annotate library for trimming

Issue Description

Hi!
When using this library in a .NET 8 project published with the new AOT compilation feature, the following build warning is emitted:

Assembly 'Microsoft.DevTunnels.Ssh' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries

When running the app anyway and triggering code that opens an SSH connection, the following exception is thrown (which I assume to be one of several possible cases):

System.MissingMethodException: No parameterless constructor defined for type 'Microsoft.DevTunnels.Ssh.Messages.KeyExchangeInitMessage'.
   at System.ActivatorImplementation.CreateInstance(Type, Boolean) + 0x119
   at Microsoft.DevTunnels.Ssh.Messages.SshMessage.TryCreate(SshSessionConfiguration, Byte, String) + 0x5b
   at Microsoft.DevTunnels.Ssh.IO.SshProtocol.<ReceiveMessageAsync>d__66.MoveNext() + 0xc43
--- End of stack trace from previous location ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb2
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task, ConfigureAwaitOptions) + 0x4b
   at Microsoft.DevTunnels.Ssh.SshSession.<ReceiveAndHandleOneMessageAsync>d__94.MoveNext() + 0x144

After reading Microsoft's Guide to creating trimmable libraries, I assume it's possible to make Microsoft.DevTunnels.Ssh trimmable, since it's not inheritably reliant on dynamic behaviors such as reflection.

Workaround

Setting TrimMode to partial still emits the warning, but avoids the exception, at least in the code paths I've reached in my limited test app.

<!--...-->
<PropertyGroup>
  <PublishAot>true</PublishAot>
  <PublishTrimmed>true</PublishTrimmed>
  <TrimMode>partial</TrimMode>
</PropertyGroup>

Piped session hangs when using PipeExtensions.pipeSession

Hang happens in forwardSessionRequest, also when piping a channel data gets corrupted somehow.
Can repro this consistently on an app I'm writing:

  • native ssh client connects to nodejs app
  • nodejs app using dev-tunnels-ssh creates local ssh server
    • on new session creates a session (using websocket) to remote ssh server and pipes SSHServerSession to a SSHClientSession
  • For data corrupted issue, native ssh client executes some shell script on remote machine but received output is corrupted

Already fixed locally, will create a PR and try to write unit tests than can reproduce this behavior.

SshSession leak if static SshSessionConfiguration is used

If SshSession is created with a static SshSessionConfiguration, e.g. SshSessionConfiguration.NoSecurity, it will be rooted by ConfigurationChanged event handler and will never be garbage collected.

Path to the root:

				Microsoft.DevTunnels.Ssh.SshSessionConfiguration [Static variable Microsoft.DevTunnels.Ssh.SshSessionConfiguration.NoSecurity]
			EventHandler<EventArgs>
		EventHandler<EventArgs>
	Microsoft.DevTunnels.Ssh.SshSession+<>c__DisplayClass11_0
Microsoft.DevTunnels.Ssh.SshSession

SshChannel leak via long living cancellation arg of OpenChannelAsync()

SshSession.OpenChannelAsync() registers a callback on its cancellation argument like this:

if (cancellation.CanBeCanceled)
{
	cancellation.Register(() => completionSource.TrySetCanceled());
	cancellation.ThrowIfCancellationRequested();
}

The callback registration is never disposed of.

If OpenChannelAsync() is successful, completionSource will reference the opened SshChannel and the SshSession. If the cancellation argument is long living, it'll root them after OpenChannelAsync() is done, potentially causing a memory leak.

There are several other places in C# SSH library with a similar pattern.

Error Invalid channel ID in ChannelCloseMessage

After fixing #64 I see this message in the trace logs, I think it's from SshChannel.closeDefault as it closes the channel too early before it receives the corresponding SSH_MSG_CHANNEL_CLOSE (see SSH RFC )

Logs:

Fri Jul 28 2023 16:04:18 [websocket][9102] Receiving #427 ChannelEofMessage (recipientChannel=5) undefined
Fri Jul 28 2023 16:04:18 [websocket][9122] SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 4) EOF received. undefined
Fri Jul 28 2023 16:04:18 [local][9101] Sending #420 ChannelEofMessage (recipientChannel=5) undefined
Fri Jul 28 2023 16:04:18 [local][9102] Receiving #339 ChannelEofMessage (recipientChannel=5) undefined
Fri Jul 28 2023 16:04:18 [local][9122] SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 5) EOF received. undefined
Fri Jul 28 2023 16:04:18 [websocket][9101] Sending #337 ChannelEofMessage (recipientChannel=4) undefined
Fri Jul 28 2023 16:04:18 [local][9102] Receiving #340 ChannelCloseMessage (recipientChannel=5) undefined
Fri Jul 28 2023 16:04:18 [local][9123] SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 5) closed remotely. (S: 4799, R: 2171) undefined
Fri Jul 28 2023 16:04:18 [websocket][9123] Piping channel closure.
Source: SshServerSession SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 5)
Destination: SshClientSession SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 4)
 undefined
Fri Jul 28 2023 16:04:18 [websocket][9101] Sending #338 ChannelCloseMessage (recipientChannel=4) undefined
Fri Jul 28 2023 16:04:18 [websocket][9123] SshChannel(Type: direct-tcpip, Id: 5, RemoteId: 4) closed locally. (S: 2171, R: 4799) undefined
Fri Jul 28 2023 16:04:18 [websocket][9102] Receiving #428 ChannelCloseMessage (recipientChannel=5) undefined
Fri Jul 28 2023 16:04:18 [websocket][9024] Invalid channel ID 5 in ChannelCloseMessage (recipientChannel=5). undefined

Don't make negative latency a fatal error

I believe there has previously been some discussion between @osortega and @jasongin about this, but we see some occassional RPC disconnects that delays users from being able to connect to their codespaces. Looking into the logs, this is the error that we see:

System.ArgumentOutOfRangeException: Measured latency cannot be negative. (Parameter 'latencyMicroseconds')

which seems to be coming from here. We are still using the old SSH package but are prioritizing the fix here for the coming migration. Would it be possible to make this a non-fatal error or handle it better upstream?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.