From ec3caf2bf7f1909d130c23050c9c0b95cfdaa873 Mon Sep 17 00:00:00 2001 From: Eugene Pankov Date: Fri, 11 Mar 2022 00:55:08 +0100 Subject: [PATCH] thrussh-keys panic cleanup --- README.md | 11 ++++++ cryptovec/src/lib.rs | 6 ++-- thrussh-config/src/lib.rs | 58 ++++++++++++++++-------------- thrussh-config/src/proxy.rs | 28 +++++++++++---- thrussh-keys/src/agent/client.rs | 30 ++++++++++------ thrussh-keys/src/agent/server.rs | 38 +++++++++++--------- thrussh-keys/src/encoding.rs | 20 ++++++++++- thrussh-keys/src/format/mod.rs | 10 +++--- thrussh-keys/src/format/openssh.rs | 12 +++++-- thrussh-keys/src/format/pkcs8.rs | 8 +++-- thrussh-keys/src/lib.rs | 12 +++++-- thrussh-keys/src/signature.rs | 2 ++ 12 files changed, 161 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index fbc525ec..4dd393f9 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,17 @@ A full implementation of the SSH 2 protocol, both server-side and client-side. Thrussh is completely asynchronous, and can be combined with other protocols using [Tokio](//tokio.rs). +## Panics + +`deny(clippy::panic)` except for: + +* When the Rust allocator fails to allocate memory during a CryptoVec being resized. + +## Unsafe code + +* `cryptovec` uses `unsafe` for faster copying, initialization and binding to native API. +* `russh-libsodium` uses `unsafe` for `libsodium` bindings. + ## Contributing We welcome contributions. Currently, the main areas where we need help are: diff --git a/cryptovec/src/lib.rs b/cryptovec/src/lib.rs index 6d6d7854..dd3c5d9c 100644 --- a/cryptovec/src/lib.rs +++ b/cryptovec/src/lib.rs @@ -262,7 +262,9 @@ impl CryptoVec { } if self.p.is_null() { - panic!("Realloc failed, pointer = {:?} {:?}", self, size) + #[allow(clippy::panic)] { + panic!("Realloc failed, pointer = {:?} {:?}", self, size) + } } else { self.capacity = next_capacity; self.size = size; @@ -300,7 +302,7 @@ impl CryptoVec { /// ``` pub fn push_u32_be(&mut self, s: u32) { let s = s.to_be(); - let x: [u8; 4] = unsafe { std::mem::transmute(s) }; + let x: [u8; 4] = s.to_ne_bytes(); self.extend(&x) } diff --git a/thrussh-config/src/lib.rs b/thrussh-config/src/lib.rs index 5a497b6a..fff1ec97 100644 --- a/thrussh-config/src/lib.rs +++ b/thrussh-config/src/lib.rs @@ -1,4 +1,9 @@ -#![deny(clippy::unwrap_used, clippy::expect_used, clippy::indexing_slicing, clippy::panic)] +#![deny( + clippy::unwrap_used, + clippy::expect_used, + clippy::indexing_slicing, + clippy::panic +)] use log::debug; use std::io::Read; use std::net::ToSocketAddrs; @@ -12,11 +17,10 @@ pub enum Error { HostNotFound, #[error("No home directory")] NoHome, - #[error("{}", source)] - Io { - #[from] - source: std::io::Error, - }, + #[error("Cannot resolve the address")] + NotResolvable, + #[error("{}", 0)] + Io(#[from] std::io::Error), } mod proxy; @@ -53,19 +57,19 @@ impl Config { } } - pub async fn stream(&mut self) -> Result { + pub async fn stream(&mut self) -> Result { self.update_proxy_command(); if let Some(ref proxy_command) = self.proxy_command { let cmd: Vec<&str> = proxy_command.split(' ').collect(); - Stream::proxy_command(cmd[0], &cmd[1..]).await + Stream::proxy_command(cmd.get(0).unwrap_or(&""), cmd.get(1..).unwrap_or(&[])) + .await + .map_err(Into::into) } else { - Stream::tcp_connect( - &(self.host_name.as_str(), self.port) - .to_socket_addrs()? - .next() - .unwrap(), - ) - .await + let address = (self.host_name.as_str(), self.port) + .to_socket_addrs()? + .next() + .ok_or(Error::NotResolvable)?; + Stream::tcp_connect(&address).await.map_err(Into::into) } } } @@ -130,7 +134,14 @@ pub fn parse(file: &str, host: &str) -> Result { if id.starts_with("~/") { if let Some(mut home) = dirs_next::home_dir() { home.push(id.split_at(2).1); - config.identity_file = Some(home.to_str().unwrap().to_string()); + config.identity_file = Some( + home.to_str() + .ok_or_else(|| std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to convert home directory to string", + ))? + .to_string(), + ); } else { return Err(Error::NoHome); } @@ -149,17 +160,10 @@ pub fn parse(file: &str, host: &str) -> Result { debug!("{:?}", key); } } - } else { - match lower.as_str() { - "host" => { - if value.trim_start() == host { - let mut c = Config::default(host); - c.port = 22; - config = Some(c) - } - } - _ => {} - } + } else if lower.as_str() == "host" && value.trim_start() == host { + let mut c = Config::default(host); + c.port = 22; + config = Some(c) } } } diff --git a/thrussh-config/src/proxy.rs b/thrussh-config/src/proxy.rs index 54cc18c1..acb9ac6c 100644 --- a/thrussh-config/src/proxy.rs +++ b/thrussh-config/src/proxy.rs @@ -27,8 +27,7 @@ impl Stream { .stdin(Stdio::piped()) .stdout(Stdio::piped()) .args(args) - .spawn() - .unwrap(), + .spawn()? )) } } @@ -40,7 +39,12 @@ impl tokio::io::AsyncRead for Stream { buf: &mut ReadBuf, ) -> Poll> { match *self { - Stream::Child(ref mut c) => Pin::new(c.stdout.as_mut().unwrap()).poll_read(cx, buf), + Stream::Child(ref mut c) => { + match c.stdout.as_mut() { + Some(ref mut stdout) => Pin::new(stdout).poll_read(cx, buf), + None => Poll::Ready(Ok(())) + } + }, Stream::Tcp(ref mut t) => Pin::new(t).poll_read(cx, buf), } } @@ -53,14 +57,24 @@ impl tokio::io::AsyncWrite for Stream { buf: &[u8], ) -> Poll> { match *self { - Stream::Child(ref mut c) => Pin::new(c.stdin.as_mut().unwrap()).poll_write(cx, buf), + Stream::Child(ref mut c) => { + match c.stdin.as_mut() { + Some(ref mut stdin) => Pin::new(stdin).poll_write(cx, buf), + None => Poll::Ready(Ok(0)) + } + }, Stream::Tcp(ref mut t) => Pin::new(t).poll_write(cx, buf), } } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { match *self { - Stream::Child(ref mut c) => Pin::new(c.stdin.as_mut().unwrap()).poll_flush(cx), + Stream::Child(ref mut c) => { + match c.stdin.as_mut() { + Some(ref mut stdin) => Pin::new(stdin).poll_flush(cx), + None => Poll::Ready(Ok(())) + } + }, Stream::Tcp(ref mut t) => Pin::new(t).poll_flush(cx), } } @@ -71,7 +85,9 @@ impl tokio::io::AsyncWrite for Stream { ) -> Poll> { match *self { Stream::Child(ref mut c) => { - ready!(Pin::new(c.stdin.as_mut().unwrap()).poll_shutdown(cx))?; + if let Some(ref mut stdin) = c.stdin { + ready!(Pin::new(stdin).poll_shutdown(cx))?; + } drop(c.stdin.take()); Poll::Ready(Ok(())) } diff --git a/thrussh-keys/src/agent/client.rs b/thrussh-keys/src/agent/client.rs index fe643ce5..601e2844 100644 --- a/thrussh-keys/src/agent/client.rs +++ b/thrussh-keys/src/agent/client.rs @@ -190,7 +190,7 @@ impl AgentClient { } } let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -202,7 +202,7 @@ impl AgentClient { self.buf.push(msg::LOCK); self.buf.extend_ssh_string(passphrase); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -214,7 +214,8 @@ impl AgentClient { self.buf.push(msg::UNLOCK); self.buf.extend_ssh_string(passphrase); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + #[allow(clippy::indexing_slicing)] // static length + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -226,11 +227,13 @@ impl AgentClient { self.buf.resize(4); self.buf.push(msg::REQUEST_IDENTITIES); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; debug!("identities: {:?}", &self.buf[..]); let mut keys = Vec::new(); + + #[allow(clippy::indexing_slicing)] // static length if self.buf[0] == msg::IDENTITIES_ANSWER { let mut r = self.buf.reader(1); let n = r.read_u32()?; @@ -286,13 +289,14 @@ impl AgentClient { return (self, Err(e)); } + #[allow(clippy::indexing_slicing)] // length is checked if !self.buf.is_empty() && self.buf[0] == msg::SIGN_RESPONSE { let resp = self.write_signature(hash, &mut data); if let Err(e) = resp { return (self, Err(e)); } (self, Ok(data)) - } else if self.buf[0] == msg::FAILURE { + } else if self.buf.get(0) == Some(&msg::FAILURE) { (self, Err(Error::AgentFailure)) } else { debug!("self.buf = {:?}", &self.buf[..]); @@ -319,7 +323,7 @@ impl AgentClient { }; self.buf.push_u32_be(hash); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); hash } @@ -350,6 +354,7 @@ impl AgentClient { return (self, Err(e)); } + #[allow(clippy::indexing_slicing)] // length is checked if !self.buf.is_empty() && self.buf[0] == msg::SIGN_RESPONSE { let base64 = data_encoding::BASE64_NOPAD.encode(&self.buf[1..]); (self, Ok(base64)) @@ -372,6 +377,7 @@ impl AgentClient { if let Err(e) = self.read_response().await { return (self, Err(e)); } + #[allow(clippy::indexing_slicing)] // length is checked if !self.buf.is_empty() && self.buf[0] == msg::SIGN_RESPONSE { let as_sig = |buf: &CryptoVec| -> Result { let mut r = buf.reader(1); @@ -415,7 +421,7 @@ impl AgentClient { self.buf.push(msg::REMOVE_IDENTITY); key_blob(public, &mut self.buf); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -428,7 +434,7 @@ impl AgentClient { self.buf.extend_ssh_string(id.as_bytes()); self.buf.extend_ssh_string(pin); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -438,7 +444,7 @@ impl AgentClient { self.buf.clear(); self.buf.resize(4); self.buf.push(msg::REMOVE_ALL_IDENTITIES); - BigEndian::write_u32(&mut self.buf[0..], 5); + BigEndian::write_u32(&mut self.buf[..], 5); self.read_response().await?; Ok(()) } @@ -451,7 +457,7 @@ impl AgentClient { self.buf.extend_ssh_string(typ); self.buf.extend_ssh_string(ext); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; Ok(()) } @@ -463,12 +469,13 @@ impl AgentClient { self.buf.push(msg::EXTENSION); self.buf.extend_ssh_string(typ); let len = self.buf.len() - 4; - BigEndian::write_u32(&mut self.buf[0..], len as u32); + BigEndian::write_u32(&mut self.buf[..], len as u32); self.read_response().await?; let mut r = self.buf.reader(1); ext.extend(r.read_string()?); + #[allow(clippy::indexing_slicing)] // length is checked Ok(!self.buf.is_empty() && self.buf[0] == msg::SUCCESS) } } @@ -492,6 +499,7 @@ fn key_blob(public: &key::PublicKey, buf: &mut CryptoVec) { buf.extend_ssh_string(b"ssh-ed25519"); buf.extend_ssh_string(&p.key[0..]); let len1 = buf.len(); + #[allow(clippy::indexing_slicing)] // length is known BigEndian::write_u32(&mut buf[5..], (len1 - len0) as u32); } } diff --git a/thrussh-keys/src/agent/server.rs b/thrussh-keys/src/agent/server.rs index 1d0c23cf..87d1ec57 100644 --- a/thrussh-keys/src/agent/server.rs +++ b/thrussh-keys/src/agent/server.rs @@ -20,6 +20,7 @@ use super::Constraint; use crate::Error; #[derive(Clone)] +#[allow(clippy::type_complexity)] struct KeyStore(Arc, (Arc, SystemTime, Vec)>>>); #[derive(Clone)] @@ -132,7 +133,7 @@ impl { // sign request - let agent = self.agent.take().unwrap(); + let agent = self.agent.take().ok_or(Error::AgentFailure)?; let (agent, signed) = self.try_sign(agent, r, writebuf).await?; self.agent = Some(agent); if signed { @@ -195,21 +196,21 @@ impl Result<(), Error> { let password = r.read_string()?; - let mut lock = self.lock.0.write().unwrap(); + let mut lock = self.lock.0.write().or(Err(Error::AgentFailure))?; lock.extend(password); Ok(()) } fn unlock(&self, mut r: Position) -> Result { let password = r.read_string()?; - let mut lock = self.lock.0.write().unwrap(); - if &lock[0..] == password { + let mut lock = self.lock.0.write().or(Err(Error::AgentFailure))?; + if &lock[..] == password { lock.clear(); Ok(true) } else { @@ -243,15 +244,19 @@ impl return Ok(false), }; - let mut w = self.keys.0.write().unwrap(); + let mut w = self.keys.0.write().or(Err(Error::AgentFailure))?; let now = SystemTime::now(); if constrained { let n = r.read_u32()?; @@ -318,14 +323,15 @@ impl usize { let mut i = 0; while i < s.len() && s[i] == 0 { @@ -52,16 +53,23 @@ pub fn mpint_len(s: &[u8]) -> usize { } impl Encoding for Vec { + #[allow(clippy::unwrap_used)] // writing into Vec<> can't panic fn extend_ssh_string(&mut self, s: &[u8]) { self.write_u32::(s.len() as u32).unwrap(); self.extend(s); } + + #[allow(clippy::unwrap_used)] // writing into Vec<> can't panic fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] { self.write_u32::(len as u32).unwrap(); let current = self.len(); self.resize(current + len, 0u8); + #[allow(clippy::indexing_slicing)] // length is known &mut self[current..] } + + #[allow(clippy::unwrap_used)] // writing into Vec<> can't panic + #[allow(clippy::indexing_slicing)] // length is known fn extend_ssh_mpint(&mut self, s: &[u8]) { // Skip initial 0s. let mut i = 0; @@ -79,6 +87,7 @@ impl Encoding for Vec { self.extend(&s[i..]); } + #[allow(clippy::indexing_slicing)] // length is known fn extend_list>(&mut self, list: I) { let len0 = self.len(); self.extend(&[0, 0, 0, 0]); @@ -106,12 +115,16 @@ impl Encoding for CryptoVec { self.push_u32_be(s.len() as u32); self.extend(s); } + + #[allow(clippy::indexing_slicing)] // length is known fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] { self.push_u32_be(len as u32); let current = self.len(); self.resize(current + len); &mut self[current..] } + + #[allow(clippy::indexing_slicing)] // length is known fn extend_ssh_mpint(&mut self, s: &[u8]) { // Skip initial 0s. let mut i = 0; @@ -142,6 +155,7 @@ impl Encoding for CryptoVec { } let len = (self.len() - len0 - 4) as u32; + #[allow(clippy::indexing_slicing)] // length is known BigEndian::write_u32(&mut self[len0..], len); } @@ -159,7 +173,7 @@ pub trait Reader { impl Reader for CryptoVec { fn reader(&self, starting_at: usize) -> Position { Position { - s: &self, + s: self, position: starting_at, } } @@ -186,6 +200,7 @@ impl<'a> Position<'a> { pub fn read_string(&mut self) -> Result<&'a [u8], Error> { let len = self.read_u32()? as usize; if self.position + len <= self.s.len() { + #[allow(clippy::indexing_slicing)] // length is known let result = &self.s[self.position..(self.position + len)]; self.position += len; Ok(result) @@ -196,6 +211,7 @@ impl<'a> Position<'a> { /// Read a `u32` from this reader. pub fn read_u32(&mut self) -> Result { if self.position + 4 <= self.s.len() { + #[allow(clippy::indexing_slicing)] // length is known let u = BigEndian::read_u32(&self.s[self.position..]); self.position += 4; Ok(u) @@ -206,6 +222,7 @@ impl<'a> Position<'a> { /// Read one byte from this reader. pub fn read_byte(&mut self) -> Result { if self.position < self.s.len() { + #[allow(clippy::indexing_slicing)] // length is known let u = self.s[self.position]; self.position += 1; Ok(u) @@ -218,6 +235,7 @@ impl<'a> Position<'a> { pub fn read_mpint(&mut self) -> Result<&'a [u8], Error> { let len = self.read_u32()? as usize; if self.position + len <= self.s.len() { + #[allow(clippy::indexing_slicing)] // length was checked let result = &self.s[self.position..(self.position + len)]; self.position += len; Ok(result) diff --git a/thrussh-keys/src/format/mod.rs b/thrussh-keys/src/format/mod.rs index 79f7845c..64b606a4 100644 --- a/thrussh-keys/src/format/mod.rs +++ b/thrussh-keys/src/format/mod.rs @@ -136,12 +136,12 @@ fn decode_rsa(secret: &[u8]) -> Result { fn pkcs_unpad(dec: &mut Vec) { let len = dec.len(); if len > 0 { + #[allow(clippy::indexing_slicing)] let padding_len = dec[len - 1]; - if dec[(len - padding_len as usize)..] - .iter() - .all(|&x| x == padding_len) - { - dec.truncate(len - padding_len as usize) + if let Some(s) = dec.get((len - padding_len as usize)..) { + if s.iter().all(|&x| x == padding_len) { + dec.truncate(len - padding_len as usize) + } } } } diff --git a/thrussh-keys/src/format/openssh.rs b/thrussh-keys/src/format/openssh.rs index 57f61d1a..9d7b72bb 100644 --- a/thrussh-keys/src/format/openssh.rs +++ b/thrussh-keys/src/format/openssh.rs @@ -8,7 +8,7 @@ use openssl::bn::BigNum; /// Decode a secret key given in the OpenSSH format, deciphering it if /// needed using the supplied password. pub fn decode_openssh(secret: &[u8], password: Option<&str>) -> Result { - if &secret[0..15] == b"openssh-key-v1\0" { + if matches!(secret.get(0..15), Some(b"openssh-key-v1\0")) { let mut position = secret.reader(15); let ciphername = position.read_string()?; @@ -35,7 +35,9 @@ pub fn decode_openssh(secret: &[u8], password: Option<&str>) -> Result { @@ -125,21 +129,25 @@ fn decrypt_secret_key( use block_modes::BlockMode; match ciphername { b"aes128-cbc" => { + #[allow(clippy::unwrap_used)] // parameters are static let cipher = Aes128Cbc::new_from_slices(key, iv).unwrap(); let n = cipher.decrypt(&mut dec)?.len(); dec.truncate(n) } b"aes256-cbc" => { + #[allow(clippy::unwrap_used)] // parameters are static let cipher = Aes256Cbc::new_from_slices(key, iv).unwrap(); let n = cipher.decrypt(&mut dec)?.len(); dec.truncate(n) } b"aes128-ctr" => { + #[allow(clippy::unwrap_used)] // parameters are static let mut cipher = Aes128Ctr::new_from_slices(key, iv).unwrap(); cipher.apply_keystream(&mut dec); dec.truncate(secret_key.len()) } b"aes256-ctr" => { + #[allow(clippy::unwrap_used)] // parameters are static let mut cipher = Aes256Ctr::new_from_slices(key, iv).unwrap(); cipher.apply_keystream(&mut dec); dec.truncate(secret_key.len()) diff --git a/thrussh-keys/src/format/pkcs8.rs b/thrussh-keys/src/format/pkcs8.rs index 61dfbd94..e5cff304 100644 --- a/thrussh-keys/src/format/pkcs8.rs +++ b/thrussh-keys/src/format/pkcs8.rs @@ -243,7 +243,7 @@ fn read_key_v0(reader: &mut BERReaderSeq) -> Result { #[cfg(not(feature = "openssl"))] fn read_key_v0(_: &mut BERReaderSeq) -> Result { - Err(Error::CouldNotReadKey.into()) + Err(Error::CouldNotReadKey) } #[test] @@ -287,9 +287,10 @@ pub fn encode_pkcs8_encrypted( let padding_len = 32 - (plaintext.len() % 32); plaintext.extend(std::iter::repeat(padding_len as u8).take(padding_len)); + #[allow(clippy::unwrap_used)] // parameters are static let c = Aes256Cbc::new_from_slices(&dkey, &iv).unwrap(); let n = plaintext.len(); - c.encrypt(&mut plaintext, n).unwrap(); + c.encrypt(&mut plaintext, n)?; Ok(yasna::construct_der(|writer| { writer.write_sequence(|writer| { @@ -317,6 +318,7 @@ pub fn encode_pkcs8(key: &key::KeyPair) -> Vec { }) } +#[allow(clippy::indexing_slicing)] fn clone(src: &[u8], dest: &mut [u8]) { let i = src.iter().take_while(|b| **b == 0).count(); let src = &src[i..]; @@ -424,6 +426,7 @@ impl Encryption { fn decrypt(&self, key: &[u8], ciphertext: &[u8]) -> Result, Error> { match *self { Encryption::Aes128Cbc(ref iv) => { + #[allow(clippy::unwrap_used)] // parameters are static let c = Aes128Cbc::new_from_slices(key, iv).unwrap(); let mut dec = ciphertext.to_vec(); c.decrypt(&mut dec)?; @@ -431,6 +434,7 @@ impl Encryption { Ok(dec) }, Encryption::Aes256Cbc(ref iv) => { + #[allow(clippy::unwrap_used)] // parameters are static let c = Aes256Cbc::new_from_slices(key, iv).unwrap(); let mut dec = ciphertext.to_vec(); c.decrypt(&mut dec)?; diff --git a/thrussh-keys/src/lib.rs b/thrussh-keys/src/lib.rs index a8e67ff0..bc0ec5d9 100644 --- a/thrussh-keys/src/lib.rs +++ b/thrussh-keys/src/lib.rs @@ -92,6 +92,9 @@ pub enum Error { /// The key is encrypted (should supply a password?) #[error("The key is encrypted")] KeyIsEncrypted, + /// The key contents are inconsistent + #[error("The key is corrupt")] + KeyIsCorrupt, /// Home directory could not be found #[error("No home directory found")] NoHomeDir, @@ -189,8 +192,10 @@ impl PublicKeyBase64 for key::PublicKey { match *self { key::PublicKey::Ed25519(ref publickey) => { let name = b"ssh-ed25519"; + #[allow(clippy::unwrap_used)] // Vec<>.write can't fail s.write_u32::(name.len() as u32).unwrap(); s.extend_from_slice(name); + #[allow(clippy::unwrap_used)] // Vec<>.write can't fail s.write_u32::(publickey.key.len() as u32) .unwrap(); s.extend_from_slice(&publickey.key); @@ -199,6 +204,7 @@ impl PublicKeyBase64 for key::PublicKey { key::PublicKey::RSA { ref key, .. } => { use encoding::Encoding; let name = b"ssh-rsa"; + #[allow(clippy::unwrap_used)] // Vec<>.write_all can't fail s.write_u32::(name.len() as u32).unwrap(); s.extend_from_slice(name); s.extend_ssh_mpint(&key.0.rsa().unwrap().e().to_vec()); @@ -213,11 +219,13 @@ impl PublicKeyBase64 for key::KeyPair { fn public_key_bytes(&self) -> Vec { let name = self.name().as_bytes(); let mut s = Vec::new(); + #[allow(clippy::unwrap_used)] // Vec<>.write_all can't fail s.write_u32::(name.len() as u32).unwrap(); s.extend_from_slice(name); match *self { key::KeyPair::Ed25519(ref key) => { let public = &key.key[32..]; + #[allow(clippy::unwrap_used)] // Vec<>.write can't fail s.write_u32::(32).unwrap(); s.extend_from_slice(public); } @@ -323,9 +331,9 @@ pub fn check_known_hosts_path>( }; debug!("host_port = {:?}", host_port); let mut line = 1; - while f.read_line(&mut buffer).unwrap() > 0 { + while f.read_line(&mut buffer)? > 0 { { - if buffer.as_bytes()[0] == b'#' { + if buffer.as_bytes().get(0) == Some(&b'#') { buffer.clear(); continue; } diff --git a/thrussh-keys/src/signature.rs b/thrussh-keys/src/signature.rs index df9293c2..f37d781e 100644 --- a/thrussh-keys/src/signature.rs +++ b/thrussh-keys/src/signature.rs @@ -25,6 +25,7 @@ impl Signature { match self { Signature::Ed25519(ref bytes) => { let t = b"ssh-ed25519"; + #[allow(clippy::unwrap_used)] // Vec<>.write_all can't fail bytes_ .write_u32::((t.len() + bytes.0.len() + 8) as u32) .unwrap(); @@ -40,6 +41,7 @@ impl Signature { SignatureHash::SHA2_512 => &b"rsa-sha2-512"[..], SignatureHash::SHA1 => &b"ssh-rsa"[..], }; + #[allow(clippy::unwrap_used)] // Vec<>.write_all can't fail bytes_ .write_u32::((t.len() + bytes.len() + 8) as u32) .unwrap();