0 votes
by (250 points)

Hi,
We have a client/server application, where the server (console app on Windows) is exposing an SFTP endpoint, implemented with Rebex FileServer library, and the client is connecting to it, using Rebex SFTP library.
I am trying to validate the server I am connecting to, from the client, using a server certificate (signed by a CA, similar to a TLS certificate), instead of a public key (https://smallstep.com/blog/use-ssh-certificates/).
The reason is to avoid having to know in the client, the server key thumbprint.
The server certficate is read from WIndows cert store (including the private key) like this:

X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
var sftpServer = new FileServer();
sftpServer.Bind(port, FileServerProtocol.Sftp);
sftpServer.Keys.Add(new SshPrivateKey(cert.PrivateKey));
sftpServer.Settings.AllowedAuthenticationMethods = AuthenticationMethods.Password;
...
sftpServer.Start()

On the client, I am connecting like this:

var ftp = new Sftp();
ftp.Settings.SshParameters.AuthenticationMethods = SshAuthenticationMethod.Password;
...
ftp.Connect(serverName, port);
// this is where I expect to get an error only if the server cert is invalid 
ftp.Login(user, password);

The root CA exists on both the server and client computer.
Now, at Connect I get no error/exception.

(I use the latest Rebex component versions, on Windows 10, .NET Framework 4.8)

I also tried to manually validate the server certificate like this:

SshPublicKey serverKey = ftp.ServerKey;
Rebex.Security.Certificates.Certificate publicServerCertificate = serverKey.GetCertificate();
var validationResult = publicServerCertificate.Validate();
if (!validationResult.Valid)
{ ... }

but serverKey.GetCertificate() returns null.

I would avoid showing a prompt to the user to accept the server key thumbprint, as I know that I use a certificate that is already signed by a public CA (the client application is always connecting to the same server app, but we try to avoid man-in-the middle attacks).

Applies to: Rebex SFTP

1 Answer

+1 vote
by (148k points)

Hi, it looks like you are setting up the server to use the key auhtentication (based on the certificate's key) instead of certificate authentication. Also, you are using X509Store/X509Certificate, so a conversion to Rebex Certificate is needed. Instead of this:

sftpServer.Keys.Add(new SshPrivateKey(cert.PrivateKey));

Try this:

var rebexCert = new Certificate(cert.RawData);
rebexCert.Associate(cert.PrivateKey);
sftpServer.Keys.Add(new SshPrivateKey(rebexCert));

Additionally, I would like to clarify the term "SSH certificates", because there is a bit of confusion in this area. Basically, there are two kinds of certificates used with SSH protocol:

  1. X.509 certificates. These are the same kind of certificates used with TLS to secure HTTP and other protocols since 1990s. This is the type of certificates supported by well-known certificate authorities such as Digicert, GlobalSign, Let's Encrypt, and other. SSH servers such as VanDyke VShell or Tectia SSH have supported X.509 certificates since early 2000s, and there is a fork of OpenSSH (PKIX-SSH) that adds support for them. Usage of X.509 certificates with SSH is specified by RFC 6187.

  2. OpenSSH certificates. In 2010, instead of adding support for X.509 certificates, OpenSSH introduced their own proprietary kind of certificates that are incompatible with X.509 certificate infrastructure and with SSH implementations that supported X.509 certificates. OpenSSH certificates are also not supported by Windows certificate stores.

Rebex SFTP and Rebex File Server only support X.509 certificates. However, the smallstep article is about OpenSSH certificates, and unfortunately, it does not mention the drawbacks. While we agree with smallstep that using certificates with SSH is a good thing, we disagree about which ones. In our view, OpenSSH certificates were a terrible idea. We just don't see any benefit in having to maintain two separate certificate infrastructures - one for X.509 certificates, the other for OpenSSH's certificates.

From a practical viewpoint, this means that if you configure Rebex File Server to only use X.509 certificates, the server will only be compatible with SFTP/SSH clients that support it as well. And unfortunately, support for X.509 certificates in third-party immplementions is still quite rare (support for OpenSSH certificates is most likely even rarer).

by (250 points)
Thanks for the answer!
Indeed, I was talking about X.509 certificates. I already have one on the server used for another service, and I'm trying to 're-use' it also for the SFTP endpoint.

I think I managed to successfully use it like this:

// on the server
X509Certificate2 cert = ....           
Certificate serverCert = new Certificate(cert);
_sftpServer.Keys.Add(new SshPrivateKey(serverCert));
--------------

// on the client
var ftp = new Sftp();
...
ftp.Connect(server, port);
// validate
SshPublicKey serverKey = ftp.ServerKey;
Certificate publicServerCert = serverKey.GetCertificate();
var validationResult = publicServerCert.Validate(ValidationOptions.SkipRevocationCheck);
if (!validationResult.Valid)
{ .... }
by (148k points)
Yes, that should work as well (there has just been a rare scenario where Associate was necessary). Actually, you might even use the implicit constructor of the Certificate class and do this:

X509Certificate2 cert = ....           
_sftpServer.Keys.Add(new SshPrivateKey(cert));
...