New release of Thrussh, including support for agents

Wednesday, December 6, 2017
By Pierre-Étienne Meunier

I’d like to announce a new version of Thrussh, which will hopefully solve a number of problems people have been having with SSH support in Pijul.

We’ve been working on a lot of improvements in Pijul lately, including an upcoming patch format change (with a converter), which simplifies the code a lot, and lots of stability improvements. We’ve actually started to prove our code (manually), function by function.

Another important change, which this post is about, is a new version of Thrussh, bringing major changes:

Moved from *ring* to openssl and libsodium

Since one of the main goals of Thrussh is to provide SSH functionalities in an easy way even in “hostile” environment (such as Windows), we need to be able to read (and maybe write) to a number of file formats, essentially SSH key files. And this is actually one of the main complaints we’re currently getting about Pijul, on all platforms.

Until now, we were using *ring* as our cryptography backend. That project is really ambitious and brilliantly written by Brian Smith and other contributors, but has an explicit policy of not using obsolete crypto. This is really great in most contexts, but it kind of goes against our goal of reading files written using obsolete/nonstandard crypto, such as key files encrypted ten years ago with AES256 in CBC mode, with a key produced by bcrypt (which uses Blowfish itself).

Crypto experts are (rightfully) advocating against each of the names I’ve written in the last sentence, and maybe against using the same key for 10 years, but this kind of stuff is actually quite common.

Another issue we had with *ring* was the lack of support for inspecting keys: indeed, one thing we absolutely needed in order to support SSH agents was the ability to load independent components of an RSA secret key. This isn’t currently possible in *ring*, and the PR I submitted to fix this seems to go against the crate’s policies.

The proliferation of libsodium bindings

There seems to be a proliferation of bindings to libsodium on crates.io. I’m not sure what the reason is, I tried to contribute to one, but my PR was somehow rewritten in a different way without any comment, which led me to bring my contribution to the proliferation and to write thrussh-libsodium.

External contributions will be accepted and discussed.

Support for SSH agent, including actual commands

One thing I like a lot in this release is the support for SSH agents. There is an example in the documentation, which I’m reproducing here:

extern crate thrussh_keys;
extern crate futures;
extern crate tempdir;
extern crate tokio_uds;
extern crate tokio_core;
use thrussh_keys::agent;
use futures::Future;

fn main() {
    let dir = tempdir::TempDir::new("thrussh").unwrap();
    let agent_path = dir.path().join("agent");
    let my_key = {
      let mut f = std::fs::File::open("/home/pe/.ssh/id_ed25519").unwrap();
      let mut s = String::new();
      f.read_to_end(&mut s).unwrap();
      thrussh_keys::decode_secret_key(&s, None).unwrap()
    };

    let mut core = tokio_core::reactor::Core::new().unwrap();

    let h = core.handle();
    let listener = tokio_uds::UnixListener::bind(&agent_path, &h).unwrap().incoming();
    h.spawn(agent::server::AgentServer::new(listener, core.handle(), ()).map_err(|e| eprintln!("{:?}", e)));

    let public = key.clone_public_key();
    let h = core.handle();
    let stream = tokio_uds::UnixStream::connect(&agent_path, &h).unwrap();
    core.run(
        agent::client::AgentClient::connect(stream)
            .add_identity(&key, &[agent::Constraint::KeyLifetime { seconds: 60 }]).and_then(|(client, _)| {
                client.request_identities().and_then(|(client, _id)| {
                    client.sign_request(&public, b"I'd like this to be signed").and_then(|(_, sig)| {
                        sig.unwrap();
                        futures::finished(())
                    })
                })
            })
    ).unwrap();
}

Actually, I went on and started writing an SSH agent to replace the one from OpenSSH, which you can install using:

$ cargo install thrussh-agent

This installs two binaries called thrussh-agent and thrussh-add, which include a subset of what their respective OpenSSH equivalents ssh-agent and ssh-add do.

The only missing features so far are: