ssh_key/
reader.rs

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