sshcerts/ssh/
writer.rs

1use std::collections::HashMap;
2
3use super::pubkey::{PublicKey, PublicKeyKind};
4
5/// A `Writer` is used for encoding a key in OpenSSH compatible format.
6#[derive(Debug)]
7pub struct Writer {
8    inner: Vec<u8>,
9}
10
11impl Writer {
12    /// Creates a new `Writer` instance.
13    ///
14    /// # Example
15    /// ```rust
16    /// # use sshcerts::ssh::Writer;
17    /// let writer = Writer::new();
18    /// ```
19    pub fn new() -> Writer {
20        Writer { inner: Vec::new() }
21    }
22
23    /// Write a cstring to the underlying vector
24    ///
25    /// # Example
26    /// ```rust
27    /// # use sshcerts::ssh::Writer;
28    /// let mut writer = Writer::new();
29    /// writer.write_cstring("AAAA");
30    /// let bytes = writer.into_bytes();
31    /// assert_eq!(bytes, vec![65, 65, 65, 65, 00]);
32    /// ```
33    pub fn write_cstring(&mut self, s: &str) {
34        let bytes = s.as_bytes();
35        self.inner.extend_from_slice(bytes);
36        self.inner.push(0x0);
37    }
38
39    /// Writes a byte sequence to the underlying vector.
40    /// The value is represented as a the byte sequence length,
41    /// followed by the actual byte sequence.
42    ///
43    /// # Example
44    /// ```rust
45    /// # use sshcerts::ssh::Writer;
46    /// let mut writer = Writer::new();
47    /// writer.write_bytes(&[0, 0, 0, 42]);
48    /// let bytes = writer.into_bytes();
49    /// assert_eq!(bytes, vec![0, 0, 0, 4, 0, 0, 0, 42]);
50    /// ```
51    pub fn write_bytes(&mut self, val: &[u8]) {
52        let size = val.len() as u32;
53        let mut buf = size.to_be_bytes().to_vec();
54        self.inner.append(&mut buf);
55        self.inner.extend_from_slice(val);
56    }
57
58    /// Writes a raw byte sequence to the underlying vector.e.
59    ///
60    /// # Example
61    /// ```rust
62    /// # use sshcerts::ssh::Writer;
63    /// let mut writer = Writer::new();
64    /// writer.write_raw_bytes(&[0, 0, 0, 42]);
65    /// let bytes = writer.into_bytes();
66    /// assert_eq!(bytes, vec![0, 0, 0, 42]);
67    /// ```
68    pub fn write_raw_bytes(&mut self, val: &[u8]) {
69        self.inner.extend_from_slice(val);
70    }
71
72    /// Writes a `string` value to the underlying byte sequence.
73    ///
74    /// # Example
75    /// ```rust
76    /// # use sshcerts::ssh::Writer;
77    /// let mut writer = Writer::new();
78    /// writer.write_string("a test string");
79    /// let bytes = writer.into_bytes();
80    /// assert_eq!(bytes, [0, 0, 0, 13, 97, 32, 116, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103]);
81    /// ```
82    pub fn write_string(&mut self, val: &str) {
83        self.write_bytes(val.as_bytes());
84    }
85
86    /// Writes a `u64` value to the underlying byte sequence.
87    ///
88    /// # Example
89    /// ```rust
90    /// # use sshcerts::ssh::Writer;
91    /// let mut writer = Writer::new();
92    /// writer.write_u64(0xFFFFFFFFFFFFFFFF);
93    /// let bytes = writer.into_bytes();
94    /// assert_eq!(bytes, [255, 255, 255, 255, 255, 255, 255, 255]);
95    /// ```
96    pub fn write_u64(&mut self, val: u64) {
97        let bytes = val.to_be_bytes();
98        self.inner.extend_from_slice(&bytes);
99    }
100
101    /// Writes a `u32` value to the underlying byte sequence.
102    ///
103    /// # Example
104    /// ```rust
105    /// # use sshcerts::ssh::Writer;
106    /// let mut writer = Writer::new();
107    /// writer.write_u32(0xFFFFFFFF);
108    /// let bytes = writer.into_bytes();
109    /// assert_eq!(bytes, [255, 255, 255, 255]);
110    /// ```
111    pub fn write_u32(&mut self, val: u32) {
112        let bytes = val.to_be_bytes();
113        self.inner.extend_from_slice(&bytes);
114    }
115
116    /// Writes an `mpint` value to the underlying byte sequence.
117    /// If the MSB bit of the first byte is set then the number is
118    /// negative, otherwise it is positive.
119    /// Positive numbers must be preceeded by a leading zero byte according to RFC 4251, section 5.
120    /// 
121    /// We also make a reasonable effort to fix encoding errors and only write valid, positive, mpints
122    ///
123    /// # Example
124    /// ```rust
125    /// # use sshcerts::ssh::Writer;
126    /// let mut writer = Writer::new();
127    /// writer.write_mpint(&[1, 0, 1]);
128    /// let bytes = writer.into_bytes();
129    /// assert_eq!(bytes, [0, 0, 0, 3, 1, 0, 1]);
130    /// ```
131    pub fn write_mpint(&mut self, val: &[u8]) {
132        let mut leading_zeros = 0;
133        // Remove leading 0s
134        for item in val {
135            if *item == 0 {
136                leading_zeros += 1
137            } else {
138                break;
139            }
140        }
141
142        let val = &val[leading_zeros..];
143        let mut bytes = val.to_vec();
144
145        // If most significant bit is set then prepend a zero byte to
146        // avoid interpretation as a negative number.
147        if val.first().unwrap_or(&0) & 0x80 != 0 {
148            bytes.insert(0, 0);
149        }
150
151        self.write_bytes(&bytes);
152    }
153
154    /// Writes a `Vec<String>` to the underlying byte sequence.
155    ///
156    /// # Example
157    /// ```rust
158    /// # use sshcerts::ssh::Writer;
159    /// let mut writer = Writer::new();
160    ///
161    /// writer.write_string_vec(&vec![String::from("Test"), String::from("Test")]);
162    /// let bytes = writer.into_bytes();
163    /// assert_eq!(bytes, [0, 0, 0, 16, 0, 0, 0, 4, 84, 101, 115, 116, 0, 0, 0, 4, 84, 101, 115, 116]);
164    /// ```
165    pub fn write_string_vec(&mut self, vec: &[String]) {
166        let total_length = vec
167            .iter()
168            .map(|x| x.len())
169            .fold(vec.len() * 4, |x, y| x + y) as u32;
170        self.write_u32(total_length);
171
172        for item in vec {
173            self.write_string(item);
174        }
175    }
176
177    /// Writes a `HashMap<String, String>` to the underlying byte sequence.
178    ///
179    /// # Example
180    /// ```rust
181    /// # use sshcerts::ssh::Writer;
182    /// # use std::collections::HashMap;
183    ///
184    /// let mut writer = Writer::new();
185    /// let mut example_map = HashMap::new();
186    /// example_map.insert(String::from("Test"), String::from(""));
187    /// writer.write_string_map(&example_map);
188    /// let bytes = writer.into_bytes();
189    /// assert_eq!(bytes, [0, 0, 0, 12, 0, 0, 0, 4, 84, 101, 115, 116, 0, 0, 0, 0]);
190    /// ```
191    pub fn write_string_map(&mut self, map: &HashMap<String, String>) {
192        let total_length = map
193            .iter()
194            .map(|x| x.0.len() + x.1.len() + if !x.1.is_empty() { 4 } else { 0 })
195            .fold(map.len() * 8, |x, y| x + y) as u32;
196
197        self.write_u32(total_length);
198
199        for (k, v) in map {
200            self.write_string(k);
201            if v.is_empty() {
202                self.write_u32(0x0);
203            } else {
204                self.write_u32(v.len() as u32 + 4);
205                self.write_string(v);
206            }
207        }
208    }
209
210    /// Writes a `PublicKey` to the underlying byte sequence.
211    ///
212    /// # Example
213    /// ```
214    /// ```
215    pub fn write_pub_key(&mut self, key: &PublicKey) {
216        let mut inner_writer = Writer::new();
217        inner_writer.write_string(key.key_type.name);
218        inner_writer.write_pub_key_data(key);
219
220        let pubkey_bytes = inner_writer.as_bytes();
221        self.write_bytes(pubkey_bytes);
222    }
223
224    /// Writes `PublicKey` data to the underlying byte sequence.
225    ///
226    /// # Example
227    /// ```
228    /// ```
229    pub fn write_pub_key_data(&mut self, key: &PublicKey) {
230        // Write the public key
231        match &key.kind {
232            PublicKeyKind::Rsa(ref k) => {
233                self.write_mpint(&k.e);
234                self.write_mpint(&k.n);
235            }
236            PublicKeyKind::Ecdsa(ref k) => {
237                self.write_string(k.curve.identifier);
238                self.write_bytes(&k.key);
239                if key.key_type.is_sk {
240                    self.write_string(k.sk_application.as_ref().unwrap());
241                }
242            }
243            PublicKeyKind::Ed25519(ref k) => {
244                self.write_bytes(&k.key);
245                if key.key_type.is_sk {
246                    self.write_string(k.sk_application.as_ref().unwrap());
247                }
248            }
249        }
250    }
251
252    /// Converts the `Writer` into a byte sequence.
253    /// This consumes the underlying byte sequence used by the `Writer`.
254    ///
255    /// # Example
256    /// ```rust
257    /// # use sshcerts::ssh::Writer;
258    ///
259    /// let mut writer = Writer::new();
260    /// writer.write_string("some data");
261    /// let bytes = writer.into_bytes();
262    /// assert_eq!(bytes, [0, 0, 0, 9, 115, 111, 109, 101, 32, 100, 97, 116, 97]);
263    /// ```
264    pub fn into_bytes(self) -> Vec<u8> {
265        self.inner
266    }
267
268    /// Converts the `Writer` into a byte sequence.
269    /// This consumes the underlying byte sequence used by the `Writer`.
270    ///
271    /// # Example
272    /// ```rust
273    /// # use sshcerts::ssh::Writer;
274    ///
275    /// let mut writer = Writer::new();
276    /// writer.write_string("some data");
277    /// let bytes = writer.into_bytes();
278    /// assert_eq!(bytes, [0, 0, 0, 9, 115, 111, 109, 101, 32, 100, 97, 116, 97]);
279    /// ```
280    pub fn as_bytes(&self) -> &[u8] {
281        self.inner.as_slice()
282    }
283}
284
285impl Default for Writer {
286    fn default() -> Self {
287        Writer::new()
288    }
289}