Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
ssh: Remove dependency on byteorder
Lorenz Leutgeb committed 9 months ago
commit 8e6279a3828dfc59c4f5e43d9a16bd30421c6660
parent 95b3303eb91609e9e959f4d873e424170c385d88
4 files changed +29 -28
modified Cargo.lock
@@ -2749,7 +2749,6 @@ dependencies = [
name = "radicle-ssh"
version = "0.9.0"
dependencies = [
-
 "byteorder",
 "log",
 "thiserror 1.0.69",
 "winpipe",
modified crates/radicle-ssh/Cargo.toml
@@ -14,10 +14,9 @@ edition.workspace = true
rust-version.workspace = true

[dependencies]
-
byteorder = "1.4"
log = { workspace = true }
thiserror = { workspace = true }
zeroize = { workspace = true }

[target.'cfg(windows)'.dependencies]
-
winpipe = { workspace = true }

\ No newline at end of file
+
winpipe = { workspace = true }
modified crates/radicle-ssh/src/agent/client.rs
@@ -1,6 +1,5 @@
use std::fmt;
use std::io::{Read, Write};
-
use std::ops::DerefMut;
use std::path::{Path, PathBuf};

#[cfg(unix)]
@@ -9,7 +8,6 @@ pub use std::os::unix::net::UnixStream as Stream;
#[cfg(windows)]
pub use winpipe::WinStream as Stream;

-
use byteorder::{BigEndian, ByteOrder as _, WriteBytesExt};
use log::*;
use thiserror::Error;
use zeroize::Zeroize as _;
@@ -145,7 +143,7 @@ impl<Stream: ClientStream> AgentClient<Stream> {
                match *cons {
                    Constraint::KeyLifetime { seconds } => {
                        buf.push(msg::CONSTRAIN_LIFETIME);
-
                        buf.deref_mut().write_u32::<BigEndian>(seconds)?
+
                        buf.extend_u32(seconds);
                    }
                    Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM),
                    Constraint::Extensions {
@@ -186,13 +184,12 @@ impl<Stream: ClientStream> AgentClient<Stream> {
        buf.extend_ssh_string(pin);

        if !constraints.is_empty() {
-
            buf.deref_mut()
-
                .write_u32::<BigEndian>(constraints.len() as u32)?;
+
            buf.extend_usize(constraints.len());
            for cons in constraints {
                match *cons {
                    Constraint::KeyLifetime { seconds } => {
                        buf.push(msg::CONSTRAIN_LIFETIME);
-
                        buf.deref_mut().write_u32::<BigEndian>(seconds)?;
+
                        buf.extend_u32(seconds);
                    }
                    Constraint::Confirm => buf.push(msg::CONSTRAIN_CONFIRM),
                    Constraint::Extensions {
@@ -304,14 +301,13 @@ impl<Stream: ClientStream> AgentClient<Stream> {
        let total = 1 + pk.len() + 4 + data.len() + 4;

        let mut buf = Buffer::default();
-
        buf.write_u32::<BigEndian>(total as u32)
-
            .expect("Writing to a vector never fails");
+
        buf.extend_usize(total);
        buf.push(msg::SIGN_REQUEST);
        buf.extend_from_slice(&pk);
        buf.extend_ssh_string(data);

        // Signature flags should be zero for ed25519.
-
        buf.write_u32::<BigEndian>(0).unwrap();
+
        buf.extend_u32(0);
        buf
    }

@@ -338,7 +334,7 @@ impl<Stream: ClientStream> AgentClient<Stream> {
        let total = 1 + pk.len();

        let mut buf = Buffer::default();
-
        buf.write_u32::<BigEndian>(total as u32)?;
+
        buf.extend_usize(total);
        buf.push(msg::REMOVE_IDENTITY);
        buf.extend_from_slice(&pk);

@@ -422,7 +418,8 @@ impl<S: Read + Write + Sized + Send + Sync> ClientStream for S {
        self.read_exact(&mut resp)?;

        // 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.resize(len, 0);
        self.read_exact(&mut resp)?;
modified crates/radicle-ssh/src/encoding.rs
@@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-
use std::ops::DerefMut;
+
use std::ops::DerefMut as _;

-
use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
use thiserror::Error;
use zeroize::Zeroizing;

@@ -53,6 +52,16 @@ pub trait Encoding {
    fn write_empty_list(&mut self);
    /// Write the buffer length at the beginning of the buffer.
    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.
@@ -66,12 +75,12 @@ pub fn mpint_len(s: &[u8]) -> usize {

impl Encoding for Vec<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);
    }

    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();
        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 s[i] & 0x80 != 0 {
-
            self.write_u32::<BigEndian>((s.len() - i + 1) as u32)
-
                .unwrap();
+
            self.extend_usize(s.len() - i + 1);
            self.push(0)
        } else {
-
            self.write_u32::<BigEndian>((s.len() - i) as u32).unwrap();
+
            self.extend_usize(s.len() - i);
        }
        self.extend(&s[i..]);
    }

    fn extend_u32(&mut self, s: u32) {
-
        let mut buf = [0x0; 4];
-
        BigEndian::write_u32(&mut buf, s);
-
        self.extend(buf);
+
        self.extend(s.to_be_bytes());
    }

    fn extend_list<'a, I: Iterator<Item = &'a [u8]>>(&mut self, list: I) {
        let len0 = self.len();
-
        self.extend([0, 0, 0, 0]);

        let mut first = true;
        for i in list {
@@ -116,7 +121,7 @@ impl Encoding for Vec<u8> {
        }
        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) {
@@ -125,7 +130,7 @@ impl Encoding for Vec<u8> {

    fn write_len(&mut self) {
        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.
    pub fn read_u32(&mut self) -> Result<u32, Error> {
        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;
            Ok(u)
        } else {