GithubHelp home page GithubHelp logo

francoismichel / ssh3 Goto Github PK

View Code? Open in Web Editor NEW
3.2K 3.2K 79.0 2.12 MB

SSH3: faster and rich secure shell using HTTP/3, checkout our article here: https://arxiv.org/abs/2312.08396 and our Internet-Draft: https://datatracker.ietf.org/doc/draft-michel-ssh3/

Home Page: https://arxiv.org/abs/2312.08396

License: Apache License 2.0

Go 99.29% Shell 0.21% Makefile 0.51%

ssh3's Introduction

SSH3: faster and rich secure shell using HTTP/3

SSH3 is a complete revisit of the SSH protocol, mapping its semantics on top of the HTTP mechanisms. It comes from our research work and we (researchers) recently proposed it as an Internet-Draft (draft-michel-ssh3-00).

In a nutshell, SSH3 uses QUIC+TLS1.3 for secure channel establishment and the HTTP Authorization mechanisms for user authentication. Among others, SSH3 allows the following improvements:

  • Significantly faster session establishment
  • New HTTP authentication methods such as OAuth 2.0 and OpenID Connect in addition to classical SSH authentication
  • Robustness to port scanning attacks: your SSH3 server can be made invisible to other Internet users
  • UDP port forwarding in addition to classical TCP port forwarding
  • All the features allowed by the modern QUIC protocol: including connection migration (soon) and multipath connections

Tip

Quickly want to get started ? Checkout how to install SSH3. You will learn to setup an SSH3 server and use the SSH3 client.

⚡ SSH3 is faster

Faster for session establishment, not throughput ! SSH3 offers a significantly faster session establishment than SSHv2. Establishing a new session with SSHv2 can take 5 to 7 network round-trip times, which can easily be noticed by the user. SSH3 only needs 3 round-trip times. The keystroke latency in a running session is unchanged.

SSH3 (top) VS SSHv2 (bottom) session establishement with a 100ms ping towards the server.

🔒 SSH3 security

While SSHv2 defines its own protocols for user authentication and secure channel establishment, SSH3 relies on the robust and time-tested mechanisms of TLS 1.3, QUIC and HTTP. These protocols are already extensively used to secure security-critical applications on the Internet such as e-commerce and Internet banking.

SSH3 already implements the common password-based and public-key (RSA and EdDSA/ed25519) authentication methods. It also supports new authentication methods such as OAuth 2.0 and allows logging in to your servers using your Google/Microsoft/Github accounts.

🧪 SSH3 is still experimental

While SSH3 shows promise for faster session establishment, it is still at an early proof-of-concept stage. As with any new complex protocol, expert cryptographic review over an extended timeframe is required before reasonable security conclusions can be made.

We are developing SSH3 as an open source project to facilitate community feedback and analysis. However, we cannot yet endorse its appropriateness for production systems without further peer review. Please collaborate with us if you have relevant expertise!

🥷 Do not deploy the SSH3 server on your production servers for now

Given the current prototype state, we advise testing SSH3 in sandboxed environments or private networks. Be aware that making experimental servers directly Internet-accessible could introduce risk before thorough security vetting.

While hiding servers behind secret paths has potential benefits, it does not negate the need for rigorous vulnerability analysis before entering production. We are excited by SSH3's future possibilities but encourage additional scrutiny first.

🥷 Your SSH3 public server can be hidden

Using SSH3, you can avoid the usual stress of scanning and dictionary attacks against your SSH server. Similarly to your secret Google Drive documents, your SSH3 server can be hidden behind a secret link and only answer to authentication attempts that made an HTTP request to this specific link, like the following:

ssh3-server -bind 192.0.2.0:443 -url-path <my-long-secret>

By replacing <my-long-secret> by, let's say, the random value M3MzkxYWMxMjYxMjc5YzJkODZiMTAyMjU, your SSH3 server will only answer to SSH3 connection attempts made to the URL https://192.0.2.0:443/M3MzkxYWMxMjYxMjc5YzJkODZiMTAyMjU and it will respond a 404 Not Found to other requests. Attackers and crawlers on the Internet can therefore not detect the presence of your SSH3 server. They will only see a simple web server answering 404 status codes to every request.

NOTE WELL: placing your SSH3 server behind a secret URL may reduce the impact of scanning attacks but will and must never replace classical authentication mechanisms. The secret link should only be used to avoid your host to be discovered. Knowing the secret URL should not grant someone access to your server. Use the classical authentication mechanisms described above to protect your server.

💐 SSH3 is already feature-rich

SSH3 provides new feature that could not be provided by the SSHv2 protocol.

Brand new features

  • UDP port forwarding: you can now access your QUIC, DNS, RTP or any UDP-based server that are only reachable from your SSH3 host. UDP packets are forwarded using QUIC datagrams.
  • X.509 certificates: you can now use your classical HTTPS certificates to authenticate your SSH3 server. This mechanism is more secure than the classical SSHv2 host key mechanism. Certificates can be obtained easily using LetsEncrypt for instance.
  • Hiding your server behind a secret link.
  • Keyless secure user authentication using OpenID Connect. You can connect to your SSH3 server using the SSO of your company or your Google/Github account, and you don't need to copy the public keys of your users anymore.

Famous OpenSSH features implemented

This SSH3 implementation already provides many of the popular features of OpenSSH, so if you are used to OpenSSH, the process of adopting SSH3 will be smooth. Here is a list of some OpenSSH features that SSH3 also implements:

  • Parses ~/.ssh/authorized_keys on the server
  • Certificate-based server authentication
  • known_hosts mechanism when X.509 certificates are not used.
  • Automatically using the ssh-agent for public key authentication
  • SSH agent forwarding to use your local keys on your remote server
  • Direct TCP port forwarding (reverse port forwarding will be implemented in the future)
  • Proxy jump (see the -proxy-jump parameter). If A is an SSH3 client and B and C are both SSH3 servers, you can connect from A to C using B as a gateway/proxy. The proxy uses UDP forwarding to forward the QUIC packets from A to C, so B cannot decrypt the traffic A<->C SSH3 traffic.
  • Parses ~/.ssh/config on the client and handles the Hostname, User, Port and IdentityFile config options (the other options are currently ignored). Also parses a new UDPProxyJump that behaves similarly to OpenSSH's ProxyJump.

🙏 Community support

Help us progress SSH3 responsibly! We welcome capable security researchers to review our codebase and provide feedback. Please also connect us with relevant standards bodies to potentially advance SSH3 through the formal IETF/IRTF processes over time.

With collaborative assistance, we hope to iteratively improve SSH3 towards safe production readiness. But we cannot credibly make definitive security claims without evidence of extensive expert cryptographic review and adoption by respected security authorities. Let's work together to realize SSH3's possibilities!

Installing SSH3

You can either download the last release binaries, install it using go install or generate these binaries yourself by compiling the code from source.

Tip

SSH3 is still experimental and is the fruit of a research work. If you are afraid of deploying publicly a new SSH3 server, you can use the secret path feature of SSH3 to hide it behing a secret URL.

Installing ssh3 and ssh3-server using Go install

go install github.com/francoismichel/ssh3/cmd/...@latest

Compiling SSH3 from source

You need a recent Golang version to do this. Downloading the source code and compiling the binaries can be done with the following steps:

git clone https://github.com/francoismichel/ssh3    # clone the repo
cd ssh3
go build -o ssh3 cmd/ssh3/main.go                        # build the client
CGO_ENABLED=1 go build -o ssh3-server cmd/ssh3-server/main.go   # build the server, requires having gcc installed

If you have root/sudo privileges and you want to make ssh3 accessible to all you users, you can then directly copy the binaries to /usr/bin:

cp ssh3 /usr/bin/ && cp ssh3-server /usr/bin

Otherwise, you can simply add the executables to your PATH environment variable by adding the following line at the end of your .bashrc or equivalent:

export PATH=$PATH:/path/to/the/ssh3/directory

Deploying an SSH3 server

Before connecting to your host, you need to deploy an SSH3 server on it. There is currently no SSH3 daemon, so right now, you will have to run the ssh3-server executable in background using screen or a similar utility.

Note

As SSH3 runs on top of HTTP/3, a server needs an X.509 certificate and its corresponding private key. Public certificates can be generated automatically for your public domain name through Let's Encrypt using the -generate-public-cert command-line argument on the server. If you do not want to generate a certificate signed by a real certificate authority or if you don't have any public domain name, you can generate a self-signed one using the -generate-selfsigned-cert command-line argument. Self-signed certificates provide you with similar security guarantees to SSHv2's host keys mechanism, with the same security issue: you may be vulnerable to machine-in-the-middle attacks during your first connection to your server. Using real certificates signed by public certificate authorities such as Let's Encrypt avoids this issue.

Here is the usage of the ssh3-server executable:

Usage of ./ssh3-server:
  -bind string
        the address:port pair to listen to, e.g. 0.0.0.0:443 (default "[::]:443")
  -cert string
        the filename of the server certificate (or fullchain) (default "./cert.pem")
  -key string
        the filename of the certificate private key (default "./priv.key")
  -enable-password-login
        if set, enable password authentication (disabled by default)
  -generate-public-cert value
        Automatically produce and use a valid public certificate usingLet's Encrypt for the provided domain name. The flag can be used several times to generate several certificates.If certificates have already been generated previously using this flag, they will simply be reused without being regenerated. The public certificates are automatically renewed as long as the server is running. Automatically-generated IP public certificates are not available yet.
  -generate-selfsigned-cert
        if set, generates a self-self-signed cerificate and key that will be stored at the paths indicated by the -cert and -key args (they must not already exist)
  -url-path string
        the secret URL path on which the ssh3 server listens (default "/ssh3-term")
  -v    verbose mode, if set
  -version
        if set, displays the software version on standard output and exit

The following command starts a public SSH3 server on port 443 with a valid Let's Encrypt public certificate for domain my-domain.example.org and answers to new sessions requests querying the /ssh3 URL path:

ssh3-server -generate-public-cert my-domain.example.org -url-path /ssh3

If you don't have a public domain name (i.e. only an IP address), you can either use an existing certificate for your IP address using the -cert and -key arguments or generate a self-signed certificate using the -generate-selfsigned-cert argument.

If you have existing certificates and keys, you can run the server as follows to use them=

ssh3-server -cert /path/to/cert/or/fullchain -key /path/to/cert/private/key -url-path /ssh3

Note

Similarly to OpenSSH, the server must be run with root priviledges to log in as other users.

Authorized keys and authorized identities

By default, the SSH3 server will look for identities in the ~/.ssh/authorized_keys and ~/.ssh3/authorized_identities files for each user. ~/.ssh3/authorized_identities allows new identities such as OpenID Connect (oidc) discussed below. Popular key types such as rsa, ed25519 and keys in the OpenSSH format can be used.

Using the SSH3 client

Once you have an SSH3 server running, you can connect to it using the SSH3 client similarly to what you did with your classical SSHv2 tool.

Here is the usage of the ssh3 executable:

Usage of ssh3:
  -pubkey-for-agent string
        if set, use an agent key whose public key matches the one in the specified path
  -privkey string
        private key file
  -use-password
        if set, do classical password authentication
  -forward-agent
        if set, forwards ssh agent to be used with sshv2 connections on the remote host
  -forward-tcp string
        if set, take a localport/remoteip@remoteport forwarding localhost@localport towards remoteip@remoteport
  -forward-udp string
        if set, take a localport/remoteip@remoteport forwarding localhost@localport towards remoteip@remoteport
  -proxy-jump string
    	if set, performs a proxy jump using the specified remote host as proxy
  -insecure
        if set, skip server certificate verification
  -keylog string
        Write QUIC TLS keys and master secret in the specified keylog file: only for debugging purpose
  -use-oidc string
        if set, force the use of OpenID Connect with the specified issuer url as parameter
  -oidc-config string
        OpenID Connect json config file containing the "client_id" and "client_secret" fields needed for most identity providers
  -do-pkce
        if set, perform PKCE challenge-response with oidc
  -v    if set, enable verbose mode

Private-key authentication

You can connect to your SSH3 server at my-server.example.org listening on /my-secret-path using the private key located in ~/.ssh/id_rsa with the following command:

  ssh3 -privkey ~/.ssh/id_rsa [email protected]/my-secret-path

Agent-based private key authentication

The SSH3 client works with the OpenSSH agent and uses the classical SSH_AUTH_SOCK environment variable to communicate with this agent. Similarly to OpenSSH, SSH3 will list the keys provided by the SSH agent and connect using the first key listen by the agent by default. If you want to specify a specific key to use with the agent, you can either specify the private key directly with the -privkey argument like above, or specify the corresponding public key using the -pubkey-for-agent argument. This allows you to authenticate in situations where only the agent has a direct access to the private key but you only have access to the public key.

Password-based authentication

While discouraged, you can connect to your server using passwords (if explicitly enabled on the ssh3-server) with the following command:

  ssh3 -use-password [email protected]/my-secret-path

Config-based session establishment

ssh3 parses your OpenSSH config. Currently, it only handles the Hostname; User, Port and IdentityFile OpenSSH options. It also adds new option only used by SSH3, such as URLPath or UDPProxyJump. URLPath allows you to omit the secret URL path in your SSH3 command. UDPProxyJump allows you to perform SSH3 (#proxy-jump)[Proxy Jump] and has the same meaning as the -proxy-jump command-line argument. Let's say you have the following lines in your OpenSSH config located in ~/.ssh/config :

IgnoreUnknown URLPath
Host my-server
  HostName 192.0.2.0
  User username
  IdentityFile ~/.ssh/id_rsa
  URLPath /my-secret-path

Similarly to what OpenSSH does, the following ssh3 command will connect you to the SSH3 server running on 192.0.2.0 on UDP port 443 using public key authentication with the private key located in .ssh/id_rsa :

  ssh3 my-server/my-secret-path

If you do not want a config-based utilization of SSH3, you can read the sections below to see how to use the CLI parameters of ssh3.

OpenID Connect authentication (still experimental)

This feature allows you to connect using an external identity provider such as the one of your company or any other provider that implements the OpenID Connect standard, such as Google Identity, Github or Microsoft Entra. The authentication flow is illustrated in the GIF below.

Secure connection without private key using a Google account.

The way it connects to your identity provider is configured in a file named ~/.ssh3/oidc_config.json. Below is an example config.json file for use with a Google account. This configuration file is an array and can contain several identity providers configurations.

[
    {
        "issuer_url": "https://accounts.google.com",
        "client_id": "<your_client_id>",
        "client_secret": "<your_client_secret>"
    }
]

This might change in the future, but currently, to make this feature work with your Google account, you will need to setup a new experimental application in your Google Cloud console and add your email as authorized users. This will provide you with a client_id and a client_secret that you can then set in your ~/.ssh3/oidc_config.json. On the server side, you just have to add the following line in your ~/.ssh3/authorized_identities:

oidc <client_id> https://accounts.google.com <email>

We currently consider removing the need of setting the client_id in the authorized_identities file in the future.

Proxy jump

It is often the case that some SSH hosts can only be accessed through a gateway. SSH3 allows you to perform a Proxy Jump similarly to what is proposed by OpenSSH. You can connect from A to C using B as a gateway/proxy. B and C must both be running a valid SSH3 server. This works by establishing UDP port forwarding on B to forward QUIC packets from A to C. The connection from A to C is therefore fully end-to-end and B cannot decrypt or alter the SSH3 traffic between A and C.

ssh3's People

Contributors

ayesh avatar clfs avatar dependabot[bot] avatar drewwells avatar ei-grad avatar francoismichel avatar hardliner66 avatar mpiraux avatar obonaventure avatar sivukhin avatar sneycampos avatar theotechnicguy 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ssh3's Issues

"virtual hosts"

Hi, found this through HN. Is there any plan to support "virtual" hosts the way HTTP servers do? This is a shortcoming of SSH that I've run into time after time, because SSH doesn't allow me to indicate what host I'm trying to connect to.

It seems like with the cert setup, the work is already half done, the biggest part of the work I'd imagine is just a way to specify multiple host names with multiple certs.

I'd be interested in contributing if this is something you'd like to see.

BSD support?

There does not seem to be any *BSD (FreeBSD, NetBSD, etc.) support. Need any help?

Active Probing Protection

I suggest implementing protection against Active Probing.

Current Behavior:

  • If the user enters the wrong secret path, they are taken to the 404 error page.

Suggested behavior:

  • If the user enters the wrong secret path, they connect to the Ngnix web server (fallback).
  • At the discretion of the user, you can choose several default settings or configure the server manually:
  • Proxying someone else's website;
  • Adding your own HTML page to the web root directory;
  • Adding a fake login window and the like.
  • Optional: Add ACME support for ease of use.

Concerns about security statements and naming

As an interested security enthusiast analyzing SSH3, I wanted to raise some questions about certain security assertions made in the documentation, as well as use of the SSH3 name/branding before formal standardization:

In particular:

  • Statements definitively calling SSH3 "safe" or claiming "strong security" seem premature for prototype software without extensive external cryptanalysis or review over longer time periods.

  • Use of the "SSH3" name and branding could be seen as presumptuous before going through an IETF standardization process and achieving consensus in the SSH community.

To contribute constructively, I think it would be beneficial to:

  • Have more cautious security messaging in the README reflecting SSH3's current experimental state. This can encourage assistance improving its responsible development. #59

  • Use a more tentative naming convention prior to standardization. #60

I opened this issue not as criticism but as constructive feedback from a security advocate hoping to help SSH3 progress and evolve responsibly. By discussing areas for improvement, my aim is to respectfully facilitate community involvement advancing SSH3 in a credible, ethical way over time. Please let me know if any part of this feedback could be clarified further!

[BeforeSuite] [FAILED] [8.752 seconds]

We run tests when building ssh3 package. Our build environment does not have access to Internet for security and reproducible builds purpose. Tests for 0.1.4 were OK but tests for 0.1.6 fail with:

++ go run github.com/onsi/ginkgo/v2/ginkgo --no-color --flake-attempts=4 ./integration_tests
Running Suite: Integration Test Suite - /usr/src/RPM/BUILD/ssh3-0.1.6/integration_tests
=======================================================================================
Random Seed: 1706439786

Will run 17 of 17 specs
------------------------------
[BeforeSuite] [FAILED] [8.752 seconds]
[BeforeSuite]
/usr/src/RPM/BUILD/ssh3-0.1.6/integration_tests/ssh3_test.go:59

  Timeline >>
  11:03AM DBG version francoismichel/ssh3 0.1.6
  Server started, listening on 127.0.0.1:4433/ssh3-tests
  11:03AM INF Server started, listening on 127.0.0.1:4433/ssh3-tests
  [FAILED] in [BeforeSuite] - /usr/src/RPM/BUILD/ssh3-0.1.6/integration_tests/ssh3_test.go:90 @ 01/28/24 11:03:17.155
  << Timeline

  [FAILED] Unexpected error:
      <*exec.ExitError | 0xc0003361c0>:
      exit status 1
      {
          ProcessState: {
              pid: 1583,
              status: 256,
              rusage: {
                  Utime: {Sec: 0, Usec: 1021},
                  Stime: {Sec: 0, Usec: 6156},
                  Maxrss: 10172,
                  Ixrss: 0,
                  Idrss: 0,
                  Isrss: 0,
                  Minflt: 306,
                  Majflt: 312,
                  Nswap: 0,
                  Inblock: 1176,
                  Oublock: 0,
                  Msgsnd: 0,
                  Msgrcv: 0,
                  Nsignals: 0,
                  Nvcsw: 655,
                  Nivcsw: 0,
              },
          },
          Stderr: nil,
      }
  occurred
  In [BeforeSuite] at: /usr/src/RPM/BUILD/ssh3-0.1.6/integration_tests/ssh3_test.go:90 @ 01/28/24 11:03:17.155
------------------------------

Summarizing 1 Failure:
  [FAIL] [BeforeSuite]
  /usr/src/RPM/BUILD/ssh3-0.1.6/integration_tests/ssh3_test.go:90

Ran 0 of 17 Specs in 8.756 seconds
FAIL! -- A BeforeSuite node failed so all tests were skipped.
--- FAIL: TestMessage (8.76s)
FAIL

Ginkgo ran 1 suite in 10.734722948s

Test Suite Failed
exit status 1

Looks like it tries to run go install github.com/francoismichel/ssh3/cmd/ssh3-server since commit 53d7264.

Maybe it's possible to make tests work without access to Internet? (Without go install basically.)

It's pity to disable integration tests run.

ProxyJump support

Forwarding the local keys to a remote server is mostly not needed - what people often want is to use a host as jump host and that works without giving it access to the key material in OpenSSH through the -J flag or the ProxyJump config entry.

       -J destination
               Connect to the target host by first making an ssh connection to the jump host described by destination and then establishing a  TCP
               forwarding  to  the ultimate destination from there.  Multiple jump hops may be specified separated by comma characters.  This is a
               shortcut to specify a ProxyJump configuration directive.  Note that configuration directives supplied on the command-line generally
               apply to the destination host and not any specified jump hosts.  Use ~/.ssh/config to specify configuration for jump hosts.
       ProxyJump
               Specifies  one or more jump proxies as either [user@]host[:port] or an ssh URI.  Multiple proxies may be separated by comma charac‐
               ters and will be visited sequentially.  Setting this option will cause ssh(1) to connect to the  target  host  by  first  making  a
               ssh(1)  connection  to the specified ProxyJump host and then establishing a TCP forwarding to the ultimate target from there.  Set‐
               ting the host to none disables this option entirely.

               Note that this option will compete with the ProxyCommand option - whichever is specified first will prevent later instances of  the
               other from taking effect.

               Note  also  that the configuration for the destination host (either supplied via the command-line or the configuration file) is not
               generally applied to jump hosts.  ~/.ssh/config should be used if specific configuration is required for jump hosts.

the connection was closed by the application: INTERNAL_ERROR ... sendmsg: invalid argument

I have tried to install ssh3-server in a docker container.
After a bit of fiddling I got it running.

However I cannot seem to keep the connection running. The client (ssh3_0.1.5-rc2_darwin_arm64) hangs and times out after a while. The server (0.1.5-rc2 linux_arm64) throws error messages

▶ ./ssh3 -v -insecure "192.168.126.130:444/ssh3-term?user=root"

9:41AM DBG dialing QUIC host at 192.168.126.130:444
9:41AM DBG QUIC handshake complete
9:41AM DBG found key in agent: <snip>
9:41AM DBG try the following Identity: agent-identity
9:41AM DBG send CONNECT request to the server
9:41AM DBG opened new session channel
9:41AM DBG sent pty request for session
9:41AM DBG sent shell request


Could not get message: timeout: no recent network activity

▶ docker run --name ssh3 --rm -p 444:444/udp -e SSH3_LOG_LEVEL=debug -v $PWD/ssl:/ssl -v ssh:/root/.ssh logopk/ssh3 /app/ssh3-server -cert /ssl/cert.pem -key /ssl/key.pem -bind 0.0.0.0:444 -v

password login is disabled
Server started, listening on 0.0.0.0:444/ssh3-term
4:22PM INF Server started, listening on 0.0.0.0:444/ssh3-term
10:40PM DBG received request from User-Agent SSH 3.0 francoismichel/ssh3 0.1.3 (major 0, minor 1, patch 3)
10:40PM DBG parsing ssh authorized key
10:40PM DBG parsing ssh-ed25519 identity
10:40PM INF got request: method: CONNECT, URL: https://192.168.126.130:444/ssh3-term?user=root
10:40PM DBG the connection was closed by the application: INTERNAL_ERROR (local): write udp [::]:444->192.168.126.1:57093: sendmsg: invalid argument
10:40PM INF conversation canceled for conversation id aEu2ntVyDA0W7Di2+QuZbstLyS+P1K49wqRqfr6Cxvs=, user root

tcpdump show a bad udp checksum

23:47:14.501739 IP (tos 0x0, ttl 64, id 156, offset 0, flags [none], proto UDP (17), length 1280)
    192.168.126.1.65002 > 192.168.126.130.444: [udp sum ok] UDP, length 1252
23:47:14.506594 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto UDP (17), length 1280)
    192.168.126.130.444 > 192.168.126.1.65002: [bad udp cksum 0x82d2 -> 0xc5cd!] UDP, length 1252
23:47:14.506991 IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto UDP (17), length 54)
    192.168.126.130.444 > 192.168.126.1.65002: [bad udp cksum 0x7e08 -> 0x358f!] UDP, length 26
23:47:14.509251 IP (tos 0x0, ttl 64, id 60816, offset 0, flags [none], proto UDP (17), length 1280)
    192.168.126.1.65002 > 192.168.126.130.444: [udp sum ok] UDP, length 1252
23:47:14.509255 IP (tos 0x0, ttl 64, id 61864, offset 0, flags [none], proto UDP (17), length 64)
    192.168.126.1.65002 > 192.168.126.130.444: [udp sum ok] UDP, length 36
23:47:14.509255 IP (tos 0x0, ttl 64, id 5391, offset 0, flags [none], proto UDP (17), length 57)
``

and netstat send buffer errors

netstat -s -u
...
Udp:
34557 packets received
794 packets to unknown port received
0 packet receive errors
1331119 packets sent
0 receive buffer errors
2 send buffer errors
...


I am aware that this is not setup nicely, as I use root in the container and can only connect to the container right now :-)


Any ideas?

Thank

Peter

`Unknown signing method: ed25519.PublicKey` error?

Hi there, thank you for this amazing piece of software that I have been waiting for so long (but now, I can even contribute to it!).

I am packaging ssh3 inside the NixOS distribution for mostly experimental users (not as a sshd replacement obviously) and I am writing an integration test for it and I see on the client:

client # 4:40PM DBG dialing QUIC host at server.ssh.acme.test:443
client # 4:40PM DBG QUIC handshake complete
client # 4:40PM WRN Could not load private key: unknown signing method: ed25519.PublicKey
client # 4:40PM ERR no suitable identity found

with an ED25519 key generated by ssh-keygen from OpenSSH tooling, does that ring a bell? Reading the source code, I cannot understand why this pattern match case fails, I am not a big Go developer in general so I may be missing something I assume.

Thank you!

bug: SSH configuration file takes precedence over CLI

👋 ! Let me start with saying that I absolutely ❤️ the idea! I currently use OIDC to create SSH certificates, which works, but requires external helpers. I think it would be great to streamline the authentication process!

The bug

I found that the client prefers the configuration from the file over the CLI host/port.

11:00PM DBG parsing user known hosts
11:00PM DBG parsed known hosts Certificates=0 InvalidLines=0
11:00PM DBG got url ConnectionURL=https://127.0.0.1:41443/
11:00PM DBG got command cmd="echo hi ssh3!"
11:00PM DBG parsed ssh config ConfigBytes=2848 SSHConfigFilePath=/home/theo/.ssh/config
11:00PM DBG parsed URL ParsedURL={"ForceQuery":false,"Fragment":"","Host":"127.0.0.1:41443","OmitHost":false,"Opaque":"","Path":"/","RawFragment":"","RawPath":"","RawQuery":"","Scheme":"https","User":null}
11:00PM DBG parsed url and port Host=127.0.0.1 Port=41443
11:00PM DBG fetched Host config ConfigHost=0.0.0.0 ConfigPort=9922 ConfigUser=theo Host=127.0.0.1 Port=41443
11:00PM DBG set hostname ConfigHostname=0.0.0.0 DialHostname=0.0.0.0 URLHostname=127.0.0.1
11:00PM DBG checked if hostname is IP HostnameIsIP=true
11:00PM DBG set port ConfigPort=9922 Port=9922 URLPort=41443
11:00PM DBG dialing QUIC host at 0.0.0.0:9922
11:00PM ERR could not establish client QUIC connection: timeout: no recent network activity
exit status 255

My ~/.ssh/config

[ other host configurations ]

Host *
  User theo
  Port 9922

For me, this qualifies as a bug because, even though my default hostname is 0.0.0.0 and port is 9922, not all run on this port (most, actually, don't). If host 127.0.0.1 (or port 22) is specified, I actually want to connect to 127.0.0.1. I would find it cumbersome to have to change the configuration file every time I want to connect to a server with a different hostname/port. Granted, it is unusual to have a default hostname, but having a default custom port is not, Imo.

Using the CLI arguments is actually the behaviour of OpenSSH-client (see man 5 ssh_config).

My solution

I would change the variable setting to first consider the hostname/IP/port/... from the CLI and fill the missing fields from the configuration files.

I believe it is enough to swap lines 413 and 415 in cli/client/main.go for the hostname

	hostname := configHostname
	if hostname == "" {
		hostname = urlHostname
	}
	hostname := urlHostname
	if hostname == "" {
		hostname = configHostname
	}

and 420/422 for the port.

	port := configPort
	if port == -1 && urlPort != "" {
		port, err = strconv.Atoi(urlPort)
		if err != nil {
			log.Error().Msgf("invalid port number: %s: %s", urlPort, err)
			return -1
		}
	}
	port, err := strconv.Atoi(urlPort)
	if err != nil && configPort == -1 {
		log.Fatal().Msg("No valid port is configured!")
		return -1
	} else if err != nil {
		port = configPort
	}

This works on my machine(tm).

As this repository does not have any guidelines on contributing, I am rasing this issue. If you advise me on how I should contribute, I would be happy to help out ^-^

Remove unnecessary HTTP layer

The server currently uses an HTTP handler that expects a CONNECT method with a protocol of SSH3. ie. instead of GET / HTTP/1.0 it expects CONNECT / SSH3.

Current stack:

+------------------------------+
|          TLS / QUIC          |
+------------------------------+
|          HTTP Server         |
+-CONNECT SSH3-+-Other methods-|
| Shell Server | HTTP Server   |
+--------------+---------------+

That's easy to implement as a proof of concept, but the HTTP layer is unnecessary and makes it harder to multiplex a server (eg. as a web server and a shell server).

I propose that you could simplify the server and protocol by removing the HTTP layer. To do this, you would use these features of TLS:

Proposed stack:

+-------------------------------+
|             TLS / QUIC        |
+-NextProto SHH--+-NextProto H2-+
| Shell Server   | HTTP Server  |
+----------------+--------------+

This way the application protocol (Shell, HTTP, others) is made at the TLS termination point rather than at the web server layer, enabling easier integration with existing services.

If you've considered this already you may want to mention the trade offs in the docs.

panic: runtime error: index out of range [0] with length 0

Installed the program from source.
Go version go1.21.4 linux/amd64

Run:
**panic: runtime error: index out of range [0] with length 0

goroutine 1 [running]:
main.mainWithStatusCode()
/install/ssh3-0.1.0/ssh3/cli/client/main.go:281 +0x65de
main.main()
/install/ssh3-0.1.0/ssh3/cli/client/main.go:1055 +0x13**

ssh3 bind only ipv6

I'm running ssh3 with the following options (Arch Linux, go 1.21.5):

./ssh3-server -cert /etc/mycert/fullchain.pem -key /etc/mycert/privkey.pem -url-path /ssh3 -bind 0.0.0.0:444 -enable-password-login -v

But it's impossible to connect to server through ipv4 address. When I started debugging the problem, I realized that server is binding only ipv6:

~ # netstat -tulpan | grep 444
udp6 0 0 :::444 :::* 3510885/./ssh3-serv

Any other configuration changes (with -bind) were unsuccessful.

Debian packaging build failures

Hi! I am preparing Debian packages of ssh3 but running in a build failure. Any ideas why this happens? I've tried 0.1.5-rc1 and 0.1.5-rc2.

https://salsa.debian.org/jas/ssh3/-/jobs/5091512

github.com/creack/pty
github.com/francoismichel/ssh3/util/linux_util
golang.org/x/crypto/ssh/agent
github.com/francoismichel/ssh3
# github.com/francoismichel/ssh3
src/github.com/francoismichel/ssh3/client.go:283:31: config.GetAll undefined (type *ssh_config.Config has no field or method GetAll)
html
internal/lazyregexp
internal/profile

"There is no daemon" statement in documentation is based on outdated premise

Modern init systems do not depend on self-daemonization, which is considered an antipattern in recent decades. Software is expected to run in the foreground so a process supervisor (launchd, systemd, etc) can simply wait() on it to exit, record its exit status, and restart it if necessary.

See f/e #63, which configures the service to run in the background with no traditional self-daemonization involved.

Server does not compile on Mac

go build -o ssh3-server server/main.go

ssh3/src/util/linux_util

src/util/linux_util/shadow.go:32:10: fatal error: 'shadow.h' file not found
#include <shadow.h>
^~~~~~~~~~
1 error generated.
obo@mac-SE23-325 ssh3 % uname -a
Darwin mac-SE23-325.local 23.1.0 Darwin Kernel Version 23.1.0: Mon Oct 9 21:28:45 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T6020 arm64
obo@mac-SE23-325 ssh3 % go version
go version go1.21.4 darwin/arm64

MacOS does not use /etc/shadow or /etc/passwd

Server compile end up with error on debian

$go version
go version go1.21.5 linux/amd64


$ go build -o ssh3-server cli/server/main.go
# ssh3/linux_server
linux_server/authorized_identities.go:39:50: undefined: linux_util.User
linux_server/authorized_identities.go:131:37: undefined: linux_util.User
linux_server/authorized_identities.go:171:53: undefined: linux_util.User
linux_server/auth.go:80:25: undefined: linux_util.UserPasswordAuthentication
linux_server/handlers.go:51:27: undefined: linux_util.GetUser

Verify certificates using local trust stores

Currently, it seems like that SSH3 only implements self signed certificates, nothing more.

In situations where you get them via Let's Encrypt, it would be nice if it could work out of the box.

Using a different QUIC implementation

I know that quic-go is the preferred solution here as they both share the same language. But I feel like that it would be a good idea to open up this application for allowing other QUIC implementations in its roots. e.g. we could then toy around with MsQuic which already supports connection migration or be able to switch over to a different stack that might become the reference implementation in the future.

i'm not fully sure how feasible that is but I just wanted to throw that idea into the pool and maybe get some feedback on it ^^

Intermittent integration_tests failures

Sometimes there is integration test failures, sometimes not. Log of failure on ppc64le:

[00:01:02] ++ go run github.com/onsi/ginkgo/v2/ginkgo ./integration_tests
[00:01:14] Running Suite: Integration Test Suite - /usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests
[00:01:14] =======================================================================================
[00:01:14] Random Seed: �[1m1702820176�[0m
[00:01:14] 
[00:01:14] Will run �[1m10�[0m of �[1m10�[0m specs
[00:01:48] �[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m
[00:01:48] �[38;5;243m------------------------------�[0m
[00:01:48] �[38;5;9m• [FAILED] [0.167 seconds]�[0m
[00:01:48] �[0mTesting the ssh3 cli �[38;5;243mWith running server �[0mInsecure �[38;5;243mClient behaviour �[0mTCP port forwarding �[38;5;9m�[1m[It] works with messages larger than a typical MTU�[0m
[00:01:48] �[38;5;243m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:239�[0m
[00:01:48] 
[00:01:48]   �[38;5;243mTimeline >>�[0m
[00:01:48]   �[90m1:36PM�[0m �[1m�[31mERR�[0m�[0m there was an error when parsing known hosts: open /root/.ssh3/known_hosts: permission denied
[00:01:48]   �[90m1:36PM�[0m �[31mWRN�[0m could not open /root/.ssh/config: open /root/.ssh/config: permission denied, ignoring config
[00:01:48]   �[90m1:36PM�[0m �[31mWRN�[0m could not open /root/.ssh3/oidc_config.json: open /root/.ssh3/oidc_config.json: permission denied
[00:01:48]   �[90m1:36PM�[0m �[33mDBG�[0m received request from User-Agent SSH 3.0 francoismichel/ssh3 0.1.3 (major 0, minor 1, patch 3)
[00:01:48]   �[90m1:36PM�[0m �[1m�[31mERR�[0m�[0m cannot parse identity line: unknown identity format: # OpenSSH authorized_keys file format is described in sshd(8) manual page.
[00:01:48]   �[90m1:36PM�[0m �[33mDBG�[0m parsing ssh authorized key
[00:01:48]   �[90m1:36PM�[0m �[33mDBG�[0m parsing ssh-rsa identity
[00:01:48]   �[90m1:36PM�[0m �[32mINF�[0m got request: method: CONNECT, URL: https://127.0.0.1:4433/ssh3-tests?user=builder
[00:01:48]   could not read data from stdin: EOF�[90m1:36PM�[0m �[32mINF�[0m eof on tcp-forwarding channel 8
[00:01:48]   �[90m1:36PM�[0m �[1m�[31mERR�[0m�[0m could read data on TCP socket: read tcp 127.0.0.1:50510->127.0.0.1:9090: read: connection reset by peer
[00:01:48]   �[38;5;9m[FAILED]�[0m in [It] - /usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:179 �[38;5;243m@ 12/17/23 13:36:57.51�[0m
[00:01:48]   �[38;5;243m<< Timeline�[0m
[00:01:48] 
[00:01:48]   �[38;5;9m[FAILED] Expected
[00:01:48]       <string>: "...ч��5ZЊ@�� Ь..."
[00:01:48]   to equal      |
[00:01:48]       <string>: "...ч��5ZЊ@�� Ь..."�[0m
[00:01:48]   �[38;5;9mIn �[1m[It]�[0m�[38;5;9m at: �[1m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:179�[0m �[38;5;243m@ 12/17/23 13:36:57.51�[0m
[00:01:48] �[38;5;243m------------------------------�[0m
[00:01:54] �[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m
[00:01:54] 
[00:01:54] �[38;5;9m�[1mSummarizing 1 Failure:�[0m
[00:01:54]   �[38;5;9m[FAIL]�[0m �[0mTesting the ssh3 cli �[38;5;243mWith running server �[0mInsecure �[38;5;243mClient behaviour �[0mTCP port forwarding �[38;5;9m�[1m[It] works with messages larger than a typical MTU�[0m
[00:01:54]   �[38;5;243m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:179�[0m
[00:01:54] 
[00:01:54] �[38;5;9m�[1mRan 10 of 10 Specs in 40.358 seconds�[0m
[00:01:54] �[38;5;9m�[1mFAIL!�[0m -- �[38;5;10m�[1m9 Passed�[0m | �[38;5;9m�[1m1 Failed�[0m | �[38;5;11m�[1m0 Pending�[0m | �[38;5;14m�[1m0 Skipped�[0m
[00:01:54] --- FAIL: TestMessage (40.36s)
[00:01:54] FAIL
[00:01:54] 
[00:01:54] Ginkgo ran 1 suite in 47.281446568s
[00:01:54] 
[00:01:54] Test Suite Failed
[00:01:54] exit status 1

Excuse me for the garbage in the output but that's how you log even if there is no tty.

On aarch64:

[00:00:44] ++ go run github.com/onsi/ginkgo/v2/ginkgo ./integration_tests
[00:00:51] Running Suite: Integration Test Suite - /usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests
[00:00:51] =======================================================================================
[00:00:51] Random Seed: �[1m1702820760�[0m
[00:00:51] 
[00:00:51] Will run �[1m10�[0m of �[1m10�[0m specs
[00:01:09] �[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m
[00:01:09] �[38;5;243m------------------------------�[0m
[00:01:09] �[38;5;9m• [FAILED] [0.079 seconds]�[0m
[00:01:09] �[0mTesting the ssh3 cli �[38;5;243mWith running server �[0mInsecure �[38;5;243mClient behaviour �[0mTCP port forwarding �[38;5;9m�[1m[It] works with messages larger than a typical MTU�[0m
[00:01:09] �[38;5;243m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:239�[0m
[00:01:09] 
[00:01:09]   �[38;5;243mTimeline >>�[0m
[00:01:09]   �[90m1:46PM�[0m �[1m�[31mERR�[0m�[0m there was an error when parsing known hosts: open /root/.ssh3/known_hosts: permission denied
[00:01:09]   �[90m1:46PM�[0m �[31mWRN�[0m could not open /root/.ssh/config: open /root/.ssh/config: permission denied, ignoring config
[00:01:09]   �[90m1:46PM�[0m �[31mWRN�[0m could not open /root/.ssh3/oidc_config.json: open /root/.ssh3/oidc_config.json: permission denied
[00:01:09]   �[90m1:46PM�[0m �[33mDBG�[0m received request from User-Agent SSH 3.0 francoismichel/ssh3 0.1.3 (major 0, minor 1, patch 3)
[00:01:09]   �[90m1:46PM�[0m �[1m�[31mERR�[0m�[0m cannot parse identity line: unknown identity format: # OpenSSH authorized_keys file format is described in sshd(8) manual page.
[00:01:09]   �[90m1:46PM�[0m �[33mDBG�[0m parsing ssh authorized key
[00:01:09]   �[90m1:46PM�[0m �[33mDBG�[0m parsing ssh-rsa identity
[00:01:09]   �[90m1:46PM�[0m �[32mINF�[0m got request: method: CONNECT, URL: https://127.0.0.1:4433/ssh3-tests?user=builder
[00:01:09]   could not read data from stdin: EOF�[90m1:46PM�[0m �[32mINF�[0m eof on tcp-forwarding channel 8
[00:01:09]   �[38;5;9m[FAILED]�[0m in [It] - /usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:225 �[38;5;243m@ 12/17/23 13:46:23.057�[0m
[00:01:09]   �[38;5;243m<< Timeline�[0m
[00:01:09] 
[00:01:09]   �[38;5;9m[FAILED] Expected
[00:01:09]       <int>: 16640
[00:01:09]   to equal
[00:01:09]       <int>: 20000�[0m
[00:01:09]   �[38;5;9mIn �[1m[It]�[0m�[38;5;9m at: �[1m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:225�[0m �[38;5;243m@ 12/17/23 13:46:23.057�[0m
[00:01:09] �[38;5;243m------------------------------�[0m
[00:01:15] �[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m�[38;5;10m•�[0m
[00:01:15] 
[00:01:15] �[38;5;9m�[1mSummarizing 1 Failure:�[0m
[00:01:15]   �[38;5;9m[FAIL]�[0m �[0mTesting the ssh3 cli �[38;5;243mWith running server �[0mInsecure �[38;5;243mClient behaviour �[0mTCP port forwarding �[38;5;9m�[1m[It] works with messages larger than a typical MTU�[0m
[00:01:15]   �[38;5;243m/usr/src/RPM/BUILD/ssh3-0.1.4/integration_tests/ssh3_test.go:225�[0m
[00:01:15] 
[00:01:15] �[38;5;9m�[1mRan 10 of 10 Specs in 24.303 seconds�[0m
[00:01:15] �[38;5;9m�[1mFAIL!�[0m -- �[38;5;10m�[1m9 Passed�[0m | �[38;5;9m�[1m1 Failed�[0m | �[38;5;11m�[1m0 Pending�[0m | �[38;5;14m�[1m0 Skipped�[0m
[00:01:15] --- FAIL: TestMessage (24.31s)
[00:01:15] FAIL
[00:01:15] 
[00:01:15] Ginkgo ran 1 suite in 28.33480022s
[00:01:15] 
[00:01:15] Test Suite Failed
[00:01:15] exit status 1

It looks different.

We have 3 architecture and almost any build&test run cause failure on some of them.

ssh3 and PAM

For now ssh3 doesnt using pam modules. If you login with password (using the special parameter), server will authorize you even if it have pam modules with 2-factor authentication.
I understand that the main purpose is authorization using keys or oidc. Are there any plans to add support for pam modules?

add support for PKCS11

This will enable various hardware backed private key tokens: Yubikey, Smartcards, TPM

Inquiry About Dynamic Port Forwarding for Full-Featured SOCKS5 Proxy in ssh3

Hello ssh3 Team,

I hope this message finds you well. I am reaching out to inquire about the current or planned support for dynamic port forwarding in ssh3, similar to the SSH -D command line switch found in traditional SSH clients.

I've noticed that ssh3 supports UDP port forwarding, which is fantastic. Given this capability, it seems that ssh3 could potentially offer a full-featured SOCKS5 proxy with UDP support through dynamic port forwarding. This feature would be extremely beneficial for users who require enhanced security and privacy, as it allows for setting up a SOCKS proxy that can tunnel through the SSH connection.

Could you please provide some information on whether this feature is on the roadmap? If it is not currently in development, would you consider adding it in future releases?

Your insights on this matter would be greatly appreciated. It would help in our decision-making processes regarding the adoption of tools in our workflows.

Thank you for your dedication to developing ssh3. I look forward to hearing from you.

Best regards,

Vadim

32-bit architectures: util/linux_util/linux_user.go:176:31: cannot use _Ctype_ulong(bufLen) (value of type _Ctype_ulong) as _Ctype_uint value in argument to (_Cfunc__CMalloc)

(Native) build error on 32-bit architectures (i586 and arm32):

[00:00:27] + go build -v -o ssh3-server cli/server/main.go
[00:00:27] text/tabwriter
[00:00:27] html
[00:00:27] internal/lazyregexp
[00:00:27] runtime/trace
[00:00:27] github.com/creack/pty
[00:00:27] runtime/pprof
[00:00:27] internal/profile
[00:00:27] ssh3/util/linux_util
[00:00:28] net/http/pprof
[00:00:28] # ssh3/util/linux_util
[00:00:28] util/linux_util/linux_user.go:176:31: cannot use _Ctype_ulong(bufLen) (value of type _Ctype_ulong) as _Ctype_uint value in argument to (_Cfunc__CMalloc)
[00:00:28] util/linux_util/linux_user.go:180:77: cannot use _Ctype_ulong(bufLen) (value of type _Ctype_ulong) as _Ctype_uint value in variable declaration

SSH Agent forwarding does not work

I have Pageant on Windows host, that works fine with PuTTY on workstation A. When I connect using SSH2, it works with ssh 2 client on Linux host B connecting to Linux host C.
I clearly see that $SSH_AUTH_SOCK is exposed on host B:

b.example.com $ echo $SSH_AUTH_SOCK
/tmp/ssh-XXXXekFLue/agent.3841213

when I'm trying to connect to Linux host C from B, ssh3 -v [email protected]/ssh3-term I see 5:50PM ERR could not dial c.example.com:444/ssh3-term: no suitable identity found.

At the same time ssh2 ssh [email protected] connects as expected.

Please advise.

Support for reverse connections

First of all let me say this seems like a really interesting project!

One thing I think it could also be useful for is remote access to IoT devices. IoT devices often sit behind a NAT and only have outbound HTTP access. Granted, sometimes they might not even have outbound HTTP/3 access due to UDP restrictions but I think those days are numbered and those cases are limited. These devices sometimes also have laggy Internet connections over 2G (for which SSH3 seems like a good fit). Therefore it would be beneficial if SSH3 supported a reverse persistent connection. Where the "client" sets up a persistent connection to a server (like for example autossh).

Missing explanation for secure host keys

The readme states:

X.509 certificates: you can now use your classical HTTPS cerificates to authenticate your SSH3 server. This mechanism is more secure than the classical SSHv2 host key mechanism.

but that's very vague. In what scenarios is it more secure / why? Does the comparison include SSHFP? Why is it more secure than CA signed host keys? etc.

Too low OIDC information for debugging

I'm trying to configure OIDC (keycloak) with ssh3.
Following to readme, done authorized_identities and oidc_config.json
"issuer_url": "https://keycloakdomain/realms/master"

When trying connect to server with parameters:
.\ssh3.exe -use-oidc https://keycloakdomain/realms/master user@server/verysecret

Getting error:
ERR could not establish SSH3 conversation: no suitable identity found

Which identity wanted by server? In which scopes and parameters it looking for? Verbose flag can't answer this questions. For now it's impossible to debug this feature :(

Rename SSH3 => SSHH3 ?

This project is not an iteration of SSH as it does not extend the SSH protocol itself and is not compatible with existing clients nor tooling and runs on a completely different port and server architecture.
Which leads me to assume that the number 3 was acquired from the use of http/3 proposals.

As such the long form description is "SSHv2 over HTTP/3" so my question is:
Wouldn't it be more correct to shorten it to sshh3 or sshh ?

-- You've created something cool but completely different :-)

Erratic behavior when SSH-ing with IPv6 hosts

I'm trying to use it with IPv6 and I notice multiple erratic behaviors with the PTY initialization and stuff, here's an log of the client in verbose:

11:20PM DBG dialing QUIC host at [snip]:8443
2024/01/25 23:20:57 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.
11:20PM DBG QUIC handshake complete
11:20PM DBG try the following Identity: pubkey-identity: ALG=RS256
11:20PM DBG send CONNECT request to the server
11:20PM DBG opened new session channel
11:20PM DBG sent pty request for session
11:20PM DBG sent shell request
11:20PM DBG received data #                                                                                                                                                                                                                   
Could not get message: INTERNAL_ERROR (local): write udp [::]:34297->[snip]:8443: sendmsg: invalid argument

After this crash, the terminal is broken because I suppose it was not reset properly on the exit.

Reverse proxy for ssh3

Since ssh3 uses http/3, it is theoretically possible to host it behind a reverse proxy. Then there is no need to use x509 certificates (there is no such option now).
I tried to host ssh3 behind angie (a fork of nginx that can use http/3 both ways), but I'm running into the following problem (with verbose):

DBG dialing QUIC host at myhost:443
DBG QUIC handshake complete
password for https://root@myhost:443/ssh3?user=root:
DBG try the following Identity: password-identity
DBG send CONNECT request to the server
ERR bad SSH version fields
ERR Could not parse server version: "Angie"
ERR Could not open channel: returned non-200 and non-401 status code: 400

And Angie log:

quic reserved transport param id:0x4d4, skipped while handling frames, client: 10.10.0.4, server: 0.0.0.0:443
quic unknown transport param id:0x20, skipped while handling frames, client: 10.10.0.4, server: 0.0.0.0:443
client sent unknown pseudo-header ":protocol" while reading client request, client: 10.10.0.4, server: myhost

Is my idea possible?

Add support for AcceptEnv/SendEnv

with ssh the LC_* variables are inherited from the client session. with ssh3 they are system defaults.

$ grep -ri Env /etc/ssh/ssh*_config
/etc/ssh/ssh_config:    SendEnv LANG LC_*
/etc/ssh/sshd_config:# Allow client to pass locale environment variables
/etc/ssh/sshd_config:AcceptEnv LANG LC_*

ssh3

glen@niblus:/etc/pam.d $ locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

ssh

glen@niblus:~ $ locale
LANG=en_GB.UTF-8
LANGUAGE=
LC_CTYPE="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_PAPER="en_GB.UTF-8"
LC_NAME="en_GB.UTF-8"
LC_ADDRESS="en_GB.UTF-8"
LC_TELEPHONE="en_GB.UTF-8"
LC_MEASUREMENT="en_GB.UTF-8"
LC_IDENTIFICATION="en_GB.UTF-8"
LC_ALL=

Certs by SPIRE

It would be really nice if the certificates for the servers could be fetched from SPIRE (https://github.com/spiffe/spire). This would allow things such as easily attesting the workload by hardware TPM and then giving access to a valid cert to ssh3.

Unable to install on Termux

Hello, I hope you're doing well.

I encountered an issue while trying to install ssh3 on Termux(aarch64) using the provided installation command(go install github.com/francoismichel/ssh3/cmd/...@latest), the installation fails with the following error:

fatal error: 'shadow.h' file not found

Complete Output on Termux

go: downloading github.com/francoismichel/ssh3 v0.1.6
go: downloading github.com/kevinburke/ssh_config v1.2.0
go: downloading github.com/quic-go/quic-go v0.40.1-0.20240102075208-1083d1fb8f98
go: downloading github.com/rs/zerolog v1.31.0
go: downloading golang.org/x/crypto v0.17.0
go: downloading github.com/caddyserver/certmagic v0.20.0
go: downloading github.com/creack/pty v1.1.18
go: downloading go.uber.org/zap v1.24.0
go: downloading github.com/coreos/go-oidc/v3 v3.7.0
go: downloading golang.org/x/oauth2 v0.13.0
go: downloading golang.org/x/term v0.15.0
go: downloading github.com/golang-jwt/jwt/v5 v5.0.0
go: downloading golang.org/x/exp v0.0.0-20221205204356-47842c84f3db
go: downloading github.com/klauspost/cpuid/v2 v2.2.5
go: downloading github.com/libdns/libdns v0.2.1
go: downloading github.com/mholt/acmez v1.2.0
go: downloading github.com/miekg/dns v1.1.55
go: downloading github.com/zeebo/blake3 v0.2.3
go: downloading golang.org/x/net v0.17.0
go: downloading github.com/quic-go/qpack v0.4.0
go: downloading golang.org/x/sys v0.15.0
go: downloading go.uber.org/atomic v1.11.0
go: downloading go.uber.org/multierr v1.11.0
go: downloading github.com/go-jose/go-jose/v3 v3.0.1
go: downloading github.com/mattn/go-isatty v0.0.19
go: downloading golang.org/x/text v0.14.0
# github.com/francoismichel/ssh3/util/unix_util
../../go/pkg/mod/github.com/francoismichel/[email protected]/util/unix_util/linux_user.go:11:10: fatal error: 'shadow.h' file not found
   11 | #include <shadow.h>
      |          ^~~~~~~~~~
1 error generated.

Attempted to resolve the issue by creating a proot-distro Alpine Linux environment using:

proot-distro install --override-alias alpine1 alpine
proot-distro login alpine1 --isolated

But, The installation still fails with the following error:

undefined: userPasswordAuthentication
undefined: passwordAuthAvailable
Complete Output on Termux using proot-distro command

go: downloading github.com/francoismichel/ssh3 v0.1.6
go: downloading github.com/creack/pty v1.1.18
go: downloading github.com/quic-go/quic-go v0.40.1-0.20240102075208-1083d1fb8f98
go: downloading github.com/rs/zerolog v1.31.0
go: downloading github.com/caddyserver/certmagic v0.20.0
go: downloading go.uber.org/zap v1.24.0
go: downloading github.com/kevinburke/ssh_config v1.2.0
go: downloading golang.org/x/crypto v0.17.0
go: downloading github.com/golang-jwt/jwt/v5 v5.0.0
go: downloading golang.org/x/exp v0.0.0-20221205204356-47842c84f3db
go: downloading github.com/klauspost/cpuid/v2 v2.2.5
go: downloading github.com/libdns/libdns v0.2.1
go: downloading github.com/mholt/acmez v1.2.0
go: downloading github.com/miekg/dns v1.1.55
go: downloading github.com/zeebo/blake3 v0.2.3
go: downloading golang.org/x/net v0.17.0
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading github.com/coreos/go-oidc/v3 v3.7.0
go: downloading golang.org/x/oauth2 v0.13.0
go: downloading golang.org/x/term v0.15.0
go: downloading go.uber.org/atomic v1.11.0
go: downloading go.uber.org/multierr v1.11.0
go: downloading golang.org/x/sys v0.15.0
go: downloading github.com/quic-go/qpack v0.4.0
go: downloading github.com/go-jose/go-jose/v3 v3.0.1
go: downloading github.com/mattn/go-isatty v0.0.19
go: downloading golang.org/x/text v0.14.0
# github.com/francoismichel/ssh3/util/unix_util
go/pkg/mod/github.com/francoismichel/[email protected]/util/unix_util/user.go:20:9: undefined: getUser
go/pkg/mod/github.com/francoismichel/[email protected]/util/unix_util/user.go:87:9: undefined: userPasswordAuthentication
go/pkg/mod/github.com/francoismichel/[email protected]/util/unix_util/user.go:91:9: undefined: passwordAuthAvailable
localhost:~# echo error $?
error 1

mesg: cannot open /dev/pts/6: Permission denied

appears openssh manages to make terminal owned by logged in user. also /etc/motd is not displayed with ssh3 and last login info

with ssh3:

$ ssh3 -privkey ~/.ssh/id_rsa niblus.local:444/ssh3-term
mesg: cannot open /dev/pts/6: Permission denied
glen@niblus:~ $ l `tty`
crw--w---- 1 root tty 136, 6 Dec 18 15:30 /dev/pts/6

with openssh

$ ssh niblus
Linux niblus 6.1.0-rpi6-rpi-2712 #1 SMP PREEMPT Debian 1:6.1.58-1+rpt2 (2023-10-27) aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Dec 14 18:06:21 2023 from 192.168.0.35

Wi-Fi is currently blocked by rfkill.
Use raspi-config to set the country before use.

glen@niblus:~ $ l `tty`
crw--w---- 1 glen tty 136, 6 Dec 18 15:30 /dev/pts/6

bug: self-signed x509 certificates with custom SAN raise MITM error

The issue

When creating a self-signed certificate with a custom SAN, trusting it, then running the SSH3 client again raises a MITM error:

7:28PM ERR The server certificate cannot be verified using the one installed in /home/theo/.ssh3/known_hosts. If you did not change the server certificate, it could be a machine-in-the-middle attack. TLS error: CRYPTO_ERROR 0x12a (local): tls: failed to verify certificate: x509: certificate is valid for selfsigned.ssh3.asdf, *, not oumpah-pah.nwrd.fischernet.net
7:28PM ERR Aborting.
exit status 255

Steps to reproduce

First, generate custom x509 certificates using OpenSSL:

openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout priv.key -days 3660 -out cert.pem -subj "/C=XX/O=Default Company/OU=XX/CN=selfsigned.ssh3" -addext "subjectAltName = DNS:selfsigned.ssh3.asdf,DNS:*"

Then run the server using -cert cert.pem -key priv.key and try to log in.

The first time, the client outputs this:

Received an unknown self-signed certificate from the server.
We recommend not using self-signed certificates.
This session is vulnerable a machine-in-the-middle attack.
Certificate fingerprint: SHA256 jVh5A/EBAtSsfPSQS3f4G67FBLJIKAohkC+dcdLfIWA=
Do you want to add this certificate to ~/.ssh3/known_hosts (yes/no)? yes
Successfully added the certificate to /home/theo/.ssh3/known_hosts, please rerun the command

The second time this:

7:28PM ERR The server certificate cannot be verified using the one installed in /home/theo/.ssh3/known_hosts. If you did not change the server certificate, it could be a machine-in-the-middle attack. TLS error: CRYPTO_ERROR 0x12a (local): tls: failed to verify certificate: x509: certificate is valid for selfsigned.ssh3.asdf, *, not ssh3.local
7:28PM ERR Aborting.
exit status 255

Expected behaviour

The client accepts the trusted certificate.

For me, this is a bug, as I explicitly trust the certificate the server presents.

Resolution

If the SANs save are the same as the one presented, then the client should accept the certificate (although all other certificate parameters should also be taken into account, like expiry).

That should be around line 473 in cli/client/main.go

Access denied from the server: unauthorized

client and server version is: 0.1.4

server log:

./ssh3-server -v -bind :59959 -url-path /abc
password login is currently disabled
Server started, listening on :59959/abc
8:06PM INF Server started, listening on :59959/abc
8:08PM DBG received request from User-Agent SSH 3.0 francoismichel/ssh3 0.1.3 (major 0, minor 1, patch 3)
8:08PM DBG parsing ssh authorized key
8:08PM DBG parsing ssh-rsa identity
8:08PM DBG parsing ssh authorized key
8:08PM DBG parsing ssh-rsa identity
8:08PM ERR invalid private key token: token signature is invalid: crypto/rsa: verification error
8:08PM ERR invalid private key token: token signature is invalid: crypto/rsa: verification error
8:08PM DBG received request from User-Agent SSH 3.0 francoismichel/ssh3 0.1.3 (major 0, minor 1, patch 3)
8:08PM DBG parsing ssh authorized key
8:08PM DBG parsing ssh-rsa identity
8:08PM DBG parsing ssh authorized key
8:08PM DBG parsing ssh-rsa identity
8:08PM DBG parsing ssh authorized key
8:08PM DBG parsing ssh-rsa identity
8:08PM ERR invalid private key token: token signature is invalid: crypto/rsa: verification error
8:08PM ERR invalid private key token: token signature is invalid: crypto/rsa: verification error
8:08PM ERR invalid private key token: token has invalid claims: token used before issued

client log:

./ssh3 -insecure -v -privkey ~/.ssh/id_rsa [a.b.c.d]:59959/abc
12:09PM DBG dialing QUIC host at a.b.c.d
12:09PM DBG QUIC handshake complete
12:09PM DBG try the following Identity: pubkey-identity: ALG=RS256
12:09PM DBG send CONNECT request to the server
12:09PM ERR Access denied from the server: unauthorized

I already add the public key(id_rsa.pub) of ~/.ssh/id_rsa into the server side ~/.ssh/authorized_keys

If I don't add the public key, it will return 8:08PM ERR invalid private key token: token signature is invalid: crypto/rsa: verification error, once I add, the server side log will show 8:08PM ERR invalid private key token: token has invalid claims: token used before issued

Can you help to check it? thank you~~

proxy-jump error

Hello,

in the documentation I saw that the ssh ProxyJump option is implemented. I was testing this, but I get an error and could not figure out so far where the problem is.

I can connect to both hosts directyl just fine. But when I specify -proxy-jump, it does not work.

◆ ssh3 git:(main) ✗ ❯❯❯ ./ssh3 -insecure -pubkey-for-agent ~/.ssh/id_ed25519.pub -forward-agent -proxy-jump [email protected]/ssh3 -v [email protected]/ssh3
5:15PM DBG version francoismichel/ssh3 0.1.7
5:15PM DBG no OIDC config file specified, use default file: /Users/marco/.ssh3/oidc_config.json
5:15PM DBG /Users/marco/.ssh3/oidc_config.json does not exist
5:15PM DBG dialing QUIC host at 192.168.2.77:443
5:15PM DBG QUIC handshake complete
5:15PM DBG try ssh-agent-based auth
5:15PM DBG we only try the first specified auth method for now
5:15PM DBG try the following Identity: agent-identity
5:15PM DBG establish conversation with the server
5:15PM DBG send CONNECT request on URL https://192.168.2.77:443/ssh3?user=pi, User-Agent="SSH 3.0 francoismichel/ssh3 0.1.7 experimental_spec_version=alpha-00"
5:15PM DBG got response with 200 OK status code
5:15PM DBG server has valid version "SSH 3.0 francoismichel/ssh3 0.1.7 experimental_spec_version=alpha-00" (protocol version = 3.0_alpha-00, software version = francoismichel/ssh3 0.1.7)
5:15PM DBG start UDP forwarding from 127.0.0.1:0 to 192.168.2.215:443
5:15PM DBG started proxy jump at 127.0.0.1:53179
5:15PM DBG dialing QUIC host at 127.0.0.1:53179
5:15PM ERR could not establish client QUIC connection: timeout: no recent network activity
5:15PM ERR could not setup transport for client: %!s(<nil>)

If I capture packets on the jump host towards the destination, I do not see a single packet leaving.
Am I specifying something wrong? Or is there an even higher debug level that I can enable? There is no error on the proxy server side.

A few questions

This is an interesting project but I have a few questions that don't seem to be raised in the readme.

  1. What kind of security audit and review has been done over the project ?
  2. Has any team or company been approached thus far for security review or are you just hoping since its a public github it will get done at some point ?
  3. Has there been any approach to the openssh team to roll in any of the changes (which from my cursory reading is really over certificate handling but I'm probably wrong here) ?
  4. If the answer to number 3 is yes - do you have a link to any discussion with that team I could review ?

ERR cannot parse identity line: unknown identity format: # OpenSSH authorized_keys file format is described in sshd(8) manual page.

Comments in authorized_keys cause an error: ERR cannot parse identity line: unknown identity format: # OpenSSH authorized_keys file format is described in sshd(8) manual page.

ALT Linux have comment in authorized_keys at the 1st line for each user by default:

# OpenSSH authorized_keys file format is described in sshd(8) manual page.

ps. Alto it's common for users to comment old keys instead of deleting them so this is not an error.

simplify install

go supports cloning via git+ssh, so you can use the toolchain to do the install ie. go install github.com/francoismichel/ssh3/cli/server@latest. You need better folder names though, b/c it's going to install the tool as $GOBIN/server

In go, it's more typical to use a cmd sub folder, maybe checkout go tools for ideas on how you want to support it: https://pkg.go.dev/golang.org/x/tools

My suggestion would be something like:

Server install

go install github.com/francoismichel/ssh3/cmd/sshd@latest

Client install

go install github.com/francoismichel/ssh3/cmd/ssh@latest

I'm happy to reoganize the repo to pretty paths.

Support 0RTT

Quic supports 0RTT (zero roundtrip connection initiation) for HTTP; perhaps it can support it for SSH3 too?

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.