1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//! SSH handshake parsing.

mod handshake;
pub mod parser;

pub use self::handshake::*;
use serde::Serialize;

/// Parsed SSH handshake contents.
#[derive(Debug, Default, Serialize)]
pub struct Ssh {
    /// Client protocol version exchange message.
    pub client_version_exchange: Option<SshVersionExchange>,
    /// Server protocol version exchange message.
    pub server_version_exchange: Option<SshVersionExchange>,

    /// Key Exchange message.
    pub key_exchange: Option<SshKeyExchange>,

    /// Client Diffie-Hellman Key Exchange message.
    pub client_dh_key_exchange: Option<SshDhInit>,
    /// Server Diffie-Hellman Key Exchange message.
    pub server_dh_key_exchange: Option<SshDhResponse>,

    /// Client New Keys message.
    pub client_new_keys: Option<SshNewKeys>,
    /// Server New Keys message.
    pub server_new_keys: Option<SshNewKeys>,
}

impl Ssh {
    /// Returns the SSH protocol version used by the client (e.g. 2.0).
    pub fn protocol_version_ctos(&self) -> &str {
        match &self.client_version_exchange {
            Some(client_version_exchange) => match &client_version_exchange.protoversion {
                Some(protoversion) => protoversion.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns the SSH software version used by the client.
    pub fn software_version_ctos(&self) -> &str {
        match &self.client_version_exchange {
            Some(client_version_exchange) => match &client_version_exchange.softwareversion {
                Some(softwareversion) => softwareversion.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns comments, or `""` if there are no comments, in the protocol version exchange message sent from the client.
    pub fn comments_ctos(&self) -> &str {
        match &self.client_version_exchange {
            Some(client_version_exchange) => match &client_version_exchange.comments {
                Some(comments) => comments.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns the SSH protocol version used by the server (e.g. 2.0).
    pub fn protocol_version_stoc(&self) -> &str {
        match &self.server_version_exchange {
            Some(server_version_exchange) => match &server_version_exchange.protoversion {
                Some(protoversion) => protoversion.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns the SSH software version used by the server.
    pub fn software_version_stoc(&self) -> &str {
        match &self.server_version_exchange {
            Some(server_version_exchange) => match &server_version_exchange.softwareversion {
                Some(softwareversion) => softwareversion.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns comments, or `""` if there are no comments, in the protocol version exchange message sent from the server.
    pub fn comments_stoc(&self) -> &str {
        match &self.server_version_exchange {
            Some(server_version_exchange) => match &server_version_exchange.comments {
                Some(comments) => comments.as_str(),
                None => "",
            },
            None => "",
        }
    }

    /// Returns the cookie used in SSH key exchange.
    pub fn key_exchange_cookie_stoc(&self) -> Vec<u8> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange.cookie.to_vec(),
            None => vec![],
        }
    }

    /// Returns the key exchange algorithms used in SSH key exchange.
    pub fn kex_algs_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .kex_algs
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the algorithms supported for the server host key.
    pub fn server_host_key_algs_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .server_host_key_algs
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the symmetric encryption algorithms (ciphers) supported by the client.
    pub fn encryption_algs_ctos(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .encryption_algs_client_to_server
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the symmetric encryption algorithms (ciphers) supported by the server.
    pub fn encryption_algs_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .encryption_algs_server_to_client
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the MAC algorithms supported by the client.
    pub fn mac_algs_ctos(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .mac_algs_client_to_server
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the MAC algorithms supported by the server.
    pub fn mac_algs_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .mac_algs_server_to_client
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the compression algorithms supported by the client.
    pub fn compression_algs_ctos(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .compression_algs_client_to_server
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the compression algorithms supported by the server.
    pub fn compression_algs_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .compression_algs_server_to_client
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the language tags (if any) supported by the client.
    pub fn languages_ctos(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .languages_client_to_server
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }

    /// Returns the language tags (if any) supported by the server.
    pub fn languages_stoc(&self) -> Vec<String> {
        match &self.key_exchange {
            Some(key_exchange) => key_exchange
                .languages_server_to_client
                .iter()
                .map(|c| c.to_string())
                .collect(),
            None => vec![],
        }
    }
}