coolssh/
messages.rs

1use super::{Result, Error, Write, U8, U32};
2use super::parse_dump_struct;
3use super::parsedump::{ParseDump, too_short, try_u32};
4pub use super::userauth::UserauthRequest;
5pub use super::channelrequest::ChannelRequest;
6
7// Use with caution: copy-pasting
8// and leaving the wrong variant name
9// can lead to stack overflow
10#[doc(hidden)]
11#[macro_export]
12macro_rules! check_msg_type {
13    ($name:ident, $expected:expr, $bytes:ident) => {
14        let raw_msg_type = u8::parse($bytes)?.0;
15        let msg_type = MessageType::try_from(raw_msg_type)?;
16        if msg_type != $expected {
17            let (msg, _) = $crate::messages::Message::parse($bytes)?;
18            log::error!(concat!("Expected ", stringify!($name), " message but got {:#?}"), msg);
19            return Err(Error::UnexpectedMessageType(msg_type));
20        }
21    }
22}
23
24#[derive(Debug)]
25#[allow(dead_code)]
26pub enum Message<'a> {
27    Disconnect(Disconnect<'a>),
28    Ignore,
29    Unimplemented(Unimplemented),
30    Debug,
31    ServiceRequest(ServiceRequest<'a>),
32    ServiceAccept(ServiceAccept<'a>),
33    Kexinit(Kexinit<'a>),
34    Newkeys(Newkeys),
35    KexdhInit(KexdhInit<'a>),
36    KexdhReply(KexdhReply<'a>),
37    UserauthRequest(UserauthRequest<'a>),
38    UserauthFailure(UserauthFailure<'a>),
39    UserauthSuccess(UserauthSuccess),
40    UserauthPkOk(UserauthPkOk<'a>),
41    GlobalRequest(GlobalRequest<'a>),
42    RequestSuccess,
43    RequestFailure,
44    ChannelOpen(ChannelOpen<'a>),
45    ChannelOpenConfirmation(ChannelOpenConfirmation),
46    ChannelOpenFailure(ChannelOpenFailure<'a>),
47    ChannelWindowAdjust(ChannelWindowAdjust),
48    ChannelData(ChannelData<'a>),
49    ChannelExtendedData(ChannelExtendedData<'a>),
50    ChannelEof(ChannelEof),
51    ChannelClose(ChannelClose),
52    ChannelRequest(ChannelRequest<'a>),
53    ChannelSuccess(ChannelSuccess),
54    ChannelFailure(ChannelFailure),
55}
56
57parse_dump_struct!(Unimplemented {
58    packet_number: u32,
59});
60
61parse_dump_struct!(Kexinit<'a> {
62    cookie: [u8; 16],
63    kex_algorithms: &'a str,
64    server_host_key_algorithms: &'a str,
65    encryption_algorithms_client_to_server: &'a str,
66    encryption_algorithms_server_to_client: &'a str,
67    mac_algorithms_client_to_server: &'a str,
68    mac_algorithms_server_to_client: &'a str,
69    compression_algorithms_client_to_server: &'a str,
70    compression_algorithms_server_to_client: &'a str,
71    languages_client_to_server: &'a str,
72    languages_server_to_client: &'a str,
73    first_kex_packet_follows: bool,
74    nop: u32,
75});
76
77parse_dump_struct!(KexdhInit<'a> {
78    client_ephemeral_pubkey: &'a [u8],
79});
80
81parse_dump_struct!(KexdhReply<'a> {
82    server_public_host_key: Blob<'a>,
83    server_ephemeral_pubkey: &'a [u8],
84    exchange_hash_signature: Blob<'a>,
85});
86
87parse_dump_struct!(Newkeys {});
88
89parse_dump_struct!(ServiceRequest<'a> {
90    service_name: &'a str,
91});
92
93parse_dump_struct!(ServiceAccept<'a> {
94    service_name: &'a str,
95});
96
97parse_dump_struct!(Disconnect<'a> {
98    reason_code: DisconnectReasonCode,
99    description: &'a str,
100    language_tag: &'a str,
101});
102
103parse_dump_struct!(UserauthSuccess {});
104
105parse_dump_struct!(UserauthPkOk<'a> {
106    algorithm: &'a str,
107    blob: Blob<'a>,
108});
109
110parse_dump_struct!(UserauthFailure<'a> {
111    allowed_auth: &'a str,
112    partial_success: bool,
113});
114
115parse_dump_struct!(ChannelOpen<'a> {
116    channel_type: &'a str,
117    client_channel: u32,
118    client_initial_window_size: u32,
119    client_max_packet_size: u32,
120});
121
122parse_dump_struct!(ChannelOpenConfirmation {
123    client_channel: u32,
124    server_channel: u32,
125    server_initial_window_size: u32,
126    server_max_packet_size: u32,
127});
128
129parse_dump_struct!(ChannelOpenFailure<'a> {
130    client_channel: u32,
131    reason_code: u32,
132    description: &'a str,
133    language_tag: &'a str,
134});
135
136parse_dump_struct!(ChannelData<'a> {
137    recipient_channel: u32,
138    data: &'a [u8],
139});
140
141parse_dump_struct!(ChannelExtendedData<'a> {
142    recipient_channel: u32,
143    data_type: u32,
144    data: &'a [u8],
145});
146
147parse_dump_struct!(ChannelEof {
148    recipient_channel: u32,
149});
150
151parse_dump_struct!(ChannelClose {
152    recipient_channel: u32,
153});
154
155parse_dump_struct!(ChannelSuccess {
156    recipient_channel: u32,
157});
158
159parse_dump_struct!(ChannelFailure {
160    recipient_channel: u32,
161});
162
163parse_dump_struct!(GlobalRequest<'a> {
164    request_name: &'a str,
165    want_reply: bool,
166});
167
168parse_dump_struct!(ChannelWindowAdjust {
169    recipient_channel: u32,
170    bytes_to_add: u32,
171});
172
173// utils, not messages:
174
175parse_dump_struct!(ExchangeHash<'a> {
176    client_header: &'a [u8],
177    server_header: &'a [u8],
178    client_kexinit_payload: &'a [u8],
179    server_kexinit_payload: &'a [u8],
180    server_public_host_key: Blob<'a>,
181    client_ephemeral_pubkey: &'a [u8],
182    server_ephemeral_pubkey: &'a [u8],
183    shared_secret: UnsignedMpInt<'a>,
184});
185
186parse_dump_struct!(Blob<'a> {
187    blob_len: u32,
188    header: &'a str,
189    content: &'a [u8],
190});
191
192macro_rules! forward_and_wrap {
193    ($variant:ident, $rem:ident) => ( $variant::parse($rem).map(|(inner, p)| (Self::$variant(inner), p)) )
194}
195
196impl<'a, 'b: 'a> ParseDump<'b> for Message<'a> {
197    fn parse(bytes: &'b [u8]) -> Result<(Self, usize)> {
198        let typ = *bytes.get(0).ok_or_else(|| too_short())?;
199        match MessageType::try_from(typ)? {
200
201            MessageType::Disconnect => forward_and_wrap!(Disconnect, bytes),
202            MessageType::Unimplemented => forward_and_wrap!(Unimplemented, bytes),
203            MessageType::ServiceRequest => forward_and_wrap!(ServiceRequest, bytes),
204            MessageType::ServiceAccept => forward_and_wrap!(ServiceAccept, bytes),
205            MessageType::Kexinit => forward_and_wrap!(Kexinit, bytes),
206            MessageType::Newkeys => forward_and_wrap!(Newkeys, bytes),
207            MessageType::KexdhInit => forward_and_wrap!(KexdhInit, bytes),
208            MessageType::KexdhReply => forward_and_wrap!(KexdhReply, bytes),
209            MessageType::UserauthRequest => forward_and_wrap!(UserauthRequest, bytes),
210            MessageType::UserauthFailure => forward_and_wrap!(UserauthFailure, bytes),
211            MessageType::UserauthSuccess => forward_and_wrap!(UserauthSuccess, bytes),
212            MessageType::UserauthPkOk => forward_and_wrap!(UserauthPkOk, bytes),
213            MessageType::ChannelOpen => forward_and_wrap!(ChannelOpen, bytes),
214            MessageType::ChannelOpenConfirmation => forward_and_wrap!(ChannelOpenConfirmation, bytes),
215            MessageType::ChannelOpenFailure => forward_and_wrap!(ChannelOpenFailure, bytes),
216            MessageType::ChannelData => forward_and_wrap!(ChannelData, bytes),
217            MessageType::ChannelExtendedData => forward_and_wrap!(ChannelExtendedData, bytes),
218            MessageType::ChannelEof => forward_and_wrap!(ChannelEof, bytes),
219            MessageType::ChannelWindowAdjust => forward_and_wrap!(ChannelWindowAdjust, bytes),
220            MessageType::ChannelClose => forward_and_wrap!(ChannelClose, bytes),
221            MessageType::ChannelSuccess => forward_and_wrap!(ChannelSuccess, bytes),
222            MessageType::ChannelFailure => forward_and_wrap!(ChannelFailure, bytes),
223            MessageType::ChannelRequest => forward_and_wrap!(ChannelRequest, bytes),
224            MessageType::GlobalRequest => forward_and_wrap!(GlobalRequest, bytes),
225
226            typ => {
227                log::error!("Unimplemented: Message::parse() for {:?}", typ);
228                Err(Error::Unimplemented)
229            },
230        }
231    }
232
233    fn dump<W: Write>(&self, sink: &mut W) -> Result<()> {
234        (self.typ() as u8).dump(sink)?;
235        match self {
236            Self::Disconnect(inner) => inner.dump(sink),
237            Self::Unimplemented(inner) => inner.dump(sink),
238            Self::ServiceRequest(inner) => inner.dump(sink),
239            Self::ServiceAccept(inner) => inner.dump(sink),
240            Self::Kexinit(inner) => inner.dump(sink),
241            Self::Newkeys(inner) => inner.dump(sink),
242            Self::KexdhInit(inner) => inner.dump(sink),
243            Self::KexdhReply(inner) => inner.dump(sink),
244            Self::UserauthRequest(inner) => inner.dump(sink),
245            Self::UserauthFailure(inner) => inner.dump(sink),
246            Self::UserauthSuccess(inner) => inner.dump(sink),
247            Self::UserauthPkOk(inner) => inner.dump(sink),
248            Self::ChannelOpen(inner) => inner.dump(sink),
249            Self::ChannelOpenConfirmation(inner) => inner.dump(sink),
250            Self::ChannelOpenFailure(inner) => inner.dump(sink),
251            Self::ChannelData(inner) => inner.dump(sink),
252            Self::ChannelExtendedData(inner) => inner.dump(sink),
253            Self::ChannelEof(inner) => inner.dump(sink),
254            Self::ChannelWindowAdjust(inner) => inner.dump(sink),
255            Self::ChannelClose(inner) => inner.dump(sink),
256            Self::ChannelSuccess(inner) => inner.dump(sink),
257            Self::ChannelFailure(inner) => inner.dump(sink),
258            Self::ChannelRequest(inner) => inner.dump(sink),
259            Self::GlobalRequest(inner) => inner.dump(sink),
260
261            typ => {
262                log::error!("Unimplemented: Message::dump() for {:?}", typ);
263                Err(Error::Unimplemented)
264            },
265        }
266    }
267}
268
269impl<'a> Message<'a> {
270    pub fn typ(&self) -> MessageType {
271        match self {
272            Self::Disconnect(_) => MessageType::Disconnect,
273            Self::Ignore => MessageType::Ignore,
274            Self::Unimplemented(_) => MessageType::Unimplemented,
275            Self::Debug => MessageType::Debug,
276            Self::ServiceRequest(_) => MessageType::ServiceRequest,
277            Self::ServiceAccept(_) => MessageType::ServiceAccept,
278            Self::Kexinit(_) => MessageType::Kexinit,
279            Self::Newkeys(_) => MessageType::Newkeys,
280            Self::KexdhInit(_) => MessageType::KexdhInit,
281            Self::KexdhReply(_) => MessageType::KexdhReply,
282            Self::UserauthRequest(_) => MessageType::UserauthRequest,
283            Self::UserauthFailure(_) => MessageType::UserauthFailure,
284            Self::UserauthSuccess(_) => MessageType::UserauthSuccess,
285            Self::UserauthPkOk(_) => MessageType::UserauthPkOk,
286            Self::GlobalRequest(_) => MessageType::GlobalRequest,
287            Self::RequestSuccess => MessageType::RequestSuccess,
288            Self::RequestFailure => MessageType::RequestFailure,
289            Self::ChannelOpen(_) => MessageType::ChannelOpen,
290            Self::ChannelOpenConfirmation(_) => MessageType::ChannelOpenConfirmation,
291            Self::ChannelOpenFailure(_) => MessageType::ChannelOpenFailure,
292            Self::ChannelWindowAdjust(_) => MessageType::ChannelWindowAdjust,
293            Self::ChannelData(_) => MessageType::ChannelData,
294            Self::ChannelExtendedData(_) => MessageType::ChannelExtendedData,
295            Self::ChannelEof(_) => MessageType::ChannelEof,
296            Self::ChannelClose(_) => MessageType::ChannelClose,
297            Self::ChannelRequest(_) => MessageType::ChannelRequest,
298            Self::ChannelSuccess(_) => MessageType::ChannelSuccess,
299            Self::ChannelFailure(_) => MessageType::ChannelFailure,
300        }
301    }
302}
303
304#[derive(Copy, Clone, Debug, PartialEq, Eq)]
305#[repr(u8)]
306pub enum MessageType {
307    Disconnect = 1,
308    Ignore = 2,
309    Unimplemented = 3,
310    Debug = 4,
311    ServiceRequest = 5,
312    ServiceAccept = 6,
313    Kexinit = 20,
314    Newkeys = 21,
315    KexdhInit = 30,
316    KexdhReply = 31,
317    UserauthRequest = 50,
318    UserauthFailure = 51,
319    UserauthSuccess = 52,
320    UserauthBanner = 53,
321    UserauthPkOk = 60,
322    GlobalRequest = 80,
323    RequestSuccess = 81,
324    RequestFailure = 82,
325    ChannelOpen = 90,
326    ChannelOpenConfirmation = 91,
327    ChannelOpenFailure = 92,
328    ChannelWindowAdjust = 93,
329    ChannelData = 94,
330    ChannelExtendedData = 95,
331    ChannelEof = 96,
332    ChannelClose = 97,
333    ChannelRequest = 98,
334    ChannelSuccess = 99,
335    ChannelFailure = 100,
336}
337
338impl MessageType {
339    const fn from_struct_name(name: &str) -> Option<Self> {
340        match name.as_bytes() {
341            b"Disconnect" => Some(Self::Disconnect),
342            b"Ignore" => Some(Self::Ignore),
343            b"Unimplemented" => Some(Self::Unimplemented),
344            b"Debug" => Some(Self::Debug),
345            b"ServiceRequest" => Some(Self::ServiceRequest),
346            b"ServiceAccept" => Some(Self::ServiceAccept),
347            b"Kexinit" => Some(Self::Kexinit),
348            b"Newkeys" => Some(Self::Newkeys),
349            b"KexdhInit" => Some(Self::KexdhInit),
350            b"KexdhReply" => Some(Self::KexdhReply),
351            b"UserauthRequest" => Some(Self::UserauthRequest),
352            b"UserauthFailure" => Some(Self::UserauthFailure),
353            b"UserauthSuccess" => Some(Self::UserauthSuccess),
354            b"UserauthBanner" => Some(Self::UserauthBanner),
355            b"UserauthPkOk" => Some(Self::UserauthPkOk),
356            b"GlobalRequest" => Some(Self::GlobalRequest),
357            b"RequestSuccess" => Some(Self::RequestSuccess),
358            b"RequestFailure" => Some(Self::RequestFailure),
359            b"ChannelOpen" => Some(Self::ChannelOpen),
360            b"ChannelOpenConfirmation" => Some(Self::ChannelOpenConfirmation),
361            b"ChannelOpenFailure" => Some(Self::ChannelOpenFailure),
362            b"ChannelWindowAdjust" => Some(Self::ChannelWindowAdjust),
363            b"ChannelData" => Some(Self::ChannelData),
364            b"ChannelExtendedData" => Some(Self::ChannelExtendedData),
365            b"ChannelEof" => Some(Self::ChannelEof),
366            b"ChannelClose" => Some(Self::ChannelClose),
367
368            // hack: this allows ChannelRequestExec to dump the correct message type
369            b"ChannelRequest" => Some(Self::ChannelRequest),
370
371            b"ChannelSuccess" => Some(Self::ChannelSuccess),
372            b"ChannelFailure" => Some(Self::ChannelFailure),
373            _ => None,
374        }
375    }
376}
377
378impl TryFrom<u8> for MessageType {
379    type Error = Error;
380    fn try_from(value: u8) -> Result<Self> {
381        match value {
382            1 => Ok(Self::Disconnect),
383            2 => Ok(Self::Ignore),
384            3 => Ok(Self::Unimplemented),
385            4 => Ok(Self::Debug),
386            5 => Ok(Self::ServiceRequest),
387            6 => Ok(Self::ServiceAccept),
388            20 => Ok(Self::Kexinit),
389            21 => Ok(Self::Newkeys),
390            30 => Ok(Self::KexdhInit),
391            31 => Ok(Self::KexdhReply),
392            50 => Ok(Self::UserauthRequest),
393            51 => Ok(Self::UserauthFailure),
394            52 => Ok(Self::UserauthSuccess),
395            53 => Ok(Self::UserauthBanner),
396            60 => Ok(Self::UserauthPkOk),
397            80 => Ok(Self::GlobalRequest),
398            81 => Ok(Self::RequestSuccess),
399            82 => Ok(Self::RequestFailure),
400            90 => Ok(Self::ChannelOpen),
401            91 => Ok(Self::ChannelOpenConfirmation),
402            92 => Ok(Self::ChannelOpenFailure),
403            93 => Ok(Self::ChannelWindowAdjust),
404            94 => Ok(Self::ChannelData),
405            95 => Ok(Self::ChannelExtendedData),
406            96 => Ok(Self::ChannelEof),
407            97 => Ok(Self::ChannelClose),
408            98 => Ok(Self::ChannelRequest),
409            99 => Ok(Self::ChannelSuccess),
410            100 => Ok(Self::ChannelFailure),
411            value => Err(Error::UnknownMessageType(value)),
412        }
413    }
414}
415
416#[derive(Copy, Clone, Debug)]
417pub struct UnsignedMpInt<'a>(pub &'a [u8]);
418
419impl<'a, 'b: 'a> ParseDump<'b> for UnsignedMpInt<'a> {
420    fn parse(bytes: &'b [u8]) -> Result<(Self, usize)> {
421        let total = U32 + (try_u32(bytes)? as usize);
422        Ok((Self(bytes.get(U32..total).ok_or_else(|| too_short())?), total))
423    }
424
425    fn dump<W: Write>(&self, sink: &mut W) -> Result<()> {
426        let has_non_zero = self.0.iter().position(|b| *b != 0);
427        if has_non_zero.is_some() {
428            let prevent_sign = (self.0[0] & 0x80) != 0;
429            let len = self.0.len() + (prevent_sign as usize);
430
431            sink.write(&(len as u32).to_be_bytes())?;
432            if prevent_sign {
433                sink.write(&[0])?;
434            }
435
436            sink.write(self.0)?;
437            Ok(())
438        } else {
439            0u32.dump(sink)
440        }
441    }
442}
443
444#[derive(Copy, Clone, Debug)]
445#[repr(u8)]
446pub enum DisconnectReasonCode {
447    HostNotAllowedToConnect = 1,
448    ProtocolError = 2,
449    KeyExchangeFailed = 3,
450    Reserved = 4,
451    MacError = 5,
452    CompressionError = 6,
453    ServiceNotAvailable = 7,
454    ProtocolVersionNotSupported = 8,
455    HostKeyNotVerifiable = 9,
456    ConnectionLost = 10,
457    ByApplication = 11,
458    TooManyConnections = 12,
459    AuthCancelledByUser = 13,
460    NoMoreAuthMethodsAvailable = 14,
461    IllegalUserName = 15,
462}
463
464impl<'b> ParseDump<'b> for DisconnectReasonCode {
465    fn parse(bytes: &'b [u8]) -> Result<(Self, usize)> {
466        let (byte, progress) = u8::parse(bytes)?;
467        let reason = match byte {
468            1 => Ok(Self::HostNotAllowedToConnect),
469            2 => Ok(Self::ProtocolError),
470            3 => Ok(Self::KeyExchangeFailed),
471            4 => Ok(Self::Reserved),
472            5 => Ok(Self::MacError),
473            6 => Ok(Self::CompressionError),
474            7 => Ok(Self::ServiceNotAvailable),
475            8 => Ok(Self::ProtocolVersionNotSupported),
476            9 => Ok(Self::HostKeyNotVerifiable),
477            10 => Ok(Self::ConnectionLost),
478            11 => Ok(Self::ByApplication),
479            12 => Ok(Self::TooManyConnections),
480            13 => Ok(Self::AuthCancelledByUser),
481            14 => Ok(Self::NoMoreAuthMethodsAvailable),
482            15 => Ok(Self::IllegalUserName),
483            c => {
484                log::error!("Invalid disconnect reason code: {}", c);
485                Err(Error::InvalidData)
486            },
487        }?;
488        Ok((reason, progress))
489    }
490
491    fn dump<W: Write>(&self, sink: &mut W) -> Result<()> {
492        (*self as u8).dump(sink)
493    }
494}
495
496impl<'a> Kexinit<'a> {
497    pub fn check_compat(&self, client: &Self) -> Result<()> {
498        fn find(haystack: &str, needle: &str) -> Result<()> {
499            match haystack.split(",").position(|alg| alg == needle) {
500                None => {
501                    log::error!("Couldn't agree with peer on an algorithm set");
502                    Err(Error::Unimplemented)
503                },
504                Some(_) => Ok(()),
505            }
506        }
507
508        find(self.kex_algorithms, client.kex_algorithms)?;
509        find(self.server_host_key_algorithms, client.server_host_key_algorithms)?;
510        find(self.encryption_algorithms_client_to_server, client.encryption_algorithms_client_to_server)?;
511        find(self.encryption_algorithms_server_to_client, client.encryption_algorithms_server_to_client)?;
512        find(self.mac_algorithms_client_to_server, client.mac_algorithms_client_to_server)?;
513        find(self.mac_algorithms_server_to_client, client.mac_algorithms_server_to_client)?;
514        find(self.compression_algorithms_client_to_server, client.compression_algorithms_client_to_server)?;
515        find(self.compression_algorithms_server_to_client, client.compression_algorithms_server_to_client)
516    }
517}