ssh_encoding/decode.rs
1//! Decoder-side implementation of the SSH protocol's data type representations
2//! as described in [RFC4251 § 5].
3//!
4//! [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
5
6use crate::{Error, Result, reader::Reader};
7
8#[cfg(feature = "alloc")]
9use alloc::{string::String, vec::Vec};
10
11#[cfg(feature = "bytes")]
12use bytes::Bytes;
13
14/// Maximum size of a `usize` this library will accept.
15const MAX_USIZE: usize = 0xFFFFF;
16
17/// Decoding trait.
18///
19/// This trait describes how to decode a given type.
20pub trait Decode: Sized {
21 /// Type returned in the event of a decoding error.
22 type Error: From<Error>;
23
24 /// Attempt to decode a value of this type using the provided [`Reader`].
25 ///
26 /// # Errors
27 /// Returns errors specific to the concrete implementation of this trait.
28 fn decode(reader: &mut impl Reader) -> core::result::Result<Self, Self::Error>;
29}
30
31/// Decode a single `byte` from the input data.
32impl Decode for u8 {
33 type Error = Error;
34
35 fn decode(reader: &mut impl Reader) -> Result<Self> {
36 let mut buf = [0];
37 reader.read(&mut buf)?;
38 Ok(buf[0])
39 }
40}
41
42/// Decode a `boolean` as described in [RFC4251 § 5]:
43///
44/// > A boolean value is stored as a single byte. The value 0
45/// > represents FALSE, and the value 1 represents TRUE. All non-zero
46/// > values MUST be interpreted as TRUE; however, applications MUST NOT
47/// > store values other than 0 and 1.
48///
49/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
50impl Decode for bool {
51 type Error = Error;
52
53 fn decode(reader: &mut impl Reader) -> Result<Self> {
54 let byte = u8::decode(reader)?;
55 match byte {
56 0 => Ok(false),
57 _ => Ok(true),
58 }
59 }
60}
61
62/// Decode a `uint32` as described in [RFC4251 § 5]:
63///
64/// > Represents a 32-bit unsigned integer. Stored as four bytes in the
65/// > order of decreasing significance (network byte order).
66/// > For example: the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4 aa.
67///
68/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
69impl Decode for u32 {
70 type Error = Error;
71
72 fn decode(reader: &mut impl Reader) -> Result<Self> {
73 let mut bytes = [0u8; 4];
74 reader.read(&mut bytes)?;
75 Ok(u32::from_be_bytes(bytes))
76 }
77}
78
79/// Decode a `uint64` as described in [RFC4251 § 5]:
80///
81/// > Represents a 64-bit unsigned integer. Stored as eight bytes in
82/// > the order of decreasing significance (network byte order).
83///
84/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
85impl Decode for u64 {
86 type Error = Error;
87
88 fn decode(reader: &mut impl Reader) -> Result<Self> {
89 let mut bytes = [0u8; 8];
90 reader.read(&mut bytes)?;
91 Ok(u64::from_be_bytes(bytes))
92 }
93}
94
95/// Decode a `usize`.
96///
97/// Uses [`Decode`] impl on `u32` and then converts to a `usize`, handling
98/// potential overflow if `usize` is smaller than `u32`.
99///
100/// Enforces a library-internal limit of 1048575, as the main use case for
101/// `usize` is length prefixes.
102impl Decode for usize {
103 type Error = Error;
104
105 fn decode(reader: &mut impl Reader) -> Result<Self> {
106 let n = usize::try_from(u32::decode(reader)?)?;
107
108 if n <= MAX_USIZE {
109 Ok(n)
110 } else {
111 Err(Error::Overflow)
112 }
113 }
114}
115
116/// Decodes a byte array from `byte[n]` as described in [RFC4251 § 5]:
117///
118/// > A byte represents an arbitrary 8-bit value (octet). Fixed length
119/// > data is sometimes represented as an array of bytes, written
120/// > `byte[n]`, where n is the number of bytes in the array.
121///
122/// Note that unlike `string`, this type is encoded without a length prefix,
123/// but instead implicitly obtains its length as `N`.
124///
125/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
126impl<const N: usize> Decode for [u8; N] {
127 type Error = Error;
128
129 fn decode(reader: &mut impl Reader) -> Result<Self> {
130 let mut result = [0u8; N];
131 reader.read(&mut result)?;
132 Ok(result)
133 }
134}
135
136/// Decodes `Vec<u8>` from `string` as described in [RFC4251 § 5]:
137///
138/// > Arbitrary length binary string. Strings are allowed to contain
139/// > arbitrary binary data, including null characters and 8-bit
140/// > characters. They are stored as a uint32 containing its length
141/// > (number of bytes that follow) and zero (= empty string) or more
142/// > bytes that are the value of the string. Terminating null
143/// > characters are not used.
144///
145/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
146#[cfg(feature = "alloc")]
147impl Decode for Vec<u8> {
148 type Error = Error;
149
150 fn decode(reader: &mut impl Reader) -> Result<Self> {
151 reader.read_prefixed(|reader| {
152 let mut result = vec![0u8; reader.remaining_len()];
153 reader.read(&mut result)?;
154 Ok(result)
155 })
156 }
157}
158
159#[cfg(feature = "alloc")]
160impl Decode for String {
161 type Error = Error;
162
163 fn decode(reader: &mut impl Reader) -> Result<Self> {
164 String::from_utf8(Vec::decode(reader)?).map_err(|_| Error::CharacterEncoding)
165 }
166}
167
168/// Decodes `Vec<String>` from `name-list` as described in [RFC4251 § 5]:
169///
170/// > A string containing a comma-separated list of names. A name-list
171/// > is represented as a uint32 containing its length (number of bytes
172/// > that follow) followed by a comma-separated list of zero or more
173/// > names. A name MUST have a non-zero length, and it MUST NOT
174/// > contain a comma (","). As this is a list of names, all of the
175/// > elements contained are names and MUST be in US-ASCII. Context may
176/// > impose additional restrictions on the names. For example, the
177/// > names in a name-list may have to be a list of valid algorithm
178/// > identifiers (see Section 6 below), or a list of [RFC3066] language
179/// > tags. The order of the names in a name-list may or may not be
180/// > significant. Again, this depends on the context in which the list
181/// > is used. Terminating null characters MUST NOT be used, neither
182/// > for the individual names, nor for the list as a whole.
183///
184/// [RFC3066]: https://datatracker.ietf.org/doc/html/rfc3066
185/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
186#[cfg(feature = "alloc")]
187impl Decode for Vec<String> {
188 type Error = Error;
189
190 fn decode(reader: &mut impl Reader) -> Result<Self> {
191 reader.read_prefixed(|reader| {
192 let mut entries = Self::new();
193
194 while !reader.is_finished() {
195 entries.push(String::decode(reader)?);
196 }
197
198 Ok(entries)
199 })
200 }
201}
202
203/// Decodes `Bytes` from `string` as described in [RFC4251 § 5]:
204///
205/// > Arbitrary length binary string. Strings are allowed to contain
206/// > arbitrary binary data, including null characters and 8-bit
207/// > characters. They are stored as a uint32 containing its length
208/// > (number of bytes that follow) and zero (= empty string) or more
209/// > bytes that are the value of the string. Terminating null
210/// > characters are not used.
211///
212/// [RFC4251 § 5]: https://datatracker.ietf.org/doc/html/rfc4251#section-5
213#[cfg(feature = "bytes")]
214impl Decode for Bytes {
215 type Error = Error;
216
217 fn decode(reader: &mut impl Reader) -> Result<Self> {
218 Vec::<u8>::decode(reader).map(Into::into)
219 }
220}