ssh/model/
data.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::error::SshResult;
4
5use super::Packet;
6
7/// Data Type Representations Used in the SSH Protocols
8/// <https://www.rfc-editor.org/rfc/rfc4251#section-5>
9
10/// byte
11///
12/// A byte represents an arbitrary 8-bit value (octet).  Fixed length
13/// data is sometimes represented as an array of bytes, written
14/// byte[n], where n is the number of bytes in the array.
15///
16/// **boolean**
17///
18/// A boolean value is stored as a single byte.  The value 0
19/// represents FALSE, and the value 1 represents TRUE.  All non-zero
20/// values MUST be interpreted as TRUE; however, applications MUST NOT
21/// store values other than 0 and 1.
22///
23/// **uint32**
24///
25/// Represents a 32-bit unsigned integer.  Stored as four bytes in the
26/// order of decreasing significance (network byte order).  For
27/// example: the value 699921578 (0x29b7f4aa) is stored as 29 b7 f4
28/// aa.
29///
30/// **uint64**
31///
32/// Represents a 64-bit unsigned integer.  Stored as eight bytes in
33/// the order of decreasing significance (network byte order).
34///
35/// **string**
36///
37/// Arbitrary length binary string.  Strings are allowed to contain
38/// arbitrary binary data, including null characters and 8-bit
39/// characters.  They are stored as a uint32 containing its length
40/// (number of bytes that follow) and zero (= empty string) or more
41/// bytes that are the value of the string.  Terminating null
42/// characters are not used.
43///
44/// Strings are also used to store text.  In that case, US-ASCII is
45/// used for internal names, and ISO-10646 UTF-8 for text that might
46/// be displayed to the user.  The terminating null character SHOULD
47/// NOT normally be stored in the string.  For example: the US-ASCII
48/// string "testing" is represented as 00 00 00 07 t e s t i n g.  The
49/// UTF-8 mapping does not alter the encoding of US-ASCII characters.
50///
51/// **mpint**
52///
53/// Represents multiple precision integers in two's complement format,
54/// stored as a string, 8 bits per byte, MSB first.  Negative numbers
55/// have the value 1 as the most significant bit of the first byte of
56/// the data partition.  If the most significant bit would be set for
57/// a positive number, the number MUST be preceded by a zero byte.
58/// Unnecessary leading bytes with the value 0 or 255 MUST NOT be
59/// included.  The value zero MUST be stored as a string with zero
60/// bytes of data.
61///
62/// By convention, a number that is used in modular computations in
63/// Z_n SHOULD be represented in the range 0 <= x < n.
64///
65///    Examples:
66///
67///    value (hex)        representation (hex)
68///    -----------        --------------------
69///    0                  00 00 00 00
70///    9a378f9b2e332a7    00 00 00 08 09 a3 78 f9 b2 e3 32 a7
71///    80                 00 00 00 02 00 80
72///    -1234              00 00 00 02 ed cc
73///    -deadbeef          00 00 00 05 ff 21 52 41 11
74///
75/// **name-list**
76///
77/// A string containing a comma-separated list of names.  A name-list
78/// is represented as a uint32 containing its length (number of bytes
79/// that follow) followed by a comma-separated list of zero or more
80/// names.  A name MUST have a non-zero length, and it MUST NOT
81/// contain a comma (",").  As this is a list of names, all of the
82/// elements contained are names and MUST be in US-ASCII.  Context may
83/// impose additional restrictions on the names.  For example, the
84/// names in a name-list may have to be a list of valid algorithm
85/// identifiers (see Section 6 below), or a list of [RFC3066] language
86/// tags.  The order of the names in a name-list may or may not be
87/// significant.  Again, this depends on the context in which the list
88/// is used.  Terminating null characters MUST NOT be used, neither
89/// for the individual names, nor for the list as a whole.
90///
91///  Examples:
92///
93///  value                      representation (hex)
94///  -----                      --------------------
95///  (), the empty name-list    00 00 00 00
96///  ("zlib")                   00 00 00 04 7a 6c 69 62
97///  ("zlib,none")              00 00 00 09 7a 6c 69 62 2c 6e 6f 6e 65
98
99#[derive(Debug, Clone)]
100pub(crate) struct Data(Vec<u8>);
101
102impl Default for Data {
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl Data {
109    pub fn new() -> Data {
110        Data(Vec::new())
111    }
112
113    #[allow(clippy::uninit_vec)]
114    pub fn uninit_new(len: usize) -> Data {
115        let mut v = Vec::with_capacity(len);
116        unsafe { v.set_len(len) }
117        Data(v)
118    }
119
120    // write uint8
121    pub fn put_u8(&mut self, v: u8) -> &mut Self {
122        self.0.push(v);
123        self
124    }
125
126    // write uint32
127    pub fn put_u32(&mut self, v: u32) -> &mut Self {
128        let vec = v.to_be_bytes().to_vec();
129        self.0.extend(&vec);
130        self
131    }
132
133    // write string
134    pub fn put_str(&mut self, str: &str) -> &mut Self {
135        let v = str.as_bytes();
136        self.put_u32(v.len() as u32);
137        self.0.extend(v);
138        self
139    }
140
141    // write [bytes]
142    pub fn put_u8s(&mut self, v: &[u8]) -> &mut Self {
143        self.put_u32(v.len() as u32);
144        self.0.extend(v);
145        self
146    }
147
148    // write mpint
149    pub fn put_mpint(&mut self, v: &[u8]) -> Vec<u8> {
150        let mut result: Vec<u8> = Vec::new();
151        // 0x80 = 128
152        if v[0] & 0x80 != 0 {
153            result.push(0);
154        }
155        result.extend(v);
156        self.put_u8s(&result).to_vec()
157    }
158
159    // skip `size`
160    pub fn skip(&mut self, size: usize) {
161        self.0.drain(..size);
162    }
163
164    // get uint8
165    pub fn get_u8(&mut self) -> u8 {
166        self.0.remove(0)
167    }
168
169    // get uint32
170    pub fn get_u32(&mut self) -> u32 {
171        let u32_buf = self.0.drain(..4).collect::<Vec<u8>>();
172        u32::from_be_bytes(u32_buf.try_into().unwrap())
173    }
174
175    // get [bytes]
176    pub fn get_u8s(&mut self) -> Vec<u8> {
177        let len = self.get_u32() as usize;
178        let bytes = self.0.drain(..len).collect::<Vec<u8>>();
179        bytes
180    }
181
182    pub fn into_inner(self) -> Vec<u8> {
183        self.0
184    }
185}
186
187impl From<Vec<u8>> for Data {
188    fn from(v: Vec<u8>) -> Self {
189        Data(v)
190    }
191}
192
193impl From<&[u8]> for Data {
194    fn from(v: &[u8]) -> Self {
195        Data(v.into())
196    }
197}
198
199impl From<Data> for Vec<u8> {
200    fn from(data: Data) -> Self {
201        data.0
202    }
203}
204
205impl Deref for Data {
206    type Target = Vec<u8>;
207
208    fn deref(&self) -> &Self::Target {
209        &self.0
210    }
211}
212
213impl DerefMut for Data {
214    fn deref_mut(&mut self) -> &mut Self::Target {
215        &mut self.0
216    }
217}
218
219impl<'a> Packet<'a> for Data {
220    fn pack(self, client: &'a mut crate::client::Client) -> super::packet::SecPacket<'a> {
221        (self, client).into()
222    }
223    fn unpack(pkt: super::packet::SecPacket) -> SshResult<Self>
224    where
225        Self: Sized,
226    {
227        Ok(pkt.into_inner())
228    }
229}