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