Skip to content

Commit 9c25fa2

Browse files
george-hopkinsEugeny
authored andcommitted
Support hashed hostnames in known_hosts file
1 parent d3c4108 commit 9c25fa2

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

russh-keys/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ rand = "0.7"
5252
rand_core = { version = "0.6.4", features = ["std"] }
5353
russh-cryptovec = { version = "0.7.0", path = "../cryptovec" }
5454
serde = { version = "1.0", features = ["derive"] }
55+
sha1 = "0.10"
5556
sha2 = "0.10"
5657
thiserror = "1.0"
5758
tokio = { version = "1.17.0", features = [

russh-keys/src/lib.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ use aes::cipher::block_padding::UnpadError;
7272
use aes::cipher::inout::PadError;
7373
use byteorder::{BigEndian, WriteBytesExt};
7474
use data_encoding::BASE64_MIME;
75+
use hmac::{Hmac, Mac};
7576
use log::debug;
77+
use sha1::Sha1;
7678
use thiserror::Error;
7779

7880
pub mod encoding;
@@ -365,8 +367,7 @@ pub fn check_known_hosts_path<P: AsRef<Path>>(
365367
let key = s.next();
366368
if let (Some(h), Some(k)) = (hosts, key) {
367369
debug!("{:?} {:?}", h, k);
368-
let host_matches = h.split(',').any(|x| x == host_port);
369-
if host_matches {
370+
if match_hostname(&host_port, h) {
370371
if &parse_public_key_base64(k)? == pubkey {
371372
return Ok(true);
372373
} else {
@@ -381,6 +382,28 @@ pub fn check_known_hosts_path<P: AsRef<Path>>(
381382
Ok(false)
382383
}
383384

385+
fn match_hostname(host: &str, pattern: &str) -> bool {
386+
for entry in pattern.split(',') {
387+
if entry.starts_with("|1|") {
388+
let mut parts = entry.split('|').skip(2);
389+
let Some(Ok(salt)) = parts.next().map(|p| BASE64_MIME.decode(p.as_bytes())) else {
390+
continue;
391+
};
392+
let Some(Ok(hash)) = parts.next().map(|p| BASE64_MIME.decode(p.as_bytes())) else {
393+
continue;
394+
};
395+
if let Ok(hmac) = Hmac::<Sha1>::new_from_slice(&salt) {
396+
if hmac.chain_update(host).verify_slice(&hash).is_ok() {
397+
return true;
398+
}
399+
}
400+
} else if host == entry {
401+
return true;
402+
}
403+
}
404+
false
405+
}
406+
384407
/// Record a host's public key into the user's known_hosts file.
385408
#[cfg(target_os = "windows")]
386409
pub fn learn_known_hosts(host: &str, port: u16, pubkey: &key::PublicKey) -> Result<(), Error> {
@@ -526,7 +549,10 @@ QR+u0AypRPmzHnOPAAAAEXJvb3RAMTQwOTExNTQ5NDBkAQ==
526549
let path = dir.path().join("known_hosts");
527550
{
528551
let mut f = File::create(&path).unwrap();
529-
f.write(b"[localhost]:13265 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJdD7y3aLq454yWBdwLWbieU1ebz9/cu7/QEXn9OIeZJ\n#pijul.org,37.120.161.53 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6rWI3G2sz07DnfFlrouTcysQlj2P+jpNSOEWD9OJ3X\npijul.org,37.120.161.53 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6rWI3G1sz07DnfFlrouTcysQlj2P+jpNSOEWD9OJ3X\n").unwrap();
552+
f.write_all(b"[localhost]:13265 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJdD7y3aLq454yWBdwLWbieU1ebz9/cu7/QEXn9OIeZJ\n").unwrap();
553+
f.write_all(b"#pijul.org,37.120.161.53 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6rWI3G2sz07DnfFlrouTcysQlj2P+jpNSOEWD9OJ3X\n").unwrap();
554+
f.write_all(b"pijul.org,37.120.161.53 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA6rWI3G1sz07DnfFlrouTcysQlj2P+jpNSOEWD9OJ3X\n").unwrap();
555+
f.write_all(b"|1|O33ESRMWPVkMYIwJ1Uw+n877jTo=|nuuC5vEqXlEZ/8BXQR7m619W6Ak= ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILIG2T/B0l0gaqj3puu510tu9N1OkQ4znY3LYuEm5zCF\n").unwrap();
530556
}
531557

532558
// Valid key, non-standard port.
@@ -538,6 +564,15 @@ QR+u0AypRPmzHnOPAAAAEXJvb3RAMTQwOTExNTQ5NDBkAQ==
538564
.unwrap();
539565
assert!(check_known_hosts_path(host, port, &hostkey, &path).unwrap());
540566

567+
// Valid key, hashed.
568+
let host = "example.com";
569+
let port = 22;
570+
let hostkey = parse_public_key_base64(
571+
"AAAAC3NzaC1lZDI1NTE5AAAAILIG2T/B0l0gaqj3puu510tu9N1OkQ4znY3LYuEm5zCF",
572+
)
573+
.unwrap();
574+
assert!(check_known_hosts_path(host, port, &hostkey, &path).unwrap());
575+
541576
// Valid key, several hosts, port 22
542577
let host = "pijul.org";
543578
let port = 22;

0 commit comments

Comments
 (0)