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}