Skip to main content

ssh_encoding/
reader.rs

1//! Reader trait and associated implementations.
2
3use crate::{Error, Result, decode::Decode};
4use core::str;
5
6/// Reader trait which decodes the binary SSH protocol serialization from
7/// various inputs.
8pub trait Reader: Sized {
9    /// Read as much data as is needed to exactly fill `out`.
10    ///
11    /// This is the base decoding method on which the rest of the trait is implemented in terms of.
12    ///
13    /// Returns `out` reborrowed as an immutable byte slice.
14    ///
15    /// # Errors
16    /// Returns `Err(Error::Length)` if the exact amount of data couldn't be read.
17    fn read<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]>;
18
19    /// Get the length of the remaining data after Base64 decoding.
20    fn remaining_len(&self) -> usize;
21
22    /// Is decoding finished?
23    fn is_finished(&self) -> bool {
24        self.remaining_len() == 0
25    }
26
27    /// Decode length-prefixed data.
28    ///
29    /// Decodes a `uint32` which identifies the length of some encapsulated data, then calls the
30    /// given reader function with the length of the remaining data.
31    ///
32    /// # Errors
33    /// Propagates errors returned from `F`.
34    fn read_prefixed<T, E, F>(&mut self, f: F) -> core::result::Result<T, E>
35    where
36        E: From<Error>,
37        F: FnOnce(&mut Self) -> core::result::Result<T, E>;
38
39    /// Decodes `[u8]` from `byte[n]` as described in [RFC4251 § 5]:
40    ///
41    /// > A byte represents an arbitrary 8-bit value (octet).  Fixed length
42    /// > data is sometimes represented as an array of bytes, written
43    /// > `byte[n]`, where n is the number of bytes in the array.
44    ///
45    /// Storage for the byte array must be provided as mutable byte slice in order to accommodate
46    /// `no_alloc` use cases.
47    ///
48    /// The [`Decode`] impl on `Vec<u8>` can be used to allocate a buffer for the result.
49    ///
50    /// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
51    ///
52    /// # Errors
53    /// - Returns [`Error::Length`] if `out` is too small to accommodate the full `byte[n]`.
54    /// - Propagates errors returned from [`Reader::read`].
55    fn read_byten<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> {
56        self.read_prefixed(|reader| {
57            let slice = out.get_mut(..reader.remaining_len()).ok_or(Error::Length)?;
58            reader.read(slice)?;
59            Ok(&*slice)
60        })
61    }
62
63    /// Decode a `string` as described in [RFC4251 § 5]:
64    ///
65    /// > Arbitrary length binary string.  Strings are allowed to contain
66    /// > arbitrary binary data, including null characters and 8-bit
67    /// > characters.  They are stored as a uint32 containing its length
68    /// > (number of bytes that follow) and zero (= empty string) or more
69    /// > bytes that are the value of the string.  Terminating null
70    /// > characters are not used.
71    /// >
72    /// > Strings are also used to store text.  In that case, US-ASCII is
73    /// > used for internal names, and ISO-10646 UTF-8 for text that might
74    /// > be displayed to the user.  The terminating null character SHOULD
75    /// > NOT normally be stored in the string.  For example: the US-ASCII
76    /// > string "testing" is represented as 00 00 00 07 t e s t i n g.  The
77    /// > UTF-8 mapping does not alter the encoding of US-ASCII characters.
78    ///
79    /// Storage for the string data must be provided as mutable byte slice in order to accommodate
80    /// `no_alloc` use cases.
81    ///
82    /// The [`Decode`] impl on `String` can be used to allocate a buffer for the result.
83    ///
84    /// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
85    ///
86    /// # Errors
87    /// - Propagates errors returned from [`Reader::read_byten`].
88    /// - Returns [`Error::CharacterEncoding`] if the data is not valid UTF-8.
89    fn read_string<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o str> {
90        Ok(str::from_utf8(self.read_byten(buf)?)?)
91    }
92
93    /// Drain the given number of bytes from the reader, discarding them.
94    ///
95    /// # Errors
96    /// Propagates errors returned from [`Reader::read`].
97    fn drain(&mut self, n_bytes: usize) -> Result<()> {
98        let mut byte = [0];
99        for _ in 0..n_bytes {
100            self.read(&mut byte)?;
101        }
102        Ok(())
103    }
104
105    /// Decode a `u32` length prefix, and then drain the length of the body.
106    ///
107    /// Upon success, returns the number of bytes drained sans the length of the `u32` length prefix
108    /// (4-bytes).
109    ///
110    /// # Errors
111    /// - Propagates errors returned from [`Reader::read_prefixed`].
112    /// - Propagates errors returned from [`Reader::drain`].
113    fn drain_prefixed(&mut self) -> Result<usize> {
114        self.read_prefixed(|reader| {
115            let len = reader.remaining_len();
116            reader.drain(len)?;
117            Ok(len)
118        })
119    }
120
121    /// Ensure that decoding is finished.
122    ///
123    /// # Errors
124    /// Returns [`Error::TrailingData`] if there is data remaining in the encoder.
125    fn ensure_finished(&self) -> Result<()> {
126        if self.is_finished() {
127            Ok(())
128        } else {
129            Err(Error::TrailingData {
130                remaining: self.remaining_len(),
131            })
132        }
133    }
134
135    /// Finish decoding, returning the given value if there is no remaining data.
136    ///
137    /// # Errors
138    /// Returns [`Error::TrailingData`] if there is data remaining in the encoder.
139    fn finish<T>(self, value: T) -> Result<T> {
140        self.ensure_finished()?;
141        Ok(value)
142    }
143}
144
145impl Reader for &[u8] {
146    fn read<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> {
147        if self.len() >= out.len() {
148            let (head, tail) = self.split_at(out.len());
149            *self = tail;
150            out.copy_from_slice(head);
151            Ok(out)
152        } else {
153            Err(Error::Length)
154        }
155    }
156
157    fn read_prefixed<T, E, F>(&mut self, f: F) -> core::result::Result<T, E>
158    where
159        E: From<Error>,
160        F: FnOnce(&mut Self) -> core::result::Result<T, E>,
161    {
162        let prefix_len = usize::decode(self)?;
163
164        if self.len() < prefix_len {
165            return Err(Error::Length.into());
166        }
167
168        let (mut prefix, remaining) = self.split_at(prefix_len);
169        let ret = f(&mut prefix)?;
170        *self = remaining;
171        Ok(ret)
172    }
173
174    fn remaining_len(&self) -> usize {
175        self.len()
176    }
177}
178
179/// Writes a `Reader` impl for the given newtype with a `remaining_len` field.
180// TODO(tarcieri): non-macro abstraction over `Base64Reader` and `PemReader`
181#[cfg(any(feature = "base64", feature = "pem"))]
182macro_rules! impl_reader_for_newtype {
183    ($type:ty) => {
184        impl Reader for $type {
185            fn read<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> {
186                if out.is_empty() {
187                    return Ok(out);
188                }
189
190                let remaining_len = self
191                    .remaining_len
192                    .checked_sub(out.len())
193                    .ok_or(Error::Length)?;
194
195                let ret = self.inner.decode(out)?;
196                self.remaining_len = remaining_len;
197                Ok(ret)
198            }
199
200            fn read_prefixed<T, E, F>(&mut self, f: F) -> core::result::Result<T, E>
201            where
202                E: From<Error>,
203                F: FnOnce(&mut Self) -> core::result::Result<T, E>,
204            {
205                let prefix_len = usize::decode(self)?;
206                let new_remaining_len = self
207                    .remaining_len
208                    .checked_sub(prefix_len)
209                    .ok_or(Error::Length)?;
210
211                self.remaining_len = prefix_len;
212                let ret = f(self)?;
213                self.ensure_finished()?;
214
215                self.remaining_len = new_remaining_len;
216                Ok(ret)
217            }
218
219            fn remaining_len(&self) -> usize {
220                self.remaining_len
221            }
222        }
223    };
224}