Pure-Rust asynchronous SSH library, both client and server

#48 How can I reliably get public key data from remote servers?

Opened by mrled on August 22, 2021
mrled on August 22, 2021

Hi, I’m new to Rust and thrussh, and I have some questions.

  1. What I’m ultimately trying to do is retrieve a remote server’s public key data. I see the check_server_key callback in the client handler, but that doesn’t return the server keys back to my code. It also seems to only get called once, even though some servers might offer more than one key (for example an RSA and an ED25519 key). Is there a way for me to get what I want - data for all public keys returned to my code?

  2. In the course of testing, I discovered an anomaly when trying to connect to github.com via ssh - check_server_key doesn’t seem to get called at all for that host. However, ssh.pijul.com and all the SSH hosts I have at home, check_server_key gets called as expected. Am I doing something wrong here? How can I get public keys for GitHub as well? (See sample code below.)

Let me know if it would be helpful to see these as separate discussion topics. I’m a rust noob so I figure there’s a good chance I’m missing something and I didn’t want to spam ya’ll if this is all on my end.

Sample code:

use std::sync::Arc;
use thrussh::client::{Handler, Session};
use thrussh_keys::key::PublicKey;

struct TinyClient {}

impl Handler for TinyClient {
    type Error = anyhow::Error;
    type FutureUnit = futures::future::Ready>;
    type FutureBool = futures::future::Ready>;

    fn finished_bool(self, b: bool) -> Self::FutureBool {
        futures::future::ready(Ok((self, b)))
    }
    fn finished(self, session: Session) -> Self::FutureUnit {
        futures::future::ready(Ok((self, session)))
    }
    fn check_server_key(self, server_public_key: &PublicKey) -> Self::FutureBool {
        println!("check_server_key: {:?}", server_public_key);
        self.finished_bool(true)
    }
}

#[tokio::main]
async fn main() {
    let config = Arc::new(thrussh::client::Config::default());
    let handlec = TinyClient {};

    let _session = thrussh::client::connect(config, "ssh.pijul.com:22", handlec)
        .await
        .unwrap();
}

When I run the code exactly as it is recorded above, with ssh.pijul.com:22 as my SSH host, it does print the host’s public key data as expected:

> cargo run
Compiling mrltesting v0.1.0 (/Users/mrled/Documents/Repositories/mrltesting.rs)
    Finished dev [unoptimized + debuginfo] target(s) in 1.50s
    Running `target/debug/mrltesting`
check_server_key: Ed25519(PublicKey { key: [43, 253, 233, 249, 203, 95, 39, 146, 159, 62, 30, 8, 42, 80, 86, 116, 156, 223, 190, 193, 26, 156, 226, 210, 129, 17, 230, 111, 183, 124, 12, 4] })

However, when I hard code the SSH host as github.com:22 instead, it prints nothing at all:

> cargo run
Compiling mrltesting v0.1.0 (/Users/mrled/Documents/Repositories/mrltesting.rs)
    Finished dev [unoptimized + debuginfo] target(s) in 1.32s
    Running `target/debug/mrltesting`