Skip to main content

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}