From 650718d3e73bad7e1a569377c0ed00798c6458d6 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Skutnik Date: Fri, 7 Jun 2024 21:15:16 +0300 Subject: [PATCH 1/2] Overachiever host key checking --- russh-keys/src/lib.rs | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/russh-keys/src/lib.rs b/russh-keys/src/lib.rs index 8d11228b..c615fdb3 100644 --- a/russh-keys/src/lib.rs +++ b/russh-keys/src/lib.rs @@ -389,7 +389,7 @@ pub fn learn_known_hosts_path>( } /// Get the server key that matches the one recorded in the user's known_hosts file. -pub fn known_host_key(host: &str, port: u16) -> Result, Error> { +pub fn known_host_key(host: &str, port: u16) -> Result, Error> { known_host_key_path(host, port, known_hosts_path()?) } @@ -398,11 +398,11 @@ pub fn known_host_key_path>( host: &str, port: u16, path: P, -) -> Result, Error> { +) -> Result, Error> { let mut f = if let Ok(f) = File::open(path) { BufReader::new(f) } else { - return Ok(None); + return Ok(vec![]); }; let mut buffer = String::new(); @@ -413,6 +413,7 @@ pub fn known_host_key_path>( }; debug!("host_port = {:?}", host_port); let mut line = 1; + let mut matches = vec![]; while f.read_line(&mut buffer)? > 0 { { if buffer.as_bytes().first() == Some(&b'#') { @@ -427,14 +428,14 @@ pub fn known_host_key_path>( if let (Some(h), Some(k)) = (hosts, key) { debug!("{:?} {:?}", h, k); if match_hostname(&host_port, h) { - return Ok(Some((line, parse_public_key_base64(k)?))); + matches.push((line, parse_public_key_base64(k)?)); } } } buffer.clear(); line += 1; } - Ok(None) + Ok(matches) } fn match_hostname(host: &str, pattern: &str) -> bool { @@ -471,15 +472,22 @@ pub fn check_known_hosts_path>( pubkey: &key::PublicKey, path: P, ) -> Result { - if let Some((line, recorded)) = known_host_key_path(host, port, path)? { - if recorded == *pubkey { - Ok(true) - } else { - Err(Error::KeyChanged { line }) - } - } else { - Ok(false) - } + let check = known_host_key_path(host, port, path)? + .into_iter() + .map( + |(line, recorded)| match (pubkey.name() == recorded.name(), *pubkey == recorded) { + (true, true) => Ok(true), + (true, false) => Err(Error::KeyChanged { line }), + _ => Ok(false), + }, + ) + // If any Err was returned, we stop here + .collect::, Error>>()? + .into_iter() + // Now we check the results for a match + .any(|x| x); + + Ok(check) } #[cfg(target_os = "windows")] From 70bdea7c1eeae0c2dac52163da81de67d6164834 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Skutnik Date: Sat, 8 Jun 2024 08:35:00 +0300 Subject: [PATCH 2/2] Rename methods --- russh-keys/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/russh-keys/src/lib.rs b/russh-keys/src/lib.rs index c615fdb3..6cef7a1e 100644 --- a/russh-keys/src/lib.rs +++ b/russh-keys/src/lib.rs @@ -389,12 +389,12 @@ pub fn learn_known_hosts_path>( } /// Get the server key that matches the one recorded in the user's known_hosts file. -pub fn known_host_key(host: &str, port: u16) -> Result, Error> { - known_host_key_path(host, port, known_hosts_path()?) +pub fn known_host_keys(host: &str, port: u16) -> Result, Error> { + known_host_keys_path(host, port, known_hosts_path()?) } /// Get the server key that matches the one recorded in `path`. -pub fn known_host_key_path>( +pub fn known_host_keys_path>( host: &str, port: u16, path: P, @@ -472,7 +472,7 @@ pub fn check_known_hosts_path>( pubkey: &key::PublicKey, path: P, ) -> Result { - let check = known_host_key_path(host, port, path)? + let check = known_host_keys_path(host, port, path)? .into_iter() .map( |(line, recorded)| match (pubkey.name() == recorded.name(), *pubkey == recorded) {