ssh: Remove dependency on byteorder

This commit is contained in:
Lorenz Leutgeb 2025-07-15 22:46:44 +02:00
parent 95b3303eb9
commit 8e6279a382
4 changed files with 29 additions and 28 deletions

1
Cargo.lock generated
View File

@ -2749,7 +2749,6 @@ dependencies = [
name = "radicle-ssh" name = "radicle-ssh"
version = "0.9.0" version = "0.9.0"
dependencies = [ dependencies = [
"byteorder",
"log", "log",
"thiserror 1.0.69", "thiserror 1.0.69",
"winpipe", "winpipe",

View File

@ -14,10 +14,9 @@ edition.workspace = true
rust-version.workspace = true rust-version.workspace = true
[dependencies] [dependencies]
byteorder = "1.4"
log = { workspace = true } log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
zeroize = { workspace = true } zeroize = { workspace = true }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winpipe = { workspace = true } winpipe = { workspace = true }

View File

@ -1,6 +1,5 @@
use std::fmt; use std::fmt;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::ops::DerefMut;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
#[cfg(unix)] #[cfg(unix)]
@ -9,7 +8,6 @@ pub use std::os::unix::net::UnixStream as Stream;
#[cfg(windows)] #[cfg(windows)]
pub use winpipe::WinStream as Stream; pub use winpipe::WinStream as Stream;
use byteorder::{BigEndian, ByteOrder as _, WriteBytesExt};
use log::*; use log::*;
use thiserror::Error; use thiserror::Error;
use zeroize::Zeroize as _; use zeroize::Zeroize as _;
@ -145,7 +143,7 @@ impl<Stream: ClientStream> AgentClient<Stream> {
match *cons { match *cons {
Constraint::KeyLifetime { seconds } => { Constraint::KeyLifetime { seconds } => {
buf.push(msg::CONSTRAIN_LIFETIME); buf.push(msg::CONSTRAIN_LIFETIME);
buf.deref_mut().write_u32::<BigEndian>(seconds)? buf.extend_u32(seconds);
} }
Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM), Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM),
Constraint::Extensions { Constraint::Extensions {
@ -186,13 +184,12 @@ impl<Stream: ClientStream> AgentClient<Stream> {
buf.extend_ssh_string(pin); buf.extend_ssh_string(pin);
if !constraints.is_empty() { if !constraints.is_empty() {
buf.deref_mut() buf.extend_usize(constraints.len());
.write_u32::<BigEndian>(constraints.len() as u32)?;
for cons in constraints { for cons in constraints {
match *cons { match *cons {
Constraint::KeyLifetime { seconds } => { Constraint::KeyLifetime { seconds } => {
buf.push(msg::CONSTRAIN_LIFETIME); buf.push(msg::CONSTRAIN_LIFETIME);
buf.deref_mut().write_u32::<BigEndian>(seconds)?; buf.extend_u32(seconds);
} }
Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM), Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM),
Constraint::Extensions { Constraint::Extensions {
@ -304,14 +301,13 @@ impl<Stream: ClientStream> AgentClient<Stream> {
let total = 1 + pk.len() + 4 + data.len() + 4; let total = 1 + pk.len() + 4 + data.len() + 4;
let mut buf = Buffer::default(); let mut buf = Buffer::default();
buf.write_u32::<BigEndian>(total as u32) buf.extend_usize(total);
.expect("Writing to a vector never fails");
buf.push(msg::SIGN_REQUEST); buf.push(msg::SIGN_REQUEST);
buf.extend_from_slice(&pk); buf.extend_from_slice(&pk);
buf.extend_ssh_string(data); buf.extend_ssh_string(data);
// Signature flags should be zero for ed25519. // Signature flags should be zero for ed25519.
buf.write_u32::<BigEndian>(0).unwrap(); buf.extend_u32(0);
buf buf
} }
@ -338,7 +334,7 @@ impl<Stream: ClientStream> AgentClient<Stream> {
let total = 1 + pk.len(); let total = 1 + pk.len();
let mut buf = Buffer::default(); let mut buf = Buffer::default();
buf.write_u32::<BigEndian>(total as u32)?; buf.extend_usize(total);
buf.push(msg::REMOVE_IDENTITY); buf.push(msg::REMOVE_IDENTITY);
buf.extend_from_slice(&pk); buf.extend_from_slice(&pk);
@ -422,7 +418,8 @@ impl<S: Read + Write + Sized + Send + Sync> ClientStream for S {
self.read_exact(&mut resp)?; self.read_exact(&mut resp)?;
// Read the rest of the buffer // Read the rest of the buffer
let len = BigEndian::read_u32(&resp) as usize; let len = u32::from_be_bytes(resp.as_slice().try_into().unwrap()) as usize;
resp.zeroize(); resp.zeroize();
resp.resize(len, 0); resp.resize(len, 0);
self.read_exact(&mut resp)?; self.read_exact(&mut resp)?;

View File

@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
use std::ops::DerefMut; use std::ops::DerefMut as _;
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use thiserror::Error; use thiserror::Error;
use zeroize::Zeroizing; use zeroize::Zeroizing;
@ -53,6 +52,16 @@ pub trait Encoding {
fn write_empty_list(&mut self); fn write_empty_list(&mut self);
/// Write the buffer length at the beginning of the buffer. /// Write the buffer length at the beginning of the buffer.
fn write_len(&mut self); fn write_len(&mut self);
/// Push a [`usize`] as an SSH-encoded unsiged 32-bit integer.
/// May panic if the argument is greater than [`u32::MAX`].
/// This is a convience method, to spare callers casting or converting
/// [`usize`] to [`u32`]. If callers end up in a situation where they
/// need to push a 32-bit unisgned integer, but the value they would
/// like to push does not fit 32 bits, then the implementation will not
/// comply with the SSH format anyway.
fn extend_usize(&mut self, u: usize) {
self.extend_u32(u.try_into().unwrap())
}
} }
/// Encoding length of the given mpint. /// Encoding length of the given mpint.
@ -66,12 +75,12 @@ pub fn mpint_len(s: &[u8]) -> usize {
impl Encoding for Vec<u8> { impl Encoding for Vec<u8> {
fn extend_ssh_string(&mut self, s: &[u8]) { fn extend_ssh_string(&mut self, s: &[u8]) {
self.write_u32::<BigEndian>(s.len() as u32).unwrap(); self.extend_usize(s.len());
self.extend(s); self.extend(s);
} }
fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] { fn extend_ssh_string_blank(&mut self, len: usize) -> &mut [u8] {
self.write_u32::<BigEndian>(len as u32).unwrap(); self.extend_usize(len);
let current = self.len(); let current = self.len();
self.resize(current + len, 0u8); self.resize(current + len, 0u8);
@ -86,24 +95,20 @@ impl Encoding for Vec<u8> {
} }
// If the first non-zero is >= 128, write its length (u32, BE), followed by 0. // If the first non-zero is >= 128, write its length (u32, BE), followed by 0.
if s[i] & 0x80 != 0 { if s[i] & 0x80 != 0 {
self.write_u32::<BigEndian>((s.len() - i + 1) as u32) self.extend_usize(s.len() - i + 1);
.unwrap();
self.push(0) self.push(0)
} else { } else {
self.write_u32::<BigEndian>((s.len() - i) as u32).unwrap(); self.extend_usize(s.len() - i);
} }
self.extend(&s[i..]); self.extend(&s[i..]);
} }
fn extend_u32(&mut self, s: u32) { fn extend_u32(&mut self, s: u32) {
let mut buf = [0x0; 4]; self.extend(s.to_be_bytes());
BigEndian::write_u32(&mut buf, s);
self.extend(buf);
} }
fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I) { fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I) {
let len0 = self.len(); let len0 = self.len();
self.extend([0, 0, 0, 0]);
let mut first = true; let mut first = true;
for i in list { for i in list {
@ -116,7 +121,7 @@ impl Encoding for Vec<u8> {
} }
let len = (self.len() - len0 - 4) as u32; let len = (self.len() - len0 - 4) as u32;
BigEndian::write_u32(&mut self[len0..], len); self.splice(len0..len0, len.to_be_bytes());
} }
fn write_empty_list(&mut self) { fn write_empty_list(&mut self) {
@ -125,7 +130,7 @@ impl Encoding for Vec<u8> {
fn write_len(&mut self) { fn write_len(&mut self) {
let len = self.len() - 4; let len = self.len() - 4;
BigEndian::write_u32(&mut self[..], len as u32); self[..4].copy_from_slice((len as u32).to_be_bytes().as_slice());
} }
} }
@ -207,7 +212,8 @@ impl<'a> Cursor<'a> {
/// Read a `u32` from this reader. /// Read a `u32` from this reader.
pub fn read_u32(&mut self) -> Result<u32, Error> { pub fn read_u32(&mut self) -> Result<u32, Error> {
if self.position + 4 <= self.s.len() { if self.position + 4 <= self.s.len() {
let u = BigEndian::read_u32(&self.s[self.position..]); let u =
u32::from_be_bytes(self.s[self.position..self.position + 4].try_into().unwrap());
self.position += 4; self.position += 4;
Ok(u) Ok(u)
} else { } else {