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