Pure-Rust asynchronous SSH library, both client and server

#47 Generic Agents

Opened by fintohaps on August 16, 2021
fintohaps on August 16, 2021

As mentioned in https://nest.pijul.com/pijul/thrussh/discussions/46, the need for a generic key in radicle-keystore#17 is only needed for the client.

I explored this route by making PublicKey and KeyPair generic in the client.rs file. The goal was then to move that code away from thrussh-keys. To do this, I decided to create two separate crates thrussh-agent and thrussh-encoding. The latter is so that other packages that don’t want to rely on thrussh-keys can use the encoding helpers defined in the encoding.rs file.

thrussh-agent houses only the agent code, i.e. client.rs and server.rs. Any need for a key is handled by a set of traits defined in key.rs. These traits are:

pub trait Signature: Sized {
    type Error;

    fn read(buf: &CryptoVec) -> Result<Self, Self::Error>;
}

pub trait Public: Sized {
    type Error;

    fn write_blob(&self, buf: &mut CryptoVec);
    fn read(reader: &mut Position) -> Result<Option<Self>, Self::Error>;
    fn hash(&self) -> u32;
}

pub trait Private: Sized {
    type Error;

    fn read(reader: &mut Position) -> Result<Option<(Vec<u8>, Self)>, Self::Error>;
    fn write(&self, buf: &mut CryptoVec) -> Result<(), Self::Error>;
    fn write_signature<Bytes: AsRef<[u8]>>(
        &self,
        buf: &mut CryptoVec,
        to_sign: Bytes,
    ) -> Result<(), Self::Error>;
}

The thrussh-keys package depends on thrussh-agent to have implementations of those traits for KeyPair and PublicKey.

This was the most straightforward way to separate out the logic. We had discussed privately the option of thrussh-keys defining traits and having packages such as thrussh-libsodium and thrussh-openssl define keys and implement the traits. However, this ripped through all of thrussh-keys and thrussh and became slightly unmanageable for me to implement. I was lacking enough knowledge and confidence to make these changes without worrying about complete breakage.

I do think this separation could be a good stepping stone towards that implementing the above though. Where we could eventually move the traits to thrussh-keys, thrussh could then be made generic over the keys and would have dependencies on thrussh-agent and thrussh-keys. Then the end-user could pick their key crate du jour. That would fit the auditing vision better too, because then the key logic is audited in each package, while the protocol logic is done via thrussh-agent and thrussh.

I’ll submit the patches once I’ve cleaned up the messages :) I’ll also be submitted a draft patch to radicle-keystore showing the signing example working there.

fintohaps on August 16, 2021

Here’s the corresponding intergation work https://github.com/radicle-dev/radicle-keystore/pull/18

fintohaps on August 19, 2021

I’m also including a patch for being generic on the runtime :)

fintohaps on September 8, 2021

@pmeunier any chance you were able to look at these patches? Anything I could do to help the review?