Pure-Rust asynchronous SSH library, both client and server

#24 Alternative dependencies

Opened by darleybarreto on February 17, 2021
darleybarreto on February 17, 2021

Hi folks, first of all I would like to say great work on this crate! I was wondering what you think about replacing the dependency of openssl with rustls and adding a feature to use AEADs instead of libsodium (replacing probably wouldn’t be the right move)? Does these make sense? I would be glad to help.

pmeunier on February 17, 2021

Excellent question. The author of *ring* even contributed an interface in the early days of this crate, actually.

This is a great idea (I loved it and accepted all his patches), but unfortunately a slightly naïve one, as we found out later. Indeed, in TLS, the author of the server is responsible for using the right formats and versions, and the PKI is here to make keys work. However, in SSH, both the client and the server have that responsibility, and the problem is that the end-users of clients are not always knowledgeable about these things, or willing to change their habits.

When I first read the SSH RFCs, I first thought it would be easy. And the protocol was indeed easy to implement, but the true difficulty was actually to deal with the many outdated key formats and protocol versions, and listening to people angry that their favourite cryptography standard from the 1990s isn’t supported.

So, getting rid of Openssl would be a good goal, but a very hard one. Making it optional would probably be a better option, and it is totally doable. Then, about AEADs, I believe this could be a good starting point, but I would like to first be convinced that writing them in pure Rust is not a security risk.

My understanding of things is that:

  • One downside of implementing stuff in a high-level language like Rust is that one loses control over the produced assembly. Of course, controlling the assembly isn’t a solution to everything, because even processors have their flaws, but it can help against some issues (like timing attacks).

  • Moreover, these block/stream ciphers are generally not very hard to implement in C/ASM from a memory-management point of view, because no memory is allocated on the heap and most lengths are fixed and hard-coded, so “out-of-bounds” accesses are very unlikely, and types don’t help very much, because everything is a [u8; SOME_FIXED_SIZE] anyway.

  • The main place where Rust is actually super useful is implementing the protocols, because types become very useful here, and a lot of checks can be done at compile-time. In Thrussh, the protocol state automaton is actually partially encoded into the type system, and that has been useful more than once.

So, in conclusion, I’m totally in favor of this (especially since OpenSSH is annoying on non-Linux platforms), but it needs more discussion about safety.

darleybarreto on February 17, 2021

I totally agree with the safety concerns around newer Rust crypto alternatives. Adding rustls and AEAD should be a feature left to the user to choose, whereas the default has to be the current implementation. My motivation on this was to provide a “pure Rust” (requiring nothing else but rustc) opt-in alternative, but ring won’t work unless all the asm is ported to asm! (nightly only), right?

pmeunier on February 17, 2021

Then I totally agree with that goal, I think it’s great and I can provide mentoring and even direct help with the code. One of the difficulties in compiling Pijul on Windows/MacOS is precisely OpenSSL.

An easier setup on Windows actually leads to more security, regardless of timing attacks, because people use the intended code instead of downloading malicious OpenSSL DLLs.

Clients are probably more susceptible to timing attacks than servers, because servers are usually dedicated to a single task, and the processes running along the SSH server are usually tightly controlled, whereas clients can run all sorts of things in parallel to their SSH client.

However, response times matter a lot for servers, because they’re usually under load, whereas sleeping for a random time in the range of 100-1000µs after each crypto operation for clients may fix timing attacks. We must be careful to use seeded RNGs to decide how much time to wait, so that the system’s entropy (possibly correlated with the computation) isn’t even taken into account.

Before you start, I believe it would be good communication practice to talk to the RustCrypto folks. They probably have an opinion about this, and I’d be curious to hear it.

darleybarreto on February 17, 2021

Browsing their repo I’ve seen this comparison. I will also ask them if it’s on their plan on using stdarch/packed_smid on the future (when stable), would spare the trouble of using another crate.

pmeunier on February 17, 2021

Wait, it seems *ring* is significantly faster. *ring* didn’t have sodium-like functions when we tried to integrate it in Thrussh, I’m happy to see that has changed. So, I wonder why they’re duplicating the work there, is it for some Rust-nightly reason that you can’t use asm! on stable?

This would be a very good replacement for libsodium actually, even without feature-gates.

darleybarreto on February 17, 2021

Actually I browsed a bit, there’s several issues and MRs throughout the RustCrypto’s ecosystem about improving parallelism and enabling x86/x86_64 and “portable” SIMD. So it’s a matter of time.

darleybarreto on February 17, 2021

So, I wonder why they’re duplicating the work there, is it for some Rust-nightly reason that you can’t use asm! on stable?

Do you mean on ring?

darleybarreto on June 27, 2021

Dear @pmeunier, I am sorry for disappearing all this time, I was too busy with my masters. I realized that you made OpenSSL optional without adding rustls dependency, great work! WRT ring, they have a bunch of asm that need be bundled together with rust code to run on stable. Eventually when asm! hits stable, all this can be placed on the rust code and compiled with rustc, but until then, one has to use an assembler.

I was thinking of having a feature gate to an experimental usage of RustCrypto implementations. AFAIK, their ChaCha20Poly1305 was audited.

You said the following

Before you start, I believe it would be good communication practice to talk to the RustCrypto folks. They probably have an opinion about this, and I’d be curious to hear it.

So the idea is to ask them how robust their RNGs are WRT current computations?

pmeunier on June 27, 2021

Hi! Did you complete your masters? That’s the important bit here!

So the idea is to ask them how robust their RNGs are WRT current computations?

Yes. And also whether they have additional hints to make it more robust (i.e. maybe adding random timers around the crypto functions).

darleybarreto on June 27, 2021

Hi! Did you complete your masters? That’s the important bit here!

Yes, I did, thanks for asking!

Yes. And also whether they have additional hints to make it more robust (i.e. maybe adding random timers around the crypto functions).

Great, I’ll ask them. Also, would you happen to have a github user so I could ping you there too?

pmeunier on June 27, 2021

Yes, I did, thanks for asking!

So, what’s next?

Also, would you happen to have a github user so I could ping you there too?

P-E-Meunier is my GitHub pseudo.

darleybarreto on June 27, 2021

So, what’s next?

Right now I am looking into positions to work in related areas to my main interests, i.e., Machine Learning, Data Science, R&D and Research Software Engineering Dev.

P-E-Meunier is my GitHub pseudo.

Great, I’ll reach out to them and ping you!

darleybarreto on June 29, 2021

Following up on the discussion, I opened an issue and that’s the response:

Are the RNGs robust to current computations (so a malicious agent cannot take advantage of them)?

Our crates do not provide or make assumptions about RNGs, but rather allow you to plug in any explicitly parameterized RNG you want using traits from the rand_core crate. They pretty much all use a signature of impl CryptoRng + RngCore.

What you folks recommend to increase robustness, e.g., adding random timers around the crypto functions calls?

Our implementations of ciphers used in the context of a protocol like OpenSSH already take great care to avoid any use of things like lookup tables, secret-dependent pointers, or secret-dependent branches, often with state-of-the-art techniques (e.g. the aes crate uses a technique called fixslicing), and making use of the subtle crate for things like constant-time comparisons. There’s little we can recommend beyond that. A few of our crates do offer random blinding as an option, however that’s as an off-by-default alternative to a constant-time algorithm for the purposes of embedded use and we do not recommend using such techniques except in unusual circumstances.

So WRT RNGs, it would be thrussh’s choice, right?

darleybarreto on July 28, 2021

Recently the Rust Cryptography Interest Group (RCIG) posted a very interesting list about Rust crypto stuff.