francoismichel / ssh3

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/
https://arxiv.org/abs/2312.08396
Apache License 2.0
3.28k stars 83 forks source link

Verify certificates using local trust stores #40

Open RaitoBezarius opened 10 months ago

RaitoBezarius commented 10 months ago

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.

francoismichel commented 10 months ago

the SSH3 server should be able to use your Let's Encrypt X509 certificate. I have a server using one. :-)

You just need to set the -cert and -key CLI args to your Let's Encrypt fullchain and key when running ssh3-server. Does it work for you ? Let me know if you have problems doing it.

RaitoBezarius commented 10 months ago

@francoismichel I tried that and the client was not able to verify it, so I am a bit curious what happened here. How do you verify the certificate against the system trust store?

francoismichel commented 10 months ago

I am using x509.SystemCertPool() that uses the local trust store of the OS. But depending on the distribution, I guess it might struggle finding the system certificates.

https://github.com/francoismichel/ssh3/blob/96b63ccb4b7d8b44f0697462cb6db1d857c1cd5e/cli/client/main.go#L455

The doc of x509.SystemCertPool() says:

On Unix systems other than macOS the environment variables SSL_CERT_FILE and SSL_CERT_DIR can be used to override the system default locations for the SSL certificate file and SSL certificate files directory, respectively. The latter can be a colon-separated list.

Maybe you want to play with these variables ?

francoismichel commented 10 months ago

@RaitoBezarius Did you have the time to try it out ? Is there something I can do on my side for it to work more smoothly or should we mark the issue as resolved ?

RaitoBezarius commented 10 months ago

I'm still getting client # 5:55PM ERR the peer provided an unknown, insecure certificate, that is not self-signed: x509: invalid signature: parent certificate cannot sign this kind of certificate with a certificate that I trust in my system store :/. If I curl with that an TLS server, it seems to work.

mpiraux commented 10 months ago

If you're familiar with the strace utility or any system call tracing tool, you could find where curl is looking for them and compare that to where ssh3 is looking. Also looking at your shell environment variables might help finding how these paths are passed to the executable :)

francoismichel commented 10 months ago

On Linux, here is where Go searches for certs by default (source):


// Possible certificate files; stop after finding one.
var certFiles = []string{
    "/etc/ssl/certs/ca-certificates.crt",                // Debian/Ubuntu/Gentoo etc.
    "/etc/pki/tls/certs/ca-bundle.crt",                  // Fedora/RHEL 6
    "/etc/ssl/ca-bundle.pem",                            // OpenSUSE
    "/etc/pki/tls/cacert.pem",                           // OpenELEC
    "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
    "/etc/ssl/cert.pem",                                 // Alpine Linux
}

// Possible directories with certificate files; all will be read.
var certDirectories = []string{
    "/etc/ssl/certs",               // SLES10/SLES11, https://golang.org/issue/12139
    "/etc/pki/tls/certs",           // Fedora/RHEL
    "/system/etc/security/cacerts", // Android
}

You can compare these paths with what curl does.

When I run curl, I can see that Curl finds the CA bundle for certificates in /etc/pki/tls/certs/ca-bundle.crt (cf `CAfile and CAPath):

user@host:~$ curl -v https://google.com
* processing: https://google.com
*   Trying [2a00:1450:400e:810::200e]:443...
* Connected to google.com (2a00:1450:400e:810::200e) port 443
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
[...]

Does curl find a CA in a file/dir that golang does not look at ?