### Bug Summary

File: | builds/wireshark/wireshark/epan/dissectors/packet-ssh.c
Warning: | line 2711, column 17 Value of 'errno' was not checked and may be overwritten by function 'ferror'

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-ssh.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-22/lib/clang/22 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-nonliteral -std=gnu17 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-07-02-100350-3577-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-ssh.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

1 | /* packet-ssh.c
2 | * Routines for ssh packet dissection
3 | *
4 | * Huagang XIE <huagang@intruvert.com>
5 | * Kees Cook <kees@outflux.net>
6 | *
7 | * Wireshark - Network traffic analyzer
8 | * By Gerald Combs <gerald@wireshark.org>
9 | * Copyright 1998 Gerald Combs
10 | *
11 | * Copied from packet-mysql.c
12 | *
13 | * SPDX-License-Identifier: GPL-2.0-or-later
14 | *
15 | *
16 | * Note: support SSH v1 and v2 now.
17 | *
18 | */
19 |
20 | /* SSH version 2 is defined in:
21 | *
22 | * RFC 4250: The Secure Shell (SSH) Protocol Assigned Numbers
23 | * RFC 4251: The Secure Shell (SSH) Protocol Architecture
24 | * RFC 4252: The Secure Shell (SSH) Authentication Protocol
25 | * RFC 4253: The Secure Shell (SSH) Transport Layer Protocol
26 | * RFC 4254: The Secure Shell (SSH) Connection Protocol
27 | *
28 | * SSH versions under 2 were never officially standardized.
29 | *
30 | * Diffie-Hellman Group Exchange is defined in:
31 | *
32 | * RFC 4419: Diffie-Hellman Group Exchange for
33 | * the Secure Shell (SSH) Transport Layer Protocol
34 | */
35 |
36 | /* "SSH" prefixes are for version 2, whereas "SSH1" is for version 1 */
37 |
38 | #include "config.h"
39 | #define WS_LOG_DOMAIN"packet-ssh" "packet-ssh"
40 | /* Start with WIRESHARK_LOG_DOMAINS=packet-ssh and WIRESHARK_LOG_LEVEL=debug to see messages. */
41 |
42 | // Define this to get hex dumps more similar to what you get in openssh. If not defined, dumps look more like what you get with other dissectors.
43 | #define OPENSSH_STYLE
44 |
45 | #include <errno(*__errno_location ()).h>
46 |
47 | #include <epan/packet.h>
48 | #include <epan/exceptions.h>
49 | #include <epan/prefs.h>
50 | #include <epan/expert.h>
51 | #include <epan/proto_data.h>
52 | #include <epan/tfs.h>
53 | #include <epan/unit_strings.h>
54 | #include <wsutil/strtoi.h>
55 | #include <wsutil/to_str.h>
56 | #include <wsutil/file_util.h>
57 | #include <wsutil/filesystem.h>
58 | #include <wsutil/wsgcrypt.h>
59 | #include <wsutil/curve25519.h>
60 | #include <wsutil/pint.h>
61 | #include <wsutil/str_util.h>
62 | #include <wsutil/wslog.h>
63 | #include <epan/secrets.h>
64 | #include <wiretap/secrets-types.h>
65 |
66 | #if defined(HAVE_LIBGNUTLS1)
67 | #include <gnutls/abstract.h>
68 | #endif
69 |
70 | #include "packet-tcp.h"
71 | #include "packet-sctp.h"
72 |
73 | void proto_register_ssh(void);
74 | void proto_reg_handoff_ssh(void);
75 |
76 | /* SSH Version 1 definition , from openssh ssh1.h */
77 | #define SSH1_MSG_NONE0 0 /* no message */
78 | #define SSH1_MSG_DISCONNECT1 1 /* cause (string) */
79 | #define SSH1_SMSG_PUBLIC_KEY2 2 /* ck,msk,srvk,hostk */
80 | #define SSH1_CMSG_SESSION_KEY3 3 /* key (BIGNUM) */
81 | #define SSH1_CMSG_USER4 4 /* user (string) */
82 |
83 |
84 | #define SSH_VERSION_UNKNOWN0 0
85 | #define SSH_VERSION_11 1
86 | #define SSH_VERSION_22 2
87 |
88 | /* proto data */
89 |
90 | typedef struct {
91 | uint8_t *data;
92 | unsigned length;
93 | } ssh_bignum;
94 |
95 | #define SSH_KEX_CURVE255190x00010000 0x00010000
96 | #define SSH_KEX_DH_GEX0x00020000 0x00020000
97 | #define SSH_KEX_DH_GROUP10x00030001 0x00030001
98 | #define SSH_KEX_DH_GROUP140x00030014 0x00030014
99 | #define SSH_KEX_DH_GROUP160x00030016 0x00030016
100 | #define SSH_KEX_DH_GROUP180x00030018 0x00030018
101 | #define SSH_KEX_SNTRUP761X255190x00040000 0x00040000
102 | #define SSH_KEX_MLKEM768X255190x00050000 0x00050000
103 |
104 | #define SSH_KEX_HASH_SHA11 1
105 | #define SSH_KEX_HASH_SHA2562 2
106 | #define SSH_KEX_HASH_SHA5124 4
107 |
108 | #define DIGEST_MAX_SIZE48 48
109 |
110 | /* The maximum SSH packet_length accepted. If the packet_length field after
111 | * attempted decryption is larger than this, the packet will be assumed to
112 | * have failed decryption (possibly due to being continuation data).
113 | * (This could be made a preference.)
114 | */
115 | #define SSH_MAX_PACKET_LEN32768 32768
116 |
117 | typedef struct _ssh_message_info_t {
118 | uint32_t sequence_number;
119 | unsigned char *plain_data; /**< Decrypted data. */
120 | unsigned data_len; /**< Length of decrypted data. */
121 | int id; /**< Identifies the exact message within a frame
122 | (there can be multiple records in a frame). */
123 | uint32_t byte_seq;
124 | uint32_t next_byte_seq;
125 | struct _ssh_message_info_t* next;
126 | uint8_t calc_mac[DIGEST_MAX_SIZE48];
127 | } ssh_message_info_t;
128 |
129 | typedef struct {
130 | bool_Bool from_server;
131 | ssh_message_info_t * messages;
132 | } ssh_packet_info_t;
133 |
134 | typedef struct _ssh_channel_info_t {
135 | uint32_t byte_seq;
136 | uint16_t flags;
137 | wmem_tree_t *multisegment_pdus;
138 | dissector_handle_t handle;
139 | } ssh_channel_info_t;
140 |
141 | struct ssh_peer_data {
142 | unsigned counter;
143 |
144 | uint32_t frame_version_start;
145 | uint32_t frame_version_end;
146 |
147 | uint32_t frame_key_start;
148 | uint32_t frame_key_end;
149 | int frame_key_end_offset;
150 |
151 | char* kex_proposal;
152 |
153 | /* For all subsequent proposals,
154 | [0] is client-to-server and [1] is server-to-client. */
155 | #define CLIENT_TO_SERVER_PROPOSAL0 0
156 | #define SERVER_TO_CLIENT_PROPOSAL1 1
157 |
158 | char* mac_proposals[2];
159 | char* mac;
160 | int mac_length;
161 |
162 | char* enc_proposals[2];
163 | char* enc;
164 |
165 | char* comp_proposals[2];
166 | char* comp;
167 |
168 | int length_is_plaintext;
169 |
170 | // see libgcrypt source, gcrypt.h:gcry_cipher_algos
171 | unsigned cipher_id;
172 | unsigned mac_id;
173 | // chacha20 needs two cipher handles
174 | gcry_cipher_hd_t cipher, cipher_2;
175 | unsigned sequence_number;
176 | ssh_bignum *bn_cookie;
177 | uint8_t iv[12];
178 | uint8_t hmac_iv[DIGEST_MAX_SIZE48];
179 | unsigned hmac_iv_len;
180 |
181 | unsigned int rekey_trigger_frame; // for storing new KEXINIT frame value when REKEY
182 | bool_Bool rekey_pending; // trace REKEY
183 | uint8_t plain0[16];
184 | bool_Bool plain0_valid;
185 |
186 | wmem_map_t *channel_info; /**< Map of sender channel numbers to recipient numbers. */
187 | wmem_map_t *channel_handles; /**< Map of recipient channel numbers to subdissector handles. */
188 | struct ssh_flow_data * global_data;
189 | };
190 |
191 | struct ssh_flow_data {
192 | unsigned version;
193 |
194 | /* The address/port of the server */
195 | address srv_addr;
196 | unsigned srv_port;
197 |
198 | char* kex;
199 | int (*kex_specific_dissector)(uint8_t msg_code, tvbuff_t *tvb,
200 | packet_info *pinfo, int offset, proto_tree *tree,
201 | struct ssh_flow_data *global_data);
202 |
203 | /* [0] is client's, [1] is server's */
204 | #define CLIENT_PEER_DATA0 0
205 | #define SERVER_PEER_DATA1 1
206 | struct ssh_peer_data peer_data[2];
207 |
208 | const uint8_t *session_id;
209 | unsigned session_id_length;
210 | ssh_bignum *kex_e;
211 | ssh_bignum *kex_f;
212 | ssh_bignum *kex_gex_p; // Group modulo
213 | ssh_bignum *kex_gex_g; // Group generator
214 | ssh_bignum *secret;
215 | wmem_array_t *kex_client_version;
216 | wmem_array_t *kex_server_version;
217 | wmem_array_t *kex_client_key_exchange_init;
218 | wmem_array_t *kex_server_key_exchange_init;
219 | wmem_array_t *kex_server_host_key_blob;
220 | wmem_array_t *kex_gex_bits_min;
221 | wmem_array_t *kex_gex_bits_req;
222 | wmem_array_t *kex_gex_bits_max;
223 | wmem_array_t *kex_shared_secret;
224 | bool_Bool do_decrypt;
225 | bool_Bool ext_ping_openssh_offered;
226 | bool_Bool ext_kex_strict;
227 | ssh_bignum new_keys[6];
228 | uint8_t *pqkem_ciphertext;
229 | uint32_t pqkem_ciphertext_len;
230 | uint8_t *curve25519_pub;
231 | uint32_t curve25519_pub_len;
232 | // storing PQ dissected keys
233 | uint8_t *kex_e_pq; // binary material => no bignum (not traditional DH integer / not math ready)
234 | uint8_t *kex_f_pq; // binary material => no bignum (not traditional DH integer / not math ready)
235 | uint32_t kex_e_pq_len;
236 | uint32_t kex_f_pq_len;
237 | };
238 |
239 | typedef struct {
240 | char *type; // "PRIVATE_KEY" or "SHARED_SECRET"
241 | ssh_bignum *key_material; // Either private key or shared secret
242 | } ssh_key_map_entry_t;
243 |
244 | static GHashTable * ssh_master_key_map;
245 |
246 | static int proto_ssh;
247 |
248 | /* Version exchange */
249 | static int hf_ssh_protocol;
250 |
251 | /* Framing */
252 | static int hf_ssh_packet_length;
253 | static int hf_ssh_packet_length_encrypted;
254 | static int hf_ssh_padding_length;
255 | static int hf_ssh_payload;
256 | static int hf_ssh_encrypted_packet;
257 | static int hf_ssh_padding_string;
258 | static int hf_ssh_mac_string;
259 | static int hf_ssh_mac_status;
260 | static int hf_ssh_seq_num;
261 | static int hf_ssh_direction;
262 |
263 | /* Message codes */
264 | static int hf_ssh_msg_code;
265 | static int hf_ssh2_msg_code;
266 | static int hf_ssh2_kex_dh_msg_code;
267 | static int hf_ssh2_kex_dh_gex_msg_code;
268 | static int hf_ssh2_kex_ecdh_msg_code;
269 | static int hf_ssh2_kex_hybrid_msg_code;
270 | static int hf_ssh2_ext_ping_msg_code;
271 |
272 | /* Algorithm negotiation */
273 | static int hf_ssh_cookie;
274 | static int hf_ssh_kex_algorithms;
275 | static int hf_ssh_server_host_key_algorithms;
276 | static int hf_ssh_encryption_algorithms_client_to_server;
277 | static int hf_ssh_encryption_algorithms_server_to_client;
278 | static int hf_ssh_mac_algorithms_client_to_server;
279 | static int hf_ssh_mac_algorithms_server_to_client;
280 | static int hf_ssh_compression_algorithms_client_to_server;
281 | static int hf_ssh_compression_algorithms_server_to_client;
282 | static int hf_ssh_languages_client_to_server;
283 | static int hf_ssh_languages_server_to_client;
284 | static int hf_ssh_kex_algorithms_length;
285 | static int hf_ssh_server_host_key_algorithms_length;
286 | static int hf_ssh_encryption_algorithms_client_to_server_length;
287 | static int hf_ssh_encryption_algorithms_server_to_client_length;
288 | static int hf_ssh_mac_algorithms_client_to_server_length;
289 | static int hf_ssh_mac_algorithms_server_to_client_length;
290 | static int hf_ssh_compression_algorithms_client_to_server_length;
291 | static int hf_ssh_compression_algorithms_server_to_client_length;
292 | static int hf_ssh_languages_client_to_server_length;
293 | static int hf_ssh_languages_server_to_client_length;
294 | static int hf_ssh_first_kex_packet_follows;
295 | static int hf_ssh_kex_reserved;
296 | static int hf_ssh_kex_hassh_algo;
297 | static int hf_ssh_kex_hassh;
298 | static int hf_ssh_kex_hasshserver_algo;
299 | static int hf_ssh_kex_hasshserver;
300 |
301 | /* Key exchange common elements */
302 | static int hf_ssh_hostkey_length;
303 | static int hf_ssh_hostkey_type_length;
304 | static int hf_ssh_hostkey_type;
305 | static int hf_ssh_hostkey_data;
306 | static int hf_ssh_hostkey_rsa_n;
307 | static int hf_ssh_hostkey_rsa_e;
308 | static int hf_ssh_hostkey_dsa_p;
309 | static int hf_ssh_hostkey_dsa_q;
310 | static int hf_ssh_hostkey_dsa_g;
311 | static int hf_ssh_hostkey_dsa_y;
312 | static int hf_ssh_hostkey_ecdsa_curve_id;
313 | static int hf_ssh_hostkey_ecdsa_curve_id_length;
314 | static int hf_ssh_hostkey_ecdsa_q;
315 | static int hf_ssh_hostkey_ecdsa_q_length;
316 | static int hf_ssh_hostkey_eddsa_key;
317 | static int hf_ssh_hostkey_eddsa_key_length;
318 | static int hf_ssh_hostsig_length;
319 | static int hf_ssh_hostsig_type_length;
320 | static int hf_ssh_hostsig_type;
321 | static int hf_ssh_hostsig_rsa;
322 | static int hf_ssh_hostsig_dsa;
323 | static int hf_ssh_hostsig_data_length;
324 | static int hf_ssh_hostsig_data;
325 |
326 | /* Key exchange: Diffie-Hellman */
327 | static int hf_ssh_dh_e;
328 | static int hf_ssh_dh_f;
329 |
330 | /* Key exchange: Diffie-Hellman Group Exchange */
331 | static int hf_ssh_dh_gex_min;
332 | static int hf_ssh_dh_gex_nbits;
333 | static int hf_ssh_dh_gex_max;
334 | static int hf_ssh_dh_gex_p;
335 | static int hf_ssh_dh_gex_g;
336 |
337 | /* Key exchange: Elliptic Curve Diffie-Hellman */
338 | static int hf_ssh_ecdh_q_c;
339 | static int hf_ssh_ecdh_q_c_length;
340 | static int hf_ssh_ecdh_q_s;
341 | static int hf_ssh_ecdh_q_s_length;
342 |
343 | /* Key exchange: Post-Quantum Hybrid KEM */
344 | static int hf_ssh_hybrid_blob_client; // client's full PQ blob
345 | static int hf_ssh_hybrid_blob_client_len;
346 | static int hf_ssh_hybrid_blob_server; // server's full PQ blob
347 | static int hf_ssh_hybrid_blob_server_len;
348 | static int hf_ssh_pq_kem_client; // client's PQ public key
349 | static int hf_ssh_pq_kem_server; // server's PQ response
350 |
351 | /* Extension negotiation */
352 | static int hf_ssh_ext_count;
353 | static int hf_ssh_ext_name_length;
354 | static int hf_ssh_ext_name;
355 | static int hf_ssh_ext_value_length;
356 | static int hf_ssh_ext_value;
357 | static int hf_ssh_ext_server_sig_algs_algorithms;
358 | static int hf_ssh_ext_delay_compression_algorithms_client_to_server_length;
359 | static int hf_ssh_ext_delay_compression_algorithms_client_to_server;
360 | static int hf_ssh_ext_delay_compression_algorithms_server_to_client_length;
361 | static int hf_ssh_ext_delay_compression_algorithms_server_to_client;
362 | static int hf_ssh_ext_no_flow_control_value;
363 | static int hf_ssh_ext_elevation_value;
364 | static int hf_ssh_ext_prop_publickey_algorithms_algorithms;
365 |
366 | /* Miscellaneous */
367 | static int hf_ssh_mpint_length;
368 |
369 | static int hf_ssh_ignore_data_length;
370 | static int hf_ssh_ignore_data;
371 | static int hf_ssh_debug_always_display;
372 | static int hf_ssh_debug_message_length;
373 | static int hf_ssh_debug_message;
374 | static int hf_ssh_service_name_length;
375 | static int hf_ssh_service_name;
376 | static int hf_ssh_userauth_user_name_length;
377 | static int hf_ssh_userauth_user_name;
378 | static int hf_ssh_userauth_change_password;
379 | static int hf_ssh_userauth_service_name_length;
380 | static int hf_ssh_userauth_service_name;
381 | static int hf_ssh_userauth_method_name_length;
382 | static int hf_ssh_userauth_method_name;
383 | static int hf_ssh_userauth_have_signature;
384 | static int hf_ssh_userauth_password_length;
385 | static int hf_ssh_userauth_password;
386 | static int hf_ssh_userauth_new_password_length;
387 | static int hf_ssh_userauth_new_password;
388 | static int hf_ssh_auth_failure_list_length;
389 | static int hf_ssh_auth_failure_list;
390 | static int hf_ssh_userauth_partial_success;
391 | static int hf_ssh_userauth_pka_name_len;
392 | static int hf_ssh_userauth_pka_name;
393 | static int hf_ssh_pk_blob_name_length;
394 | static int hf_ssh_pk_blob_name;
395 | static int hf_ssh_blob_length;
396 | static int hf_ssh_signature_length;
397 | static int hf_ssh_pk_sig_blob_name_length;
398 | static int hf_ssh_pk_sig_blob_name;
399 | static int hf_ssh_connection_type_name_len;
400 | static int hf_ssh_connection_type_name;
401 | static int hf_ssh_connection_sender_channel;
402 | static int hf_ssh_connection_recipient_channel;
403 | static int hf_ssh_connection_initial_window;
404 | static int hf_ssh_connection_maximum_packet_size;
405 | static int hf_ssh_global_request_name_len;
406 | static int hf_ssh_global_request_name;
407 | static int hf_ssh_global_request_want_reply;
408 | static int hf_ssh_global_request_hostkeys_array_len;
409 | static int hf_ssh_channel_request_name_len;
410 | static int hf_ssh_channel_request_name;
411 | static int hf_ssh_channel_request_want_reply;
412 | static int hf_ssh_subsystem_name_len;
413 | static int hf_ssh_subsystem_name;
414 | static int hf_ssh_exec_cmd;
415 | static int hf_ssh_env_name;
416 | static int hf_ssh_env_value;
417 | static int hf_ssh_pty_term;
418 | static int hf_ssh_pty_term_width_char;
419 | static int hf_ssh_pty_term_height_row;
420 | static int hf_ssh_pty_term_width_pixel;
421 | static int hf_ssh_pty_term_height_pixel;
422 | static int hf_ssh_pty_term_modes_len;
423 | static int hf_ssh_pty_term_modes;
424 | static int hf_ssh_pty_term_mode;
425 | static int hf_ssh_pty_term_mode_opcode;
426 | static int hf_ssh_pty_term_mode_vintr;
427 | static int hf_ssh_pty_term_mode_vquit;
428 | static int hf_ssh_pty_term_mode_verase;
429 | static int hf_ssh_pty_term_mode_vkill;
430 | static int hf_ssh_pty_term_mode_veof;
431 | static int hf_ssh_pty_term_mode_veol;
432 | static int hf_ssh_pty_term_mode_veol2;
433 | static int hf_ssh_pty_term_mode_vstart;
434 | static int hf_ssh_pty_term_mode_vstop;
435 | static int hf_ssh_pty_term_mode_vsusp;
436 | static int hf_ssh_pty_term_mode_vdsusp;
437 | static int hf_ssh_pty_term_mode_vreprint;
438 | static int hf_ssh_pty_term_mode_vwerase;
439 | static int hf_ssh_pty_term_mode_vlnext;
440 | static int hf_ssh_pty_term_mode_vflush;
441 | static int hf_ssh_pty_term_mode_vswtch;
442 | static int hf_ssh_pty_term_mode_vstatus;
443 | static int hf_ssh_pty_term_mode_vdiscard;
444 | static int hf_ssh_pty_term_mode_ignpar;
445 | static int hf_ssh_pty_term_mode_parmrk;
446 | static int hf_ssh_pty_term_mode_inpck;
447 | static int hf_ssh_pty_term_mode_istrip;
448 | static int hf_ssh_pty_term_mode_inlcr;
449 | static int hf_ssh_pty_term_mode_igncr;
450 | static int hf_ssh_pty_term_mode_icrnl;
451 | static int hf_ssh_pty_term_mode_iuclc;
452 | static int hf_ssh_pty_term_mode_ixon;
453 | static int hf_ssh_pty_term_mode_ixany;
454 | static int hf_ssh_pty_term_mode_ixoff;
455 | static int hf_ssh_pty_term_mode_imaxbel;
456 | static int hf_ssh_pty_term_mode_iutf8;
457 | static int hf_ssh_pty_term_mode_isig;
458 | static int hf_ssh_pty_term_mode_icanon;
459 | static int hf_ssh_pty_term_mode_xcase;
460 | static int hf_ssh_pty_term_mode_echo;
461 | static int hf_ssh_pty_term_mode_echoe;
462 | static int hf_ssh_pty_term_mode_echok;
463 | static int hf_ssh_pty_term_mode_echonl;
464 | static int hf_ssh_pty_term_mode_noflsh;
465 | static int hf_ssh_pty_term_mode_tostop;
466 | static int hf_ssh_pty_term_mode_iexten;
467 | static int hf_ssh_pty_term_mode_echoctl;
468 | static int hf_ssh_pty_term_mode_echoke;
469 | static int hf_ssh_pty_term_mode_pendin;
470 | static int hf_ssh_pty_term_mode_opost;
471 | static int hf_ssh_pty_term_mode_olcuc;
472 | static int hf_ssh_pty_term_mode_onlcr;
473 | static int hf_ssh_pty_term_mode_ocrnl;
474 | static int hf_ssh_pty_term_mode_onocr;
475 | static int hf_ssh_pty_term_mode_onlret;
476 | static int hf_ssh_pty_term_mode_cs7;
477 | static int hf_ssh_pty_term_mode_cs8;
478 | static int hf_ssh_pty_term_mode_parenb;
479 | static int hf_ssh_pty_term_mode_parodd;
480 | static int hf_ssh_pty_term_mode_ispeed;
481 | static int hf_ssh_pty_term_mode_ospeed;
482 | static int hf_ssh_pty_term_mode_value;
483 | static int hf_ssh_channel_window_adjust;
484 | static int hf_ssh_channel_data_len;
485 | static int hf_ssh_channel_data_type_code;
486 | static int hf_ssh_exit_status;
487 | static int hf_ssh_disconnect_reason;
488 | static int hf_ssh_disconnect_description_length;
489 | static int hf_ssh_disconnect_description;
490 | static int hf_ssh_lang_tag_length;
491 | static int hf_ssh_lang_tag;
492 | static int hf_ssh_ping_data_length;
493 | static int hf_ssh_ping_data;
494 | static int hf_ssh_pong_data_length;
495 | static int hf_ssh_pong_data;
496 |
497 | static int hf_ssh_blob;
498 | static int hf_ssh_blob_e;
499 | static int hf_ssh_blob_n;
500 | static int hf_ssh_blob_dsa_p;
501 | static int hf_ssh_blob_dsa_q;
502 | static int hf_ssh_blob_dsa_g;
503 | static int hf_ssh_blob_dsa_y;
504 | static int hf_ssh_blob_ecdsa_curve_id;
505 | static int hf_ssh_blob_ecdsa_curve_id_length;
506 | static int hf_ssh_blob_ecdsa_q;
507 | static int hf_ssh_blob_ecdsa_q_length;
508 | static int hf_ssh_blob_eddsa_key;
509 | static int hf_ssh_blob_eddsa_key_length;
510 | static int hf_ssh_blob_data;
511 |
512 | static int hf_ssh_pk_sig_s_length;
513 | static int hf_ssh_pk_sig_s;
514 |
515 | static int hf_ssh_reassembled_in;
516 | static int hf_ssh_reassembled_length;
517 | static int hf_ssh_reassembled_data;
518 | static int hf_ssh_segments;
519 | static int hf_ssh_segment;
520 | static int hf_ssh_segment_overlap;
521 | static int hf_ssh_segment_overlap_conflict;
522 | static int hf_ssh_segment_multiple_tails;
523 | static int hf_ssh_segment_too_long_fragment;
524 | static int hf_ssh_segment_error;
525 | static int hf_ssh_segment_count;
526 | static int hf_ssh_segment_data;
527 |
528 | static int ett_ssh;
529 | static int ett_key_exchange;
530 | static int ett_key_exchange_host_key;
531 | static int ett_key_exchange_host_sig;
532 | static int ett_extension;
533 | static int ett_userauth_pk_blob;
534 | static int ett_userauth_pk_signature;
535 | static int ett_term_modes;
536 | static int ett_term_mode;
537 | static int ett_key_init;
538 | static int ett_ssh1;
539 | static int ett_ssh2;
540 | static int ett_ssh_segments;
541 | static int ett_ssh_segment;
542 | static int ett_ssh_pqhybrid_client;
543 | static int ett_ssh_pqhybrid_server;
544 |
545 | static expert_field ei_ssh_packet_length;
546 | static expert_field ei_ssh_padding_length;
547 | static expert_field ei_ssh_packet_decode;
548 | static expert_field ei_ssh_channel_number;
549 | static expert_field ei_ssh_invalid_keylen;
550 | static expert_field ei_ssh_mac_bad;
551 | static expert_field ei_ssh2_kex_hybrid_msg_code;
552 | static expert_field ei_ssh2_kex_hybrid_msg_code_unknown;
553 |
554 | static bool_Bool ssh_desegment = true1;
555 | static bool_Bool ssh_ignore_mac_failed;
556 |
557 | static dissector_handle_t ssh_handle;
558 | static dissector_handle_t sftp_handle;
559 | static dissector_handle_t data_text_lines_handle;
560 |
561 | static const char *pref_keylog_file;
562 | static FILE *ssh_keylog_file;
563 |
564 | static reassembly_table ssh_reassembly_table;
565 |
566 | static const fragment_items ssh_segment_items = {
567 | &ett_ssh_segment,
568 | &ett_ssh_segments,
569 | &hf_ssh_segments,
570 | &hf_ssh_segment,
571 | &hf_ssh_segment_overlap,
572 | &hf_ssh_segment_overlap_conflict,
573 | &hf_ssh_segment_multiple_tails,
574 | &hf_ssh_segment_too_long_fragment,
575 | &hf_ssh_segment_error,
576 | &hf_ssh_segment_count,
577 | &hf_ssh_reassembled_in,
578 | &hf_ssh_reassembled_length,
579 | &hf_ssh_reassembled_data,
580 | "Segments"
581 | };
582 |
583 | #define SSH_DECRYPT_DEBUG
584 |
585 | #ifdef SSH_DECRYPT_DEBUG
586 | static const char *ssh_debug_file_name;
587 | #endif
588 |
589 | #define TCP_RANGE_SSH"22" "22"
590 | #define SCTP_PORT_SSH22 22
591 |
592 | /* Message Numbers (from RFC 4250) (1-255) */
593 |
594 | /* Transport layer protocol: generic (1-19) */
595 | #define SSH_MSG_DISCONNECT1 1
596 | #define SSH_MSG_IGNORE2 2
597 | #define SSH_MSG_UNIMPLEMENTED3 3
598 | #define SSH_MSG_DEBUG4 4
599 | #define SSH_MSG_SERVICE_REQUEST5 5
600 | #define SSH_MSG_SERVICE_ACCEPT6 6
601 | #define SSH_MSG_EXT_INFO7 7
602 | #define SSH_MSG_NEWCOMPRESS8 8
603 |
604 | /* Transport layer protocol: Algorithm negotiation (20-29) */
605 | #define SSH_MSG_KEXINIT20 20
606 | #define SSH_MSG_NEWKEYS21 21
607 |
608 | /* Transport layer: Key exchange method specific (reusable) (30-49) */
609 | #define SSH_MSG_KEXDH_INIT30 30
610 | #define SSH_MSG_KEXDH_REPLY31 31
611 |
612 | #define SSH_MSG_KEX_DH_GEX_REQUEST_OLD30 30
613 | #define SSH_MSG_KEX_DH_GEX_GROUP31 31
614 | #define SSH_MSG_KEX_DH_GEX_INIT32 32
615 | #define SSH_MSG_KEX_DH_GEX_REPLY33 33
616 | #define SSH_MSG_KEX_DH_GEX_REQUEST34 34
617 |
618 | #define SSH_MSG_KEX_ECDH_INIT30 30
619 | #define SSH_MSG_KEX_ECDH_REPLY31 31
620 |
621 | #define SSH_MSG_KEX_HYBRID_INIT30 30
622 | #define SSH_MSG_KEX_HYBRID_REPLY31 31
623 |
624 | /* User authentication protocol: generic (50-59) */
625 | #define SSH_MSG_USERAUTH_REQUEST50 50
626 | #define SSH_MSG_USERAUTH_FAILURE51 51
627 | #define SSH_MSG_USERAUTH_SUCCESS52 52
628 | #define SSH_MSG_USERAUTH_BANNER53 53
629 |
630 | /* User authentication protocol: method specific (reusable) (50-79) */
631 | #define SSH_MSG_USERAUTH_PK_OK60 60
632 |
633 | /* Connection protocol: generic (80-89) */
634 | #define SSH_MSG_GLOBAL_REQUEST80 80
635 | #define SSH_MSG_REQUEST_SUCCESS81 81
636 | #define SSH_MSG_REQUEST_FAILURE82 82
637 |
638 | /* Connection protocol: channel related messages (90-127) */
639 | #define SSH_MSG_CHANNEL_OPEN90 90
640 | #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION91 91
641 | #define SSH_MSG_CHANNEL_OPEN_FAILURE92 92
642 | #define SSH_MSG_CHANNEL_WINDOW_ADJUST93 93
643 | #define SSH_MSG_CHANNEL_DATA94 94
644 | #define SSH_MSG_CHANNEL_EXTENDED_DATA95 95
645 | #define SSH_MSG_CHANNEL_EOF96 96
646 | #define SSH_MSG_CHANNEL_CLOSE97 97
647 | #define SSH_MSG_CHANNEL_REQUEST98 98
648 | #define SSH_MSG_CHANNEL_SUCCESS99 99
649 | #define SSH_MSG_CHANNEL_FAILURE100 100
650 |
651 | /* 128-191 reserved for client protocols */
652 | /* 192-255 local extensions */
653 | #define SSH_MSG_PING192 192
654 | #define SSH_MSG_PONG193 193
655 |
656 | #define CIPHER_AES128_CTR0x00010001 0x00010001
657 | #define CIPHER_AES192_CTR0x00010003 0x00010003
658 | #define CIPHER_AES256_CTR0x00010004 0x00010004
659 | #define CIPHER_AES128_CBC0x00020001 0x00020001
660 | #define CIPHER_AES192_CBC0x00020002 0x00020002
661 | #define CIPHER_AES256_CBC0x00020004 0x00020004
662 | #define CIPHER_AES128_GCM0x00040001 0x00040001
663 | //#define CIPHER_AES192_GCM 0x00040002 -- does not exist
664 | #define CIPHER_AES256_GCM0x00040004 0x00040004
665 | // DO NOT USE 0x00040000 (used by SSH_KEX_SNTRUP761X25519)
666 | #define CIPHER_NULL0x00080000 0x00080000
667 |
668 | #define CIPHER_MAC_SHA2_2560x00020001 0x00020001
669 |
670 | #define SSH_EXTENDED_DATA_STDERR1 1
671 |
672 | #define SSH_TTY_OP_END0 0
673 | #define SSH_TTY_OP_VINTR1 1
674 | #define SSH_TTY_OP_VQUIT2 2
675 | #define SSH_TTY_OP_VERASE3 3
676 | #define SSH_TTY_OP_VKILL4 4
677 | #define SSH_TTY_OP_VEOF5 5
678 | #define SSH_TTY_OP_VEOL6 6
679 | #define SSH_TTY_OP_VEOL27 7
680 | #define SSH_TTY_OP_VSTART8 8
681 | #define SSH_TTY_OP_VSTOP9 9
682 | #define SSH_TTY_OP_VSUSP10 10
683 | #define SSH_TTY_OP_VDSUSP11 11
684 | #define SSH_TTY_OP_VREPRINT12 12
685 | #define SSH_TTY_OP_VWERASE13 13
686 | #define SSH_TTY_OP_VLNEXT14 14
687 | #define SSH_TTY_OP_VFLUSH15 15
688 | #define SSH_TTY_OP_VSWTCH16 16
689 | #define SSH_TTY_OP_VSTATUS17 17
690 | #define SSH_TTY_OP_VDISCARD18 18
691 | #define SSH_TTY_OP_IGNPAR30 30
692 | #define SSH_TTY_OP_PARMRK31 31
693 | #define SSH_TTY_OP_INPCK32 32
694 | #define SSH_TTY_OP_ISTRIP33 33
695 | #define SSH_TTY_OP_INLCR34 34
696 | #define SSH_TTY_OP_IGNCR35 35
697 | #define SSH_TTY_OP_ICRNL36 36
698 | #define SSH_TTY_OP_IUCLC37 37
699 | #define SSH_TTY_OP_IXON38 38
700 | #define SSH_TTY_OP_IXANY39 39
701 | #define SSH_TTY_OP_IXOFF40 40
702 | #define SSH_TTY_OP_IMAXBEL41 41
703 | #define SSH_TTY_OP_IUTF842 42
704 | #define SSH_TTY_OP_ISIG50 50
705 | #define SSH_TTY_OP_ICANON51 51
706 | #define SSH_TTY_OP_XCASE52 52
707 | #define SSH_TTY_OP_ECHO53 53
708 | #define SSH_TTY_OP_ECHOE54 54
709 | #define SSH_TTY_OP_ECHOK55 55
710 | #define SSH_TTY_OP_ECHONL56 56
711 | #define SSH_TTY_OP_NOFLSH57 57
712 | #define SSH_TTY_OP_TOSTOP58 58
713 | #define SSH_TTY_OP_IEXTEN59 59
714 | #define SSH_TTY_OP_ECHOCTL60 60
715 | #define SSH_TTY_OP_ECHOKE61 61
716 | #define SSH_TTY_OP_PENDIN62 62
717 | #define SSH_TTY_OP_OPOST70 70
718 | #define SSH_TTY_OP_OLCUC71 71
719 | #define SSH_TTY_OP_ONLCR72 72
720 | #define SSH_TTY_OP_OCRNL73 73
721 | #define SSH_TTY_OP_ONOCR74 74
722 | #define SSH_TTY_OP_ONLRET75 75
723 | #define SSH_TTY_OP_CS790 90
724 | #define SSH_TTY_OP_CS891 91
725 | #define SSH_TTY_OP_PARENB92 92
726 | #define SSH_TTY_OP_PARODD93 93
727 | #define SSH_TTY_OP_ISPEED128 128
728 | #define SSH_TTY_OP_OSPEED129 129
729 |
730 | static const value_string ssh2_msg_vals[] = {
731 | { SSH_MSG_DISCONNECT1, "Disconnect" },
732 | { SSH_MSG_IGNORE2, "Ignore" },
733 | { SSH_MSG_UNIMPLEMENTED3, "Unimplemented" },
734 | { SSH_MSG_DEBUG4, "Debug" },
735 | { SSH_MSG_SERVICE_REQUEST5, "Service Request" },
736 | { SSH_MSG_SERVICE_ACCEPT6, "Service Accept" },
737 | { SSH_MSG_EXT_INFO7, "Extension Information" },
738 | { SSH_MSG_NEWCOMPRESS8, "New Compression" },
739 | { SSH_MSG_KEXINIT20, "Key Exchange Init" },
740 | { SSH_MSG_NEWKEYS21, "New Keys" },
741 | { SSH_MSG_USERAUTH_REQUEST50, "User Authentication Request" },
742 | { SSH_MSG_USERAUTH_FAILURE51, "User Authentication Failure" },
743 | { SSH_MSG_USERAUTH_SUCCESS52, "User Authentication Success" },
744 | { SSH_MSG_USERAUTH_BANNER53, "User Authentication Banner" },
745 | { SSH_MSG_GLOBAL_REQUEST80, "Global Request" },
746 | { SSH_MSG_REQUEST_SUCCESS81, "Request Success" },
747 | { SSH_MSG_REQUEST_FAILURE82, "Request Failure" },
748 | { SSH_MSG_CHANNEL_OPEN90, "Channel Open" },
749 | { SSH_MSG_CHANNEL_OPEN_CONFIRMATION91, "Channel Open Confirmation" },
750 | { SSH_MSG_CHANNEL_OPEN_FAILURE92, "Channel Open Failure" },
751 | { SSH_MSG_CHANNEL_WINDOW_ADJUST93, "Window Adjust" },
752 | { SSH_MSG_CHANNEL_DATA94, "Channel Data" },
753 | { SSH_MSG_CHANNEL_EXTENDED_DATA95, "Channel Extended Data" },
754 | { SSH_MSG_CHANNEL_EOF96, "Channel EOF" },
755 | { SSH_MSG_CHANNEL_CLOSE97, "Channel Close" },
756 | { SSH_MSG_CHANNEL_REQUEST98, "Channel Request" },
757 | { SSH_MSG_CHANNEL_SUCCESS99, "Channel Success" },
758 | { SSH_MSG_CHANNEL_FAILURE100, "Channel Failure" },
759 | { SSH_MSG_USERAUTH_PK_OK60, "Public Key algorithm accepted" },
760 | { 0, NULL((void*)0) }
761 | };
762 |
763 | static const value_string ssh2_kex_dh_msg_vals[] = {
764 | { SSH_MSG_KEXDH_INIT30, "Diffie-Hellman Key Exchange Init" },
765 | { SSH_MSG_KEXDH_REPLY31, "Diffie-Hellman Key Exchange Reply" },
766 | { 0, NULL((void*)0) }
767 | };
768 |
769 | static const value_string ssh2_kex_dh_gex_msg_vals[] = {
770 | { SSH_MSG_KEX_DH_GEX_REQUEST_OLD30, "Diffie-Hellman Group Exchange Request (Old)" },
771 | { SSH_MSG_KEX_DH_GEX_GROUP31, "Diffie-Hellman Group Exchange Group" },
772 | { SSH_MSG_KEX_DH_GEX_INIT32, "Diffie-Hellman Group Exchange Init" },
773 | { SSH_MSG_KEX_DH_GEX_REPLY33, "Diffie-Hellman Group Exchange Reply" },
774 | { SSH_MSG_KEX_DH_GEX_REQUEST34, "Diffie-Hellman Group Exchange Request" },
775 | { 0, NULL((void*)0) }
776 | };
777 |
778 | static const value_string ssh2_kex_ecdh_msg_vals[] = {
779 | { SSH_MSG_KEX_ECDH_INIT30, "Elliptic Curve Diffie-Hellman Key Exchange Init" },
780 | { SSH_MSG_KEX_ECDH_REPLY31, "Elliptic Curve Diffie-Hellman Key Exchange Reply" },
781 | { 0, NULL((void*)0) }
782 | };
783 |
784 | static const value_string ssh2_kex_hybrid_msg_vals[] = {
785 | { SSH_MSG_KEX_HYBRID_INIT30, "PQ/T Hybrid Key Exchange Init" },
786 | { SSH_MSG_KEX_HYBRID_REPLY31, "PQ/T Hybrid Key Exchange Reply" },
787 | { 0, NULL((void*)0) }
788 | };
789 |
790 | static const value_string ssh2_ext_ping_msg_vals[] = {
791 | { SSH_MSG_PING192, "Ping" },
792 | { SSH_MSG_PONG193, "Pong" },
793 | { 0, NULL((void*)0) }
794 | };
795 |
796 | static const value_string ssh1_msg_vals[] = {
797 | {SSH1_MSG_NONE0, "No Message"},
798 | {SSH1_MSG_DISCONNECT1, "Disconnect"},
799 | {SSH1_SMSG_PUBLIC_KEY2, "Public Key"},
800 | {SSH1_CMSG_SESSION_KEY3, "Session Key"},
801 | {SSH1_CMSG_USER4, "User"},
802 | {0, NULL((void*)0)}
803 | };
804 |
805 | static const value_string ssh_channel_data_type_code_vals[] = {
806 | { SSH_EXTENDED_DATA_STDERR1, "Standard Error" },
807 | { 0, NULL((void*)0) }
808 | };
809 |
810 | static const value_string ssh_tty_op_vals[] = {
811 | { SSH_TTY_OP_END0, "TTY_OP_END" }, // [RFC4250]
812 | { SSH_TTY_OP_VINTR1, "VINTR" }, // [RFC4254],Section 8
813 | { SSH_TTY_OP_VQUIT2, "VQUIT" }, // [RFC4254],Section 8
814 | { SSH_TTY_OP_VERASE3, "VERASE" }, // [RFC4254],Section 8
815 | { SSH_TTY_OP_VKILL4, "VKILL" }, // [RFC4254], Section 8
816 | { SSH_TTY_OP_VEOF5, "VEOF" }, // [RFC4254],Section 8
817 | { SSH_TTY_OP_VEOL6, "VEOL" }, // [RFC4254],Section 8
818 | { SSH_TTY_OP_VEOL27, "VEOL2" }, // [RFC4254], Section 8
819 | { SSH_TTY_OP_VSTART8, "VSTART" }, // [RFC4254],Section 8
820 | { SSH_TTY_OP_VSTOP9, "VSTOP" }, // [RFC4254], Section 8
821 | { SSH_TTY_OP_VSUSP10, "VSUSP" }, // [RFC4254], Section 8
822 | { SSH_TTY_OP_VDSUSP11, "VDSUSP" }, // [RFC4254], Section 8
823 | { SSH_TTY_OP_VREPRINT12, "VREPRINT" }, // [RFC4254], Section 8
824 | { SSH_TTY_OP_VWERASE13, "VWERASE" }, // [RFC4254], Section 8
825 | { SSH_TTY_OP_VLNEXT14, "VLNEXT" }, // [RFC4254],Section 8
826 | { SSH_TTY_OP_VFLUSH15, "VFLUSH" }, // [RFC4254], Section 8
827 | { SSH_TTY_OP_VSWTCH16, "VSWTCH" }, // [RFC4254], Section 8
828 | { SSH_TTY_OP_VSTATUS17, "VSTATUS" }, // [RFC4254],Section 8
829 | { SSH_TTY_OP_VDISCARD18, "VDISCARD" }, // [RFC4254], Section 8
830 | { SSH_TTY_OP_IGNPAR30, "IGNPAR" }, // [RFC4254],Section 8
831 | { SSH_TTY_OP_PARMRK31, "PARMRK" }, // [RFC4254], Section 8
832 | { SSH_TTY_OP_INPCK32, "INPCK" }, // [RFC4254], Section 8
833 | { SSH_TTY_OP_ISTRIP33, "ISTRIP" }, // [RFC4254], Section 8
834 | { SSH_TTY_OP_INLCR34, "INLCR" }, // [RFC4254], Section 8
835 | { SSH_TTY_OP_IGNCR35, "IGNCR" }, // [RFC4254], Section 8
836 | { SSH_TTY_OP_ICRNL36, "ICRNL" }, // [RFC4254], Section 8
837 | { SSH_TTY_OP_IUCLC37, "IUCLC" }, // [RFC4254],Section 8
838 | { SSH_TTY_OP_IXON38, "IXON" }, // [RFC4254], Section 8
839 | { SSH_TTY_OP_IXANY39, "IXANY" }, // [RFC4254], Section 8
840 | { SSH_TTY_OP_IXOFF40, "IXOFF" }, // [RFC4254], Section 8
841 | { SSH_TTY_OP_IMAXBEL41, "IMAXBEL" }, // [RFC4254], Section 8
842 | { SSH_TTY_OP_IUTF842, "IUTF8" }, // [RFC8160],
843 | { SSH_TTY_OP_ISIG50, "ISIG" }, // [RFC4254], Section 8
844 | { SSH_TTY_OP_ICANON51, "ICANON" }, // [RFC4254], Section 8
845 | { SSH_TTY_OP_XCASE52, "XCASE" }, // [RFC4254],Section 8
846 | { SSH_TTY_OP_ECHO53, "ECHO" }, // [RFC4254], Section 8
847 | { SSH_TTY_OP_ECHOE54, "ECHOE" }, // [RFC4254], Section 8
848 | { SSH_TTY_OP_ECHOK55, "ECHOK" }, // [RFC4254], Section 8
849 | { SSH_TTY_OP_ECHONL56, "ECHONL" }, // [RFC4254], Section 8
850 | { SSH_TTY_OP_NOFLSH57, "NOFLSH" }, // [RFC4254],Section 8
851 | { SSH_TTY_OP_TOSTOP58, "TOSTOP" }, // [RFC4254], Section 8
852 | { SSH_TTY_OP_IEXTEN59, "IEXTEN" }, // [RFC4254], Section 8
853 | { SSH_TTY_OP_ECHOCTL60, "ECHOCTL" }, // [RFC4254], Section 8
854 | { SSH_TTY_OP_ECHOKE61, "ECHOKE" }, // [RFC4254], Section 8
855 | { SSH_TTY_OP_PENDIN62, "PENDIN" }, // [RFC4254], Section 8
856 | { SSH_TTY_OP_OPOST70, "OPOST" }, // [RFC4254], Section 8
857 | { SSH_TTY_OP_OLCUC71, "OLCUC" }, // [RFC4254], Section 8
858 | { SSH_TTY_OP_ONLCR72, "ONLCR" }, // [RFC4254], Section 8
859 | { SSH_TTY_OP_OCRNL73, "OCRNL" }, // [RFC4254],Section 8
860 | { SSH_TTY_OP_ONOCR74, "ONOCR" }, // [RFC4254],Section 8
861 | { SSH_TTY_OP_ONLRET75, "ONLRET" }, // [RFC4254],Section 8
862 | { SSH_TTY_OP_CS790, "CS7" }, // [RFC4254], Section 8
863 | { SSH_TTY_OP_CS891, "CS8" }, // [RFC4254], Section 8
864 | { SSH_TTY_OP_PARENB92, "PARENB" }, // [RFC4254], Section 8
865 | { SSH_TTY_OP_PARODD93, "PARODD" }, // [RFC4254], Section 8
866 | { SSH_TTY_OP_ISPEED128, "TTY_OP_ISPEED" }, // [RFC4254],Section 8
867 | { SSH_TTY_OP_OSPEED129, "TTY_OP_OSPEED" }, // [RFC4254],Section 8
868 | { 0, NULL((void*)0) }
869 | };
870 |
871 | static int ssh_dissect_key_init(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *tree,
872 | int is_response,
873 | struct ssh_flow_data *global_data);
874 | static int ssh_dissect_proposal(tvbuff_t *tvb, int offset, proto_tree *tree,
875 | int hf_index_length, int hf_index_value, char **store);
876 | static int ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
877 | struct ssh_flow_data *global_data,
878 | int offset, proto_tree *tree, int is_response,
879 | bool_Bool *need_desegmentation);
880 | static int ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
881 | struct ssh_flow_data *global_data,
882 | int offset, proto_tree *tree, int is_response,
883 | bool_Bool *need_desegmentation);
884 | static int ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
885 | struct ssh_flow_data *global_data,
886 | int offset, proto_tree *tree, int is_response,
887 | bool_Bool *need_desegmentation);
888 | static int ssh_dissect_kex_dh(uint8_t msg_code, tvbuff_t *tvb,
889 | packet_info *pinfo, int offset, proto_tree *tree,
890 | struct ssh_flow_data *global_data);
891 | static int ssh_dissect_kex_dh_gex(uint8_t msg_code, tvbuff_t *tvb,
892 | packet_info *pinfo, int offset, proto_tree *tree,
893 | struct ssh_flow_data *global_data);
894 | static int ssh_dissect_kex_ecdh(uint8_t msg_code, tvbuff_t *tvb,
895 | packet_info *pinfo, int offset, proto_tree *tree,
896 | struct ssh_flow_data *global_data);
897 | static int ssh_dissect_kex_pq_hybrid(uint8_t msg_code, tvbuff_t *tvb,
898 | packet_info *pinfo, int offset, proto_tree *tree,
899 | struct ssh_flow_data *global_data);
900 | static int // add support of client PQ hybrid key (e)
901 | ssh_read_e_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data);
902 | static int // add support of server PQ hybrid key (f)
903 | ssh_read_f_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data);
904 | static int ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
905 | struct ssh_flow_data *global_data,
906 | unsigned offset, proto_tree *tree, int is_response, unsigned *version,
907 | bool_Bool *need_desegmentation);
908 | static int ssh_try_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
909 | struct ssh_peer_data *peer_data, int offset, proto_tree *tree);
910 | static int ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
911 | struct ssh_peer_data *peer_data,
912 | int offset, proto_tree *tree);
913 | static bool_Bool ssh_choose_algo(char *client, char *server, char **result);
914 | static void ssh_set_mac_length(struct ssh_peer_data *peer_data);
915 | static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data);
916 |
917 | static void ssh_keylog_read_file(void);
918 | static void ssh_keylog_process_line(const char *line);
919 | static void ssh_keylog_process_lines(const uint8_t *data, unsigned datalen);
920 | static void ssh_keylog_reset(void);
921 | static ssh_bignum *ssh_kex_make_bignum(const uint8_t *data, unsigned length);
922 | static bool_Bool ssh_read_e(tvbuff_t *tvb, int offset,
923 | struct ssh_flow_data *global_data);
924 | static bool_Bool ssh_read_f(tvbuff_t *tvb, int offset,
925 | struct ssh_flow_data *global_data);
926 | static ssh_bignum * ssh_read_mpint(tvbuff_t *tvb, int offset);
927 | static void ssh_keylog_hash_write_secret(struct ssh_flow_data *global_data, wmem_allocator_t* tmp_allocator);
928 | static ssh_bignum *ssh_kex_shared_secret(int kex_type, ssh_bignum *pub, ssh_bignum *priv, ssh_bignum *modulo);
929 | static void ssh_hash_buffer_put_string(wmem_array_t *buffer, const uint8_t *string,
930 | unsigned len);
931 | static void ssh_hash_buffer_put_uint32(wmem_array_t *buffer, unsigned val);
932 | static char *ssh_string(wmem_allocator_t* allocator, const uint8_t *string, unsigned len);
933 | static void ssh_derive_symmetric_keys(ssh_bignum *shared_secret,
934 | uint8_t *exchange_hash, unsigned hash_length,
935 | struct ssh_flow_data *global_data);
936 | static void ssh_derive_symmetric_key(ssh_bignum *shared_secret,
937 | const uint8_t *exchange_hash, unsigned hash_length, char id,
938 | ssh_bignum *result_key, struct ssh_flow_data *global_data, unsigned we_need);
939 |
940 | static void ssh_choose_enc_mac(struct ssh_flow_data *global_data);
941 | static void ssh_decryption_set_cipher_id(struct ssh_peer_data *peer);
942 | static void ssh_decryption_setup_cipher(struct ssh_peer_data *peer,
943 | ssh_bignum *iv, ssh_bignum *key);
944 | static void ssh_decryption_set_mac_id(struct ssh_peer_data *peer);
945 | static void ssh_decryption_setup_mac(struct ssh_peer_data *peer,
946 | ssh_bignum *iv);
947 | static ssh_packet_info_t* ssh_get_packet_info(packet_info *pinfo, bool_Bool is_response);
948 | static ssh_message_info_t* ssh_get_message(packet_info *pinfo, int record_id);
949 | static unsigned ssh_decrypt_packet(tvbuff_t *tvb, packet_info *pinfo,
950 | struct ssh_peer_data *peer_data, int offset);
951 | static bool_Bool ssh_decrypt_chacha20(gcry_cipher_hd_t hd, uint32_t seqnr,
952 | uint32_t counter, const unsigned char *ctext, unsigned ctext_len,
953 | unsigned char *plain, unsigned plain_len);
954 | static int ssh_dissect_decrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
955 | struct ssh_peer_data *peer_data, proto_tree *tree,
956 | ssh_message_info_t *message);
957 | static int ssh_dissect_transport_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
958 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code);
959 | static int ssh_dissect_rfc8308_extension(tvbuff_t *packet_tvb, packet_info *pinfo,
960 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree);
961 | static int ssh_dissect_userauth_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
962 | int offset, proto_item *msg_type_tree, unsigned msg_code);
963 | static int ssh_dissect_userauth_specific(tvbuff_t *packet_tvb, packet_info *pinfo,
964 | int offset, proto_item *msg_type_tree, unsigned msg_code);
965 | static int ssh_dissect_connection_specific(tvbuff_t *packet_tvb, packet_info *pinfo,
966 | struct ssh_peer_data *peer_data, int offset, proto_item *msg_type_tree,
967 | unsigned msg_code, ssh_message_info_t *message);
968 | static int ssh_dissect_connection_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
969 | int offset, proto_item *msg_type_tree, unsigned msg_code);
970 | static int ssh_dissect_local_extension(tvbuff_t *packet_tvb, packet_info *pinfo,
971 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code);
972 | static int ssh_dissect_public_key_blob(tvbuff_t *tvb, packet_info *pinfo,
973 | proto_item *msg_type_tree);
974 | static int ssh_dissect_public_key_signature(tvbuff_t *packet_tvb, packet_info *pinfo,
975 | int offset, proto_item *msg_type_tree);
976 |
977 | static void create_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, uint32_t sender_channel);
978 | static ssh_channel_info_t* get_channel_info_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel);
979 | static void set_subdissector_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, const char* subsystem_name);
980 |
981 | #define SSH_DEBUG_USE_STDERR"-" "-"
982 |
983 | #ifdef SSH_DECRYPT_DEBUG
984 | static void
985 | ssh_debug_printf(const char* fmt,...) G_GNUC_PRINTF(1,2)__attribute__((__format__ (__printf__, 1, 2)));
986 | static void
987 | ssh_print_data(const char* name, const unsigned char* data, size_t len);
988 | static void
989 | ssh_set_debug(const char* name);
990 | static void
991 | ssh_debug_flush(void);
992 | #else
993 |
994 | /* No debug: nullify debug operation*/
995 | static inline void G_GNUC_PRINTF(1,2)__attribute__((__format__ (__printf__, 1, 2)))
996 | ssh_debug_printf(const char* fmt _U___attribute__((unused)),...)
997 | {
998 | }
999 | #define ssh_print_data(a, b, c)
1000 | #define ssh_print_string(a, b)
1001 | #define ssh_set_debug(name)
1002 | #define ssh_debug_flush()
1003 |
1004 | #endif /* SSH_DECRYPT_DEBUG */
1005 |
1006 | static void
1007 | ssh_set_server(struct ssh_flow_data *global_data, address *addr, uint32_t port)
1008 | {
1009 | copy_address_wmem(wmem_file_scope(), &global_data->srv_addr, addr);
1010 | global_data->srv_port = port;
1011 | }
1012 |
1013 | static bool_Bool
1014 | ssh_packet_from_server(struct ssh_flow_data *session, const packet_info *pinfo)
1015 | {
1016 | bool_Bool ret;
1017 | if (session && session->srv_addr.type != AT_NONE) {
1018 | ret = (session->srv_port == pinfo->srcport) &&
1019 | addresses_equal(&session->srv_addr, &pinfo->src);
1020 | } else {
1021 | ret = (pinfo->match_uint == pinfo->srcport);
1022 | }
1023 |
1024 | ssh_debug_printf("packet_from_server: is from server - %s\n", (ret)?"TRUE":"FALSE");
1025 | return ret;
1026 | }
1027 |
1028 | static bool_Bool
1029 | ssh_peer_data_from_server(struct ssh_peer_data* peer_data) {
1030 | return &peer_data->global_data->peer_data[SERVER_PEER_DATA1] == peer_data;
1031 | }
1032 |
1033 | static int
1034 | dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
1035 | {
1036 | proto_tree *ssh_tree;
1037 | proto_item *ti;
1038 | conversation_t *conversation;
1039 | int last_offset, offset = 0;
1040 |
1041 | bool_Bool is_response,
1042 | need_desegmentation;
1043 | unsigned version;
1044 |
1045 | struct ssh_flow_data *global_data = NULL((void*)0);
1046 | struct ssh_peer_data *peer_data;
1047 |
1048 | ssh_debug_printf("\ndissect_ssh enter frame #%u (%s)\n", pinfo->num, (pinfo->fd->visited)?"already visited":"first time");
1049 |
1050 | conversation = find_or_create_conversation(pinfo);
1051 |
1052 | global_data = (struct ssh_flow_data *)conversation_get_proto_data(conversation, proto_ssh);
1053 | if (!global_data) {
1054 | global_data = wmem_new0(wmem_file_scope(), struct ssh_flow_data)((struct ssh_flow_data*)wmem_alloc0((wmem_file_scope()), sizeof (struct ssh_flow_data)));
1055 | global_data->version = SSH_VERSION_UNKNOWN0;
1056 | global_data->kex_specific_dissector = ssh_dissect_kex_dh;
1057 | global_data->peer_data[CLIENT_PEER_DATA0].mac_length = -1;
1058 | global_data->peer_data[SERVER_PEER_DATA1].mac_length = -1;
1059 | global_data->peer_data[CLIENT_PEER_DATA0].sequence_number = 0;
1060 | global_data->peer_data[SERVER_PEER_DATA1].sequence_number = 0;
1061 | global_data->peer_data[CLIENT_PEER_DATA0].bn_cookie = NULL((void*)0);
1062 | global_data->peer_data[SERVER_PEER_DATA1].bn_cookie = NULL((void*)0);
1063 | global_data->peer_data[CLIENT_PEER_DATA0].global_data = global_data;
1064 | global_data->peer_data[SERVER_PEER_DATA1].global_data = global_data;
1065 | global_data->kex_client_version = wmem_array_new(wmem_file_scope(), 1);
1066 | global_data->kex_server_version = wmem_array_new(wmem_file_scope(), 1);
1067 | global_data->kex_client_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
1068 | global_data->kex_server_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
1069 | global_data->kex_server_host_key_blob = wmem_array_new(wmem_file_scope(), 1);
1070 | global_data->kex_gex_bits_min = wmem_array_new(wmem_file_scope(), 1);
1071 | global_data->kex_gex_bits_req = wmem_array_new(wmem_file_scope(), 1);
1072 | global_data->kex_gex_bits_max = wmem_array_new(wmem_file_scope(), 1);
1073 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1);
1074 | global_data->do_decrypt = true1;
1075 | global_data->ext_ping_openssh_offered = false0;
1076 |
1077 | /* We expect to get the client message first. If this is from an
1078 | * an assigned server port, call it the server, otherwise call it
1079 | * the client.
1080 | * XXX - We don't unambiguously know which side is the server and
1081 | * which the client until the KEX specific _INIT and _REPLY messages;
1082 | * we ought to be able to handle the cases where the version string or
1083 | * KEXINIT messages are out of order or where the client version string
1084 | * is missing. */
1085 | if (pinfo->match_uint == pinfo->srcport) {
1086 | ssh_set_server(global_data, &pinfo->src, pinfo->srcport);
1087 | } else {
1088 | ssh_set_server(global_data, &pinfo->dst, pinfo->destport);
1089 | }
1090 |
1091 | conversation_add_proto_data(conversation, proto_ssh, global_data);
1092 | }
1093 |
1094 | is_response = ssh_packet_from_server(global_data, pinfo);
1095 | peer_data = &global_data->peer_data[is_response];
1096 |
1097 | ti = proto_tree_add_item(tree, proto_ssh, tvb, offset, -1, ENC_NA0x00000000);
1098 | ssh_tree = proto_item_add_subtree(ti, ett_ssh);
1099 |
1100 | version = global_data->version;
1101 |
1102 | switch(version) {
1103 | case SSH_VERSION_UNKNOWN0:
1104 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSH");
1105 | break;
1106 | case SSH_VERSION_11:
1107 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv1");
1108 | break;
1109 | case SSH_VERSION_22:
1110 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv2");
1111 | break;
1112 |
1113 | }
1114 |
1115 | col_clear(pinfo->cinfo, COL_INFO);
1116 |
1117 | while(tvb_reported_length_remaining(tvb, offset)> 0) {
1118 | bool_Bool after_version_start = (peer_data->frame_version_start == 0 ||
1119 | pinfo->num >= peer_data->frame_version_start);
1120 | bool_Bool before_version_end = (peer_data->frame_version_end == 0 ||
1121 | pinfo->num <= peer_data->frame_version_end);
1122 |
1123 | need_desegmentation = false0;
1124 | last_offset = offset;
1125 |
1126 | peer_data->counter++;
1127 |
1128 | if (after_version_start && before_version_end &&
1129 | (tvb_strncaseeql(tvb, offset, "SSH-", 4) == 0)) {
1130 | if (peer_data->frame_version_start == 0)
1131 | peer_data->frame_version_start = pinfo->num;
1132 |
1133 | offset = ssh_dissect_protocol(tvb, pinfo,
1134 | global_data,
1135 | offset, ssh_tree, is_response,
1136 | &version, &need_desegmentation);
1137 |
1138 | if (!need_desegmentation) {
1139 | peer_data->frame_version_end = pinfo->num;
1140 | global_data->version = version;
1141 | }
1142 | } else {
1143 | switch(version) {
1144 |
1145 | case SSH_VERSION_UNKNOWN0:
1146 | offset = ssh_try_dissect_encrypted_packet(tvb, pinfo,
1147 | &global_data->peer_data[is_response], offset, ssh_tree);
1148 | break;
1149 |
1150 | case SSH_VERSION_11:
1151 | offset = ssh_dissect_ssh1(tvb, pinfo, global_data,
1152 | offset, ssh_tree, is_response,
1153 | &need_desegmentation);
1154 | break;
1155 |
1156 | case SSH_VERSION_22:
1157 | offset = ssh_dissect_ssh2(tvb, pinfo, global_data,
1158 | offset, ssh_tree, is_response,
1159 | &need_desegmentation);
1160 | break;
1161 | }
1162 | }
1163 |
1164 | if (need_desegmentation)
1165 | return tvb_captured_length(tvb);
1166 | if (offset <= last_offset) {
1167 | /* XXX - add an expert info in the function
1168 | that decrements offset */
1169 | break;
1170 | }
1171 | }
1172 |
1173 | col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s: ", is_response ? "Server" : "Client");
1174 | ti = proto_tree_add_boolean(ssh_tree, hf_ssh_direction, tvb, 0, 0, is_response);
1175 | proto_item_set_generated(ti);
1176 |
1177 | ssh_debug_flush();
1178 |
1179 | return tvb_captured_length(tvb);
1180 | }
1181 |
1182 | static bool_Bool
1183 | dissect_ssh_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1184 | {
1185 | conversation_t *conversation;
1186 |
1187 | if (tvb_strneql(tvb, 0, "SSH-", 4) != 0) {
1188 | return false0;
1189 | }
1190 |
1191 | conversation = find_or_create_conversation(pinfo);
1192 | conversation_set_dissector(conversation, ssh_handle);
1193 |
1194 | dissect_ssh(tvb, pinfo, tree, data);
1195 |
1196 | return true1;
1197 | }
1198 |
1199 | static int
1200 | ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
1201 | struct ssh_flow_data *global_data,
1202 | int offset, proto_tree *tree, int is_response,
1203 | bool_Bool *need_desegmentation)
1204 | {
1205 | proto_item *ssh2_tree = NULL((void*)0);
1206 | int remain_length;
1207 |
1208 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response];
1209 |
1210 | remain_length = tvb_captured_length_remaining(tvb, offset);
1211 |
1212 | if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1213 | ws_debug("SSH: SECOND PASS frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 1213, __func__, "SSH: SECOND PASS frame %u", pinfo->num) ; } } while (0);
1214 | }else{
1215 | ws_debug("SSH: FIRST PASS frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 1215, __func__, "SSH: FIRST PASS frame %u", pinfo->num); } } while (0);
1216 | }
1217 |
1218 | while(remain_length>0){
1219 | int last_offset = offset;
1220 | if (tree) {
1221 | wmem_strbuf_t *title = wmem_strbuf_new(pinfo->pool, "SSH Version 2");
1222 |
1223 | if (peer_data->enc || peer_data->mac || peer_data->comp) {
1224 | wmem_strbuf_append_printf(title, " (");
1225 | if (peer_data->enc)
1226 | wmem_strbuf_append_printf(title, "encryption:%s%s",
1227 | peer_data->enc,
1228 | peer_data->mac || peer_data->comp
1229 | ? " " : "");
1230 | if (peer_data->mac)
1231 | wmem_strbuf_append_printf(title, "mac:%s%s",
1232 | peer_data->mac,
1233 | peer_data->comp ? " " : "");
1234 | if (peer_data->comp)
1235 | wmem_strbuf_append_printf(title, "compression:%s",
1236 | peer_data->comp);
1237 | wmem_strbuf_append_printf(title, ")");
1238 | }
1239 |
1240 | ssh2_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_ssh2, NULL((void*)0), wmem_strbuf_get_str(title));
1241 | }
1242 | ws_noisy("....ssh_dissect_ssh2[%c]: frame_key_start=%d, pinfo->num=%d, frame_key_end=%d, offset=%d, frame_key_end_offset=%d ", is_response==SERVER_PEER_DATA?'S':'C', peer_data->frame_key_start, pinfo->num, peer_data->frame_key_end, offset, peer_data->frame_key_end_offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 1242, __func__, "....ssh_dissect_ssh2[%c]: frame_key_start=%d, pinfo->num=%d, frame_key_end=%d, offset=%d, frame_key_end_offset=%d " , is_response==1?'S':'C', peer_data->frame_key_start, pinfo ->num, peer_data->frame_key_end, offset, peer_data-> frame_key_end_offset); } } while (0);
1243 | if ((peer_data->frame_key_start == 0) ||
1244 | ((peer_data->frame_key_start <= pinfo->num) &&
1245 | ((peer_data->frame_key_end == 0) || (pinfo->num < peer_data->frame_key_end) ||
1246 | ((pinfo->num == peer_data->frame_key_end) && (offset < peer_data->frame_key_end_offset))))) {
1247 | offset = ssh_dissect_key_exchange(tvb, pinfo, global_data,
1248 | offset, ssh2_tree, is_response,
1249 | need_desegmentation);
1250 |
1251 | if (!*need_desegmentation) {
1252 | ssh_get_packet_info(pinfo, is_response);
1253 | }else{
1254 | break;
1255 | }
1256 | } else {
1257 | if(!*need_desegmentation){
1258 | offset = ssh_try_dissect_encrypted_packet(tvb, pinfo,
1259 | &global_data->peer_data[is_response], offset, ssh2_tree);
1260 | if (pinfo->desegment_len) {
1261 | break;
1262 | }
1263 | }else{
1264 | break;
1265 | }
1266 | }
1267 |
1268 | if (ssh2_tree) {
1269 | proto_item_set_len(ssh2_tree, offset - last_offset);
1270 | }
1271 |
1272 | remain_length = tvb_captured_length_remaining(tvb, offset);
1273 | }
1274 |
1275 | return offset;
1276 | }
1277 | static int
1278 | ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
1279 | struct ssh_flow_data *global_data,
1280 | int offset, proto_tree *tree, int is_response,
1281 | bool_Bool *need_desegmentation)
1282 | {
1283 | unsigned plen, padding_length, len;
1284 | uint8_t msg_code;
1285 | unsigned remain_length;
1286 |
1287 | proto_item *ssh1_tree;
1288 |
1289 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response];
1290 |
1291 | ssh1_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_ssh1, NULL((void*)0), "SSH Version 1");
1292 |
1293 | /*
1294 | * We use "tvb_ensure_captured_length_remaining()" to make sure there
1295 | * actually *is* data remaining.
1296 | *
1297 | * This means we're guaranteed that "remain_length" is positive.
1298 | */
1299 | remain_length = tvb_ensure_captured_length_remaining(tvb, offset);
1300 | /*
1301 | * Can we do reassembly?
1302 | */
1303 | if (ssh_desegment && pinfo->can_desegment) {
1304 | /*
1305 | * Yes - would an SSH header starting at this offset be split
1306 | * across segment boundaries?
1307 | */
1308 | if (remain_length < 4) {
1309 | /*
1310 | * Yes. Tell the TCP dissector where the data for
1311 | * this message starts in the data it handed us and
1312 | * that we need "some more data." Don't tell it
1313 | * exactly how many bytes we need because if/when we
1314 | * ask for even more (after the header) that will
1315 | * break reassembly.
1316 | */
1317 | pinfo->desegment_offset = offset;
1318 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
1319 | *need_desegmentation = true1;
1320 | return offset;
1321 | }
1322 | }
1323 | plen = tvb_get_ntohl(tvb, offset) ;
1324 |
1325 | /*
1326 | * Amount of random padding.
1327 | *
1328 | * This is between 1 and 8; if the length is a multiple of 8,
1329 | * there are 8 bytes of padding, not 1 byte.
1330 | *
1331 | * That means this calculation is correct; do not use either
1332 | * WS_ROUNDUP_8() or WS_PADDING_TO_8() here.
1333 | */
1334 | padding_length = 8 - plen%8;
1335 |
1336 |
1337 | if (ssh_desegment && pinfo->can_desegment) {
1338 | if (plen+4+padding_length > remain_length) {
1339 | pinfo->desegment_offset = offset;
1340 | pinfo->desegment_len = plen+padding_length - remain_length;
1341 | *need_desegmentation = true1;
1342 | return offset;
1343 | }
1344 | }
1345 |
1346 | if (plen >= SSH_MAX_PACKET_LEN32768) {
1347 | if (ssh1_tree) {
1348 | proto_tree_add_uint_format(ssh1_tree, hf_ssh_packet_length, tvb,
1349 | offset, 4, plen, "Overly large length %x", plen);
1350 | }
1351 | plen = remain_length-4-padding_length;
1352 | } else {
1353 | if (ssh1_tree && plen > 0) {
1354 | proto_tree_add_uint(ssh1_tree, hf_ssh_packet_length, tvb,
1355 | offset, 4, plen);
1356 | }
1357 | }
1358 | offset+=4;
1359 | /* padding length */
1360 |
1361 | proto_tree_add_uint(ssh1_tree, hf_ssh_padding_length, tvb,
1362 | offset, padding_length, padding_length);
1363 | offset += padding_length;
1364 |
1365 | /* msg_code */
1366 | if ((peer_data->frame_key_start == 0) ||
1367 | ((peer_data->frame_key_start >= pinfo->num) && (pinfo->num <= peer_data->frame_key_end))) {
1368 |
1369 | proto_tree_add_item_ret_uint8(ssh1_tree, hf_ssh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000, &msg_code);
1370 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1371 | val_to_str(pinfo->pool, msg_code, ssh1_msg_vals, "Unknown (%u)"));
1372 | offset += 1;
1373 | len = plen -1;
1374 | if (!pinfo->fd->visited) {
1375 | if (peer_data->frame_key_start == 0)
1376 | peer_data->frame_key_start = pinfo->num;
1377 | peer_data->frame_key_end = pinfo->num;
1378 | }
1379 | } else {
1380 | len = plen;
1381 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (len=%d)", len);
1382 | }
1383 | /* payload */
1384 | if (ssh1_tree) {
1385 | proto_tree_add_item(ssh1_tree, hf_ssh_payload,
1386 | tvb, offset, len, ENC_NA0x00000000);
1387 | }
1388 | offset += len;
1389 |
1390 | return offset;
1391 | }
1392 |
1393 | static int
1394 | ssh_tree_add_mpint(tvbuff_t *tvb, int offset, proto_tree *tree,
1395 | int hf_ssh_mpint_selection)
1396 | {
1397 | unsigned len = tvb_get_ntohl(tvb, offset);
1398 | proto_tree_add_uint(tree, hf_ssh_mpint_length, tvb,
1399 | offset, 4, len);
1400 | offset+=4;
1401 | proto_tree_add_item(tree, hf_ssh_mpint_selection,
1402 | tvb, offset, len, ENC_NA0x00000000);
1403 | return 4+len;
1404 | }
1405 |
1406 | static int
1407 | ssh_tree_add_string(tvbuff_t *tvb, int offset, proto_tree *tree,
1408 | int hf_ssh_string, int hf_ssh_string_length)
1409 | {
1410 | unsigned len = tvb_get_ntohl(tvb, offset);
1411 | proto_tree_add_uint(tree, hf_ssh_string_length, tvb,
1412 | offset, 4, len);
1413 | offset+=4;
1414 | proto_tree_add_item(tree, hf_ssh_string,
1415 | tvb, offset, len, ENC_NA0x00000000);
1416 | return 4+len;
1417 | }
1418 |
1419 | static unsigned
1420 | ssh_tree_add_hostkey(tvbuff_t *tvb, packet_info* pinfo, int offset, proto_tree *parent_tree,
1421 | const char *tree_name, int ett_idx,
1422 | struct ssh_flow_data *global_data)
1423 | {
1424 | proto_tree *tree = NULL((void*)0);
1425 | proto_item *ti;
1426 | int last_offset;
1427 | int remaining_len;
1428 | unsigned key_len, type_len;
1429 | char* key_type;
1430 | char *tree_title;
1431 |
1432 | last_offset = offset;
1433 |
1434 | key_len = tvb_get_ntohl(tvb, offset);
1435 | offset += 4;
1436 |
1437 | /* Read the key type before creating the tree so we can append it as info. */
1438 | type_len = tvb_get_ntohl(tvb, offset);
1439 | offset += 4;
1440 | key_type = (char *) tvb_get_string_enc(pinfo->pool, tvb, offset, type_len, ENC_ASCII0x00000000|ENC_NA0x00000000);
1441 |
1442 | tree_title = wmem_strdup_printf(pinfo->pool, "%s (type: %s)", tree_name, key_type);
1443 | tree = proto_tree_add_subtree(parent_tree, tvb, last_offset, key_len + 4, ett_idx, NULL((void*)0),
1444 | tree_title);
1445 |
1446 | ti = proto_tree_add_uint(tree, hf_ssh_hostkey_length, tvb, last_offset, 4, key_len);
1447 |
1448 | // server host key (K_S / Q)
1449 | uint8_t *data = (uint8_t *)tvb_memdup(pinfo->pool, tvb, last_offset + 4, key_len);
1450 | if (global_data) {
1451 | // Reset array while REKEY: sanitize server host key blob
1452 | global_data->kex_server_host_key_blob = wmem_array_new(wmem_file_scope(), 1);
1453 | ssh_hash_buffer_put_string(global_data->kex_server_host_key_blob, data, key_len);
1454 | }
1455 |
1456 | last_offset += 4;
1457 | proto_tree_add_uint(tree, hf_ssh_hostkey_type_length, tvb, last_offset, 4, type_len);
1458 | proto_tree_add_string(tree, hf_ssh_hostkey_type, tvb, offset, type_len, key_type);
1459 | offset += type_len;
1460 |
1461 | if (0 == strcmp(key_type, "ssh-rsa")) {
1462 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_rsa_e);
1463 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_rsa_n);
1464 | } else if (0 == strcmp(key_type, "ssh-dss")) {
1465 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_p);
1466 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_q);
1467 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_g);
1468 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_y);
1469 | } else if (g_str_has_prefix(key_type, "ecdsa-sha2-")(__builtin_constant_p ("ecdsa-sha2-")? __extension__ ({ const char * const __str = (key_type); const char * const __prefix = ("ecdsa-sha2-"); gboolean __result = (0); if (__str == ((void *)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (( (__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix ) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (key_type, "ecdsa-sha2-" ) )) {
1470 | offset += ssh_tree_add_string(tvb, offset, tree,
1471 | hf_ssh_hostkey_ecdsa_curve_id, hf_ssh_hostkey_ecdsa_curve_id_length);
1472 | offset += ssh_tree_add_string(tvb, offset, tree,
1473 | hf_ssh_hostkey_ecdsa_q, hf_ssh_hostkey_ecdsa_q_length);
1474 | } else if (g_str_has_prefix(key_type, "ssh-ed")(__builtin_constant_p ("ssh-ed")? __extension__ ({ const char * const __str = (key_type); const char * const __prefix = ("ssh-ed" ); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix ))); if (__str_len >= __prefix_len) __result = memcmp (((__str ) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0 ; } __result; }) : (g_str_has_prefix) (key_type, "ssh-ed") )) {
1475 | offset += ssh_tree_add_string(tvb, offset, tree,
1476 | hf_ssh_hostkey_eddsa_key, hf_ssh_hostkey_eddsa_key_length);
1477 | } else {
1478 | remaining_len = key_len - (type_len + 4);
1479 | proto_tree_add_item(tree, hf_ssh_hostkey_data, tvb, offset, remaining_len, ENC_NA0x00000000);
1480 | offset += remaining_len;
1481 | }
1482 |
1483 | if (last_offset + (int)key_len != offset) {
1484 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but hostkey length is %d bytes", offset - last_offset, key_len);
1485 | }
1486 | return 4+key_len;
1487 | }
1488 |
1489 | static unsigned
1490 | ssh_tree_add_hostsignature(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree,
1491 | const char *tree_name, int ett_idx,
1492 | struct ssh_flow_data *global_data)
1493 | {
1494 | (void)global_data;
1495 | proto_tree *tree = NULL((void*)0);
1496 | proto_item* ti = NULL((void*)0);
1497 | int last_offset;
1498 | int offset0 = offset;
1499 | unsigned sig_len, type_len, data_len;
1500 | const char* sig_type;
1501 | char *tree_title;
1502 |
1503 | last_offset = offset;
1504 |
1505 | sig_len = tvb_get_ntohl(tvb, offset);
1506 | offset += 4;
1507 |
1508 | /* Read the signature type before creating the tree so we can append it as info. */
1509 | type_len = tvb_get_ntohl(tvb, offset);
1510 | offset += 4;
1511 | sig_type = (char*)tvb_get_string_enc(pinfo->pool, tvb, offset, type_len, ENC_ASCII0x00000000|ENC_NA0x00000000);
1512 |
1513 | tree_title = wmem_strdup_printf(pinfo->pool, "%s (type: %s)", tree_name, sig_type);
1514 | tree = proto_tree_add_subtree(parent_tree, tvb, last_offset, sig_len + 4, ett_idx, NULL((void*)0),
1515 | tree_title);
1516 |
1517 | ti = proto_tree_add_uint(tree, hf_ssh_hostsig_length, tvb, last_offset, 4, sig_len);
1518 |
1519 | last_offset += 4;
1520 | proto_tree_add_uint(tree, hf_ssh_hostsig_type_length, tvb, last_offset, 4, type_len);
1521 | proto_tree_add_string(tree, hf_ssh_hostsig_type, tvb, offset, type_len, sig_type);
1522 | offset += type_len;
1523 |
1524 | if (0 == strcmp(sig_type, "ssh-rsa")) {
1525 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostsig_rsa);
1526 | } else if (0 == strcmp(sig_type, "ssh-dss")) {
1527 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostsig_dsa);
1528 | // } else if (g_str_has_prefix(sig_type, "ecdsa-sha2-")) {
1529 | // offset += ssh_tree_add_string(tvb, offset, tree,
1530 | // hf_ssh_hostkey_ecdsa_curve_id, hf_ssh_hostkey_ecdsa_curve_id_length);
1531 | // ssh_tree_add_string(tvb, offset, tree,
1532 | // hf_ssh_hostkey_ecdsa_q, hf_ssh_hostkey_ecdsa_q_length);
1533 | // } else if (g_str_has_prefix(sig_type, "ssh-ed")) {
1534 | // ssh_tree_add_string(tvb, offset, tree,
1535 | // hf_ssh_hostkey_eddsa_key, hf_ssh_hostkey_eddsa_key_length);
1536 | } else {
1537 | proto_tree_add_item_ret_uint(tree, hf_ssh_hostsig_data_length, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &data_len);
1538 | offset += 4;
1539 | proto_tree_add_item(tree, hf_ssh_hostsig_data, tvb, offset, data_len, ENC_NA0x00000000);
1540 | offset += data_len;
1541 | }
1542 |
1543 | if(offset-offset0!=(int)(4+sig_len)){
1544 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", offset-offset0, sig_len);
1545 | }
1546 |
1547 | return 4+sig_len;
1548 | }
1549 |
1550 | static int
1551 | ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
1552 | struct ssh_flow_data *global_data,
1553 | int offset, proto_tree *tree, int is_response,
1554 | bool_Bool *need_desegmentation)
1555 | {
1556 | unsigned plen, len;
1557 | uint8_t padding_length;
1558 | unsigned remain_length;
1559 | int last_offset = offset;
1560 | unsigned msg_code;
1561 |
1562 | proto_item *ti;
1563 | proto_item *key_ex_tree = NULL((void*)0);
1564 | const char *key_ex_title = "Key Exchange";
1565 |
1566 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response];
1567 |
1568 | if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1569 | ws_debug("SSH: SECOND PASS dissecting keys -for Wireshark UI- frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 1569, __func__, "SSH: SECOND PASS dissecting keys -for Wireshark UI- frame %u" , pinfo->num); } } while (0);
1570 | }
1571 | /* This is after the identification string (Protocol Version Exchange)
1572 | * but before the first key exchange has completed, so we expect the SSH
1573 | * packets to be unencrypted, and to contain KEX related messages.
1574 | *
1575 | * XXX - Without the "strict kex" extension, other messages are allowed;
1576 | * most don't make sense (SSH_MSG_IGNORE and SSH_MSG_DEBUG might), but we
1577 | * could dissect them and add them to the tree.
1578 | *
1579 | * XXX - Could we combine this with ssh_dissect_decrypted_packet, with a
1580 | * flag to indicate whether we're before the initial key exchange?
1581 | */
1582 |
1583 | /*
1584 | * We use "tvb_ensure_captured_length_remaining()" to make sure there
1585 | * actually *is* data remaining.
1586 | *
1587 | * This means we're guaranteed that "remain_length" is positive.
1588 | */
1589 | remain_length = tvb_ensure_captured_length_remaining(tvb, offset);
1590 | /*
1591 | * Can we do reassembly?
1592 | */
1593 | if (ssh_desegment && pinfo->can_desegment) {
1594 | /*
1595 | * Yes - would an SSH header starting at this offset
1596 | * be split across segment boundaries?
1597 | */
1598 | if (remain_length < 4) {
1599 | /*
1600 | * Yes. Tell the TCP dissector where the data for
1601 | * this message starts in the data it handed us and
1602 | * that we need "some more data." Don't tell it
1603 | * exactly how many bytes we need because if/when we
1604 | * ask for even more (after the header) that will
1605 | * break reassembly.
1606 | */
1607 | pinfo->desegment_offset = offset;
1608 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
1609 | *need_desegmentation = true1;
1610 | return offset;
1611 | }
1612 | }
1613 | plen = tvb_get_ntohl(tvb, offset) ;
1614 |
1615 | if (ssh_desegment && pinfo->can_desegment) {
1616 | if (plen +4 > remain_length) {
1617 | pinfo->desegment_offset = offset;
1618 | pinfo->desegment_len = plen+4 - remain_length;
1619 | *need_desegmentation = true1;
1620 | return offset;
1621 | }
1622 | }
1623 | /*
1624 | * Need to check plen > 0x80000000 here
1625 | */
1626 |
1627 | ti = proto_tree_add_uint(tree, hf_ssh_packet_length, tvb,
1628 | offset, 4, plen);
1629 | if (plen >= SSH_MAX_PACKET_LEN32768) {
1630 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Overly large number %d", plen);
1631 | plen = remain_length-4;
1632 |
1633 | /* XXX - Mark as Continuation Data and return without incrementing?
1634 | * Or do so *before* using this length to desegment? */
1635 | }
1636 | offset+=4;
1637 |
1638 | ssh_packet_info_t *packet = ssh_get_packet_info(pinfo, is_response);
1639 |
1640 | int record_id = tvb_raw_offset(tvb)+offset;
1641 | ssh_message_info_t *message;
1642 | message = ssh_get_message(pinfo, record_id);
1643 | if (!message) {
1644 | message = wmem_new0(wmem_file_scope(), ssh_message_info_t)((ssh_message_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_message_info_t)));
1645 | message->sequence_number = peer_data->sequence_number++;
1646 | message->id = record_id;
1647 | /* No data, and no MAC, as is this is before encryption starts. */
1648 | message->next = NULL((void*)0);
1649 | ssh_debug_printf("%s->sequence_number++ > %d\n", is_response?"server":"client", peer_data->sequence_number);
1650 |
1651 | ssh_message_info_t **pmessage = &packet->messages;
1652 | while(*pmessage){
1653 | pmessage = &(*pmessage)->next;
1654 | }
1655 | *pmessage = message;
1656 | }
1657 |
1658 | /* padding length */
1659 | padding_length = tvb_get_uint8(tvb, offset);
1660 | proto_tree_add_uint(tree, hf_ssh_padding_length, tvb, offset, 1, padding_length);
1661 | offset += 1;
1662 |
1663 | if (global_data->kex)
1664 | key_ex_title = wmem_strdup_printf(pinfo->pool, "%s (method:%s)", key_ex_title, global_data->kex);
1665 | key_ex_tree = proto_tree_add_subtree(tree, tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), key_ex_title);
1666 |
1667 | /* msg_code */
1668 | msg_code = tvb_get_uint8(tvb, offset);
1669 |
1670 | if (msg_code >= 30 && msg_code < 40) {
1671 | offset = global_data->kex_specific_dissector(msg_code, tvb, pinfo,
1672 | offset, key_ex_tree, global_data);
1673 | } else {
1674 | proto_tree_add_item(key_ex_tree, hf_ssh2_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1675 | offset += 1;
1676 |
1677 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1678 | val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
1679 |
1680 | /* 16 bytes cookie */
1681 | switch(msg_code)
1682 | {
1683 | case SSH_MSG_KEXINIT20:
1684 | offset = ssh_dissect_key_init(tvb, pinfo, offset, key_ex_tree, is_response, global_data);
1685 | if ((peer_data->frame_key_start == 0) && (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))) {
1686 | peer_data->frame_key_start = pinfo->num;
1687 | }
1688 | break;
1689 | case SSH_MSG_NEWKEYS21:
1690 | if (peer_data->frame_key_end == 0) {
1691 | peer_data->frame_key_end = pinfo->num;
1692 | peer_data->frame_key_end_offset = offset;
1693 |
1694 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1695 | /* "After sending or receiving a SSH2_MSG_NEWKEYS message,
1696 | * reset the packet sequence number to zero. This behaviour
1697 | * persists for the duration of the connection (i.e. not
1698 | * just the first SSH2_MSG_NEWKEYS) */
1699 | if (global_data->ext_kex_strict) {
1700 | peer_data->sequence_number = 0;
1701 | ssh_debug_printf("%s->sequence_number reset to 0 (Strict KEX)\n", is_response?"server":"client");
1702 | }
1703 | }
1704 |
1705 | // the client sent SSH_MSG_NEWKEYS
1706 | if (!is_response) {
1707 | ssh_debug_printf("Activating new keys for CLIENT => SERVER\n");
1708 | ssh_decryption_setup_cipher(&global_data->peer_data[CLIENT_PEER_DATA0], &global_data->new_keys[0], &global_data->new_keys[2]);
1709 | ssh_decryption_setup_mac(&global_data->peer_data[CLIENT_PEER_DATA0], &global_data->new_keys[4]);
1710 | }else{
1711 | ssh_debug_printf("Activating new keys for SERVER => CLIENT\n");
1712 | ssh_decryption_setup_cipher(&global_data->peer_data[SERVER_PEER_DATA1], &global_data->new_keys[1], &global_data->new_keys[3]);
1713 | ssh_decryption_setup_mac(&global_data->peer_data[SERVER_PEER_DATA1], &global_data->new_keys[5]);
1714 | }
1715 | }
1716 | break;
1717 | }
1718 | }
1719 |
1720 | len = plen+4-padding_length-(offset-last_offset);
1721 | if (len > 0) {
1722 | proto_tree_add_item(key_ex_tree, hf_ssh_payload, tvb, offset, len, ENC_NA0x00000000);
1723 | }
1724 | offset += len;
1725 |
1726 | /* padding */
1727 | proto_tree_add_item(tree, hf_ssh_padding_string, tvb, offset, padding_length, ENC_NA0x00000000);
1728 | offset+= padding_length;
1729 | ti = proto_tree_add_uint(tree, hf_ssh_seq_num, tvb, offset, 0, message->sequence_number);
1730 | proto_item_set_generated(ti);
1731 |
1732 | return offset;
1733 | }
1734 |
1735 | static int ssh_dissect_kex_dh(uint8_t msg_code, tvbuff_t *tvb,
1736 | packet_info *pinfo, int offset, proto_tree *tree,
1737 | struct ssh_flow_data *global_data)
1738 | {
1739 | proto_tree_add_item(tree, hf_ssh2_kex_dh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1740 | offset += 1;
1741 |
1742 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1743 | val_to_str(pinfo->pool, msg_code, ssh2_kex_dh_msg_vals, "Unknown (%u)"));
1744 |
1745 | switch (msg_code) {
1746 | case SSH_MSG_KEXDH_INIT30:
1747 | // e (client ephemeral key public part)
1748 | if (!ssh_read_e(tvb, offset, global_data)) {
1749 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2,
1750 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset));
1751 | }
1752 |
1753 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_e);
1754 | break;
1755 |
1756 | case SSH_MSG_KEXDH_REPLY31:
1757 | offset += ssh_tree_add_hostkey(tvb, pinfo, offset, tree, "KEX host key",
1758 | ett_key_exchange_host_key, global_data);
1759 |
1760 | // f (server ephemeral key public part), K_S (host key)
1761 | if (!ssh_read_f(tvb, offset, global_data)) {
1762 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2,
1763 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset));
1764 | }
1765 | ssh_choose_enc_mac(global_data);
1766 | ssh_keylog_hash_write_secret(global_data, pinfo->pool);
1767 |
1768 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_f);
1769 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature",
1770 | ett_key_exchange_host_sig, global_data);
1771 | break;
1772 | }
1773 |
1774 | return offset;
1775 | }
1776 |
1777 | static int ssh_dissect_kex_dh_gex(uint8_t msg_code, tvbuff_t *tvb,
1778 | packet_info *pinfo, int offset, proto_tree *tree,
1779 | struct ssh_flow_data *global_data)
1780 | {
1781 | proto_tree_add_item(tree, hf_ssh2_kex_dh_gex_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1782 | offset += 1;
1783 |
1784 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1785 | val_to_str(pinfo->pool, msg_code, ssh2_kex_dh_gex_msg_vals, "Unknown (%u)"));
1786 |
1787 | switch (msg_code) {
1788 | case SSH_MSG_KEX_DH_GEX_REQUEST_OLD30:
1789 | proto_tree_add_item(tree, hf_ssh_dh_gex_nbits, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
1790 | offset += 4;
1791 | break;
1792 |
1793 | case SSH_MSG_KEX_DH_GEX_GROUP31:
1794 | // p (Group modulo)
1795 | global_data->kex_gex_p = ssh_read_mpint(tvb, offset);
1796 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_gex_p);
1797 | // g (Group generator)
1798 | global_data->kex_gex_g = ssh_read_mpint(tvb, offset);
1799 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_gex_g);
1800 | break;
1801 |
1802 | case SSH_MSG_KEX_DH_GEX_INIT32:
1803 | // e (Client public key)
1804 | if (!ssh_read_e(tvb, offset, global_data)) {
1805 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2,
1806 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset));
1807 | }
1808 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_e);
1809 | break;
1810 |
1811 | case SSH_MSG_KEX_DH_GEX_REPLY33:
1812 | offset += ssh_tree_add_hostkey(tvb, pinfo, offset, tree, "KEX host key",
1813 | ett_key_exchange_host_key, global_data);
1814 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1815 | ssh_read_f(tvb, offset, global_data);
1816 | // f (server ephemeral key public part), K_S (host key)
1817 | ssh_choose_enc_mac(global_data);
1818 | ssh_keylog_hash_write_secret(global_data, pinfo->pool);
1819 | }
1820 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_f);
1821 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature",
1822 | ett_key_exchange_host_sig, global_data);
1823 | break;
1824 |
1825 | case SSH_MSG_KEX_DH_GEX_REQUEST34:{
1826 |
1827 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1828 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_min, tvb_get_ntohl(tvb, offset));
1829 | }
1830 | proto_tree_add_item(tree, hf_ssh_dh_gex_min, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
1831 | offset += 4;
1832 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1833 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_req, tvb_get_ntohl(tvb, offset));
1834 | }
1835 | proto_tree_add_item(tree, hf_ssh_dh_gex_nbits, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
1836 | offset += 4;
1837 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1838 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_max, tvb_get_ntohl(tvb, offset));
1839 | }
1840 | proto_tree_add_item(tree, hf_ssh_dh_gex_max, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
1841 | offset += 4;
1842 | break;
1843 | }
1844 | }
1845 |
1846 | return offset;
1847 | }
1848 |
1849 | static int
1850 | ssh_dissect_kex_ecdh(uint8_t msg_code, tvbuff_t *tvb,
1851 | packet_info *pinfo, int offset, proto_tree *tree,
1852 | struct ssh_flow_data *global_data)
1853 | {
1854 | proto_tree_add_item(tree, hf_ssh2_kex_ecdh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1855 | offset += 1;
1856 |
1857 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1858 | val_to_str(pinfo->pool, msg_code, ssh2_kex_ecdh_msg_vals, "Unknown (%u)"));
1859 |
1860 | switch (msg_code) {
1861 | case SSH_MSG_KEX_ECDH_INIT30:
1862 | if (!ssh_read_e(tvb, offset, global_data)) {
1863 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2,
1864 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset));
1865 | }
1866 |
1867 | offset += ssh_tree_add_string(tvb, offset, tree, hf_ssh_ecdh_q_c, hf_ssh_ecdh_q_c_length);
1868 | break;
1869 |
1870 | case SSH_MSG_KEX_ECDH_REPLY31:
1871 | offset += ssh_tree_add_hostkey(tvb, pinfo, offset, tree, "KEX host key",
1872 | ett_key_exchange_host_key, global_data);
1873 |
1874 | if (!ssh_read_f(tvb, offset, global_data)){
1875 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2,
1876 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset));
1877 | }
1878 |
1879 | ssh_choose_enc_mac(global_data);
1880 | ssh_keylog_hash_write_secret(global_data, pinfo->pool);
1881 |
1882 | offset += ssh_tree_add_string(tvb, offset, tree, hf_ssh_ecdh_q_s, hf_ssh_ecdh_q_s_length);
1883 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature",
1884 | ett_key_exchange_host_sig, global_data);
1885 | break;
1886 | }
1887 |
1888 | return offset;
1889 | }
1890 |
1891 | /*
1892 | * === Hybrid KEX Dissection Strategy for Post-Quantum algorithms ===
1893 | *
1894 | * This 3 functions:
1895 | *
1896 | * - ssh_dissect_kex_pq_hybrid()
1897 | * - ssh_read_e_pq()
1898 | * - ssh_read_f_pq()
1899 | *
1900 | * handles the dissection of server key exchange payloads for the
1901 | * post-quantum hybrid key exchange method:
1902 | * - sntrup761x25519-sha512
1903 | * - mlkem768x25519-sha256
1904 | * - mlkem768nistp256-sha256
1905 | * - mlkem1024nistp384-sha384
1906 | *
1907 | * /!\ Rationale for implementation approach:
1908 | *
1909 | * SSH encodes the server's ephemeral key (`Q_S`) as a single SSH `string`
1910 | * which contains both the post-quantum KEM ciphertext (from sntrup761 / mlkem768
1911 | * / mlkem1024) and the traditional (Curve25519 / nistp256 / nistp384) public key.
1912 | * Therefore, we parse one string
1913 | *
1914 | * sntrup761x25519:
1915 | * - PQ client keyshare: 1158 bytes
1916 | * - PQ server ciphertext: 1039 bytes
1917 | * - Curve25519 pubkey: 32 bytes
1918 | *
1919 | * mlkem768x25519:
1920 | * - PQ client keyshare: 1184 bytes
1921 | * - PQ server ciphertext: 1088 bytes
1922 | * - Curve25519 pubkey: 32 bytes
1923 | *
1924 | * mlkem768nistp256:
1925 | * - PQ client keyshare: 1184 bytes
1926 | * - PQ server ciphertext: 1088 bytes
1927 | * - nistp256 pubkey: 65 bytes
1928 | *
1929 | * mlkem1024nistp384:
1930 | * - PQ client keyshare: 1568 bytes
1931 | * - PQ server ciphertext: 1568 bytes
1932 | * - nistp384 pubkey: 97 bytes
1933 | *
1934 | * OpenSSH uses `sntrup761x25519-sha512@openssh.com` as an (old) alias for `sntrup761x25519-sha512`
1935 | *
1936 | * This matches how OpenSSH serializes the hybrid key material, and allows Wireshark
1937 | * to compute the correct key exchange hash and derive session keys accurately.
1938 | *
1939 | * /!\ This design is necessary for live decryption support in Wireshark and TShark.
1940 | *
1941 | * References:
1942 | * - RFC 4253: The SSH Transport Layer Protocol
1943 | * - Section 6: string encoding format
1944 | * - Section 7.2: Key derivation
1945 | * - RFC 8731: Secure Shell (SSH) Key Exchange Method using Curve25519
1946 | * - Internet-Draft on sntrup761x25519-sha512
1947 | * - https://datatracker.ietf.org/doc/draft-ietf-sshm-ntruprime-ssh/
1948 | * - Internet-Draft on mlkem768x25519-sha256
1949 | * - https://datatracker.ietf.org/doc/draft-ietf-sshm-mlkem-hybrid-kex/
1950 | * - OpenSSH Hybrid KEM Implementation (sntrup761x25519-sha512 / mlkem768x25519-sha256)
1951 | * - https://github.com/openssh/openssh-portable/blob/master/kexc25519.c
1952 | * - https://github.com/openssh/openssh-portable/blob/master/kexsntrup761x25519.c
1953 | * - https://github.com/openssh/openssh-portable/blob/master/kexmlkem768x25519.c
1954 | * - AsyncSSH Hybrid KEM Implementation (sntrup761x25519-sha512 / mlkem768x25519-sha256 / mlkem768nistp256-sha256 / mlkem1024nistp384-sha384)
1955 | * - https://github.com/ronf/asyncssh/blob/develop/asyncssh/kex_dh.py
1956 | *
1957 | */
1958 |
1959 | static int
1960 | ssh_dissect_kex_pq_hybrid(uint8_t msg_code, tvbuff_t *tvb,
1961 | packet_info *pinfo, int offset, proto_tree *tree,
1962 | struct ssh_flow_data *global_data)
1963 | {
1964 | // SSH PACKET STRUCTURE RFC4253 (e.g. packet of 1228 bytes payload)
1965 | // [00 00 04 cc] → ssh payload blob length field in tcp packet (e.g. 1228=0x04cc): 4 bytes
1966 | // [1228 bytes of SSH PAYLOAD BLOB] → ssh payload blob field: 1228 bytes
1967 |
1968 | // Add the message code byte (first field in packet) to the GUI tree.
1969 | proto_tree_add_item(tree, hf_ssh2_kex_hybrid_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
1970 | offset += 1; // Move offset past the msg_code byte.
1971 |
1972 | // Add a descriptive string to Wireshark's "Info" column.
1973 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0),
1974 | val_to_str(pinfo->pool, msg_code, ssh2_kex_hybrid_msg_vals, "Unknown (%u)"));
1975 |
1976 | const char *kex_name = global_data->kex;
1977 |
1978 | if (msg_code == SSH_MSG_KEX_HYBRID_INIT30) {
1 | Assuming 'msg_code' is not equal to SSH_MSG_KEX_HYBRID_INIT | →
2 | ← | Taking false branch | →
1979 | // Print warning when PQ hybrid KEM is detected in KEX
1980 | // This implementation currently rely on SHARED_SECRET only and do not work with PRIVATE_KEY
1981 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
1982 | ws_warning("POST-QUANTUM KEX_HYBRID detected: KEX = %s", kex_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_WARNING, "epan/dissectors/packet-ssh.c" , 1982, __func__, "POST-QUANTUM KEX_HYBRID detected: KEX = %s" , kex_name); } } while (0);
1983 | ws_warning("SHARED_SECRET decryption is supported - PRIVATE_KEY decryption is not supported")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_WARNING, "epan/dissectors/packet-ssh.c" , 1983, __func__, "SHARED_SECRET decryption is supported - PRIVATE_KEY decryption is not supported" ); } } while (0);
1984 | }
1985 | // Print noisy debug info
1986 | ws_noisy(">>> HYBRID KEM: msg_code = %u, offset = %d, kex = %s", msg_code, offset, kex_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 1986, __func__, ">>> HYBRID KEM: msg_code = %u, offset = %d, kex = %s" , msg_code, offset, kex_name); } } while (0);
1987 | }
1988 |
1989 | switch (msg_code) {
3 | ← | Control jumps to 'case 31:' at line 2076 | →
1990 |
1991 | // Client Key Exchange INIT
1992 | case SSH_MSG_KEX_HYBRID_INIT30: {
1993 |
1994 | // SNTRUP761X25519: RFC4253 SSH "string" (binary-encoded structure)
1995 | // [00 00 04 a6] → length = 1190 (0x04a6)
1996 | // [1158 bytes PQ blob] → sntrup761 encapsulated client key
1997 | // [32 bytes of X25519 pubkey] → ephemeral X25519 public key
1998 |
1999 | // MLKEM768X25519: RFC4253 SSH "string" (binary-encoded structure)
2000 | // [00 00 04 c0] → length = 1216 (0x04c0)
2001 | // [1184 bytes PQ blob] → mlkem768 encapsulated client key
2002 | // [32 bytes of X25519 pubkey] → ephemeral X25519 public key
2003 |
2004 | // MLKEM768NISTP256: RFC4253 SSH "string" (binary-encoded structure)
2005 | // [00 00 04 e1] → length = 1249 (0x04e1)
2006 | // [1184 bytes PQ blob] → mlkem768 encapsulated client key
2007 | // [65 bytes of nistp256 pubkey] → ephemeral nistp256 public key
2008 |
2009 | // MLKEM1024NISTP384: RFC4253 SSH "string" (binary-encoded structure)
2010 | // [00 00 06 81] → length = 1665 (0x0681)
2011 | // [1568 bytes PQ blob] → mlkem1024 encapsulated client key
2012 | // [97 bytes of nistp384 pubkey] → ephemeral nistp384 public key
2013 |
2014 | ws_debug("CLIENT INIT follow offset pointer - absolute offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2014, __func__, "CLIENT INIT follow offset pointer - absolute offset: %d" , offset); } } while (0); // debug trace offset
2015 | int new_offset_client = ssh_read_e_pq(tvb, offset, global_data);
2016 | if (new_offset_client < 0) {
2017 | uint32_t bad_len = tvb_get_ntohl(tvb, offset);
2018 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4,
2019 | "Invalid PQ client key length: %u", bad_len);
2020 | ws_debug("ExpertInfo: Invalid PQ client key length at offset %d: %u", offset, bad_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2020, __func__, "ExpertInfo: Invalid PQ client key length at offset %d: %u" , offset, bad_len); } } while (0);
2021 |
2022 | return offset + 4;
2023 | }
2024 |
2025 | // PQ-hybrid KEMs cannot use ssh_add_tree_string => manual dissection
2026 | // Get PQ blob size
2027 | proto_tree *pq_tree = NULL((void*)0);
2028 | uint32_t hybrid_len;
2029 |
2030 | // Add a subtree for dissecting PQ blob
2031 | proto_tree_add_item_ret_uint(tree, hf_ssh_hybrid_blob_client_len, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &hybrid_len); // add blob length
2032 | ws_debug("CLIENT INIT PQ blob length - pq_len: %d", hybrid_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2032, __func__, "CLIENT INIT PQ blob length - pq_len: %d", hybrid_len ); } } while (0); // debug trace pq_len
2033 | offset += 4; // shift length field
2034 | pq_tree = proto_tree_add_subtree(tree, tvb, offset, hybrid_len, ett_ssh_pqhybrid_client, NULL((void*)0), "Hybrid Key Exchange Blob Client");
2035 | ws_debug("CLIENT INIT add PQ Hybrid subtree - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2035, __func__, "CLIENT INIT add PQ Hybrid subtree - offset: %d" , offset); } } while (0); // debug trace offset
2036 |
2037 | // Make a new tvb for just the PQ hybrid blob string contents
2038 | tvbuff_t *string_tvb = tvb_new_subset_length(tvb, offset, hybrid_len);
2039 |
2040 | uint32_t pq_len;
2041 | uint32_t t_len;
2042 | if (g_str_has_prefix(kex_name, "sntrup761x25519-sha512")(__builtin_constant_p ("sntrup761x25519-sha512")? __extension__ ({ const char * const __str = (kex_name); const char * const __prefix = ("sntrup761x25519-sha512"); gboolean __result = ( 0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len ) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix )), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) ( kex_name, "sntrup761x25519-sha512") )) {
2043 | pq_len = 1158;
2044 | t_len = 32;
2045 | } else if (strcmp(kex_name, "mlkem768x25519-sha256") == 0) {
2046 | pq_len = 1184;
2047 | t_len = 32;
2048 | } else if (strcmp(kex_name, "mlkem768nistp256-sha256") == 0) {
2049 | pq_len = 1184;
2050 | t_len = 65;
2051 | } else if (strcmp(kex_name, "mlkem1024nistp384-sha384") == 0) {
2052 | pq_len = 1568;
2053 | t_len = 97;
2054 | } else {
2055 | DISSECTOR_ASSERT_NOT_REACHED()(proto_report_dissector_bug("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"" , "epan/dissectors/packet-ssh.c", 2055));
2056 | break;
2057 | }
2058 |
2059 | if (pq_len + t_len != hybrid_len) {
2060 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4,
2061 | "Invalid PQ hybrid client key length for %s: %u does not match %u + %u",
2062 | kex_name, hybrid_len, pq_len, t_len);
2063 | } else {
2064 | // Now dissect string inside the blob and add PQ server response and ECDH Q_S to GUI subtree
2065 | proto_tree_add_item(pq_tree, hf_ssh_pq_kem_client, string_tvb, 0, pq_len, ENC_NA0x00000000);
2066 | proto_tree_add_item(pq_tree, hf_ssh_ecdh_q_c, string_tvb, pq_len, t_len, ENC_NA0x00000000);
2067 | }
2068 |
2069 | // retrieve offset from read_f_pq() to shift blob length and consume packet
2070 | offset = new_offset_client;
2071 | ws_debug("CLIENT INIT shift PQ blob - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2071, __func__, "CLIENT INIT shift PQ blob - offset: %d", offset ); } } while (0); // debug trace offset
2072 | break;
2073 | }
2074 |
2075 | // Server Reply Message
2076 | case SSH_MSG_KEX_HYBRID_REPLY31: {
2077 |
2078 | // SNTRUP761X25519: RFC4253 SSH "string" (binary-encoded structure)
2079 | // [00 00 00 33] → host key structure length = 51
2080 | // [00 00 00 0b] → host key alg length = 11
2081 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2082 | // [00 00 00 20] → host key length = 32
2083 | // [32 bytes of public key] → public key
2084 | // [00 00 04 2f] → PQ blob length = 1071 (0x042f)
2085 | // [1071 bytes PQ blob] → PQ blob (1039 sntrup761 + 32 x25519)
2086 | // [00 00 00 53] → signature structure length = 83
2087 | // [00 00 00 0b] → signature alg length
2088 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2089 | // [00 00 00 40] → signature length
2090 | // [40 bytes signature] → server signature
2091 |
2092 | // MLKEM768X25519: RFC4253 SSH "string" (binary-encoded structure)
2093 | // [00 00 00 33] → host key structure length = 51
2094 | // [00 00 00 0b] → host key alg length = 11
2095 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2096 | // [00 00 00 20] → host key length = 32
2097 | // [32 bytes of public key] → public key
2098 | // [00 00 04 60] → PQ blob length = 1120 (0x0460)
2099 | // [1120 bytes PQ blob] → PQ blob (1088 mlkem768 + 32 x25519)
2100 | // [00 00 00 53] → signature structure length = 83
2101 | // [00 00 00 0b] → signature alg length
2102 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2103 | // [00 00 00 40] → signature length
2104 | // [40 bytes signature] → server signature
2105 |
2106 | // MLKEM768NISTP256: RFC4253 SSH "string" (binary-encoded structure)
2107 | // [00 00 00 33] → host key structure length = 51
2108 | // [00 00 00 0b] → host key alg length = 11
2109 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2110 | // [00 00 00 20] → host key length = 32
2111 | // [32 bytes of public key] → public key
2112 | // [00 00 04 81] → PQ blob length = 1153 (0x0481)
2113 | // [1153 bytes PQ blob] → PQ blob (1088 mlkem768 + 65 nistp256)
2114 | // [00 00 00 53] → signature structure length = 83
2115 | // [00 00 00 0b] → signature alg length
2116 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2117 | // [00 00 00 40] → signature length
2118 | // [40 bytes signature] → server signature
2119 |
2120 | // MLKEM1024NISTP384: RFC4253 SSH "string" (binary-encoded structure)
2121 | // [00 00 00 33] → host key structure length = 51
2122 | // [00 00 00 0b] → host key alg length = 11
2123 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2124 | // [00 00 00 20] → host key length = 32
2125 | // [32 bytes of public key] → public key
2126 | // [00 00 06 81] → PQ blob length = 1665 (0x0681)
2127 | // [1665 bytes PQ blob] → PQ blob (1568 mlkem1024 + 97 nistp384)
2128 | // [00 00 00 53] → signature structure length = 83
2129 | // [00 00 00 0b] → signature alg length
2130 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519"
2131 | // [00 00 00 40] → signature length
2132 | // [40 bytes signature] → server signature
2133 |
2134 | ws_debug("SERVER REPLY follow offset pointer - absolute offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2134, __func__, "SERVER REPLY follow offset pointer - absolute offset: %d" , offset); } } while (0); // debug trace offset
4 | ← | Taking true branch | →
5 | ← | Loop condition is false. Exiting loop | →
2135 |
2136 | // Add the host key used to sign the key exchange to the GUI tree.
2137 | offset += ssh_tree_add_hostkey(tvb, pinfo, offset, tree, "KEX host key", ett_key_exchange_host_key, global_data);
2138 |
2139 | ws_debug("SERVER REPLY add hostkey tree - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2139, __func__, "SERVER REPLY add hostkey tree - offset: %d" , offset); } } while (0); // debug trace offset
6 | ← | Taking true branch | →
7 | ← | Loop condition is false. Exiting loop | →
2140 |
2141 | int new_offset_server = ssh_read_f_pq(tvb, offset, global_data);
2142 | if (new_offset_server
7.1 | 'new_offset_server' is >= 0
< 0) {
8 | ← | Taking false branch | →
2143 | uint32_t bad_len = tvb_get_ntohl(tvb, offset);
2144 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4,
2145 | "Invalid PQ server key length: %u", bad_len);
2146 | ws_debug("ExpertInfo: Invalid PQ server key length at offset %d: %u", offset, bad_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2146, __func__, "ExpertInfo: Invalid PQ server key length at offset %d: %u" , offset, bad_len); } } while (0);
2147 |
2148 | return offset + 4;
2149 | }
2150 |
2151 | // Select encryption and MAC based on negotiated algorithms.
2152 | ssh_choose_enc_mac(global_data);
2153 |
2154 | // Write session secrets to keylog file (if enabled).
2155 | ssh_keylog_hash_write_secret(global_data, pinfo->pool);
9 | ← | Calling 'ssh_keylog_hash_write_secret' | →
2156 |
2157 | // PQ-hybrid KEMs cannot use ssh_add_tree_string => manual dissection
2158 | // Get PQ blob size
2159 | proto_tree *pq_tree = NULL((void*)0);
2160 | uint32_t hybrid_len = tvb_get_ntohl(tvb, offset);
2161 | ws_debug("SERVER REPLY PQ blob length - hybrid_len: %d", hybrid_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2161, __func__, "SERVER REPLY PQ blob length - hybrid_len: %d" , hybrid_len); } } while (0); // debug trace hybrid_len
2162 |
2163 | // Add a subtree for dissecting PQ blob
2164 | proto_tree_add_item(tree, hf_ssh_hybrid_blob_server_len, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); // add blob length
2165 | offset += 4; // shift length field
2166 | pq_tree = proto_tree_add_subtree(tree, tvb, offset, hybrid_len, ett_ssh_pqhybrid_server, NULL((void*)0), "Hybrid Key Exchange Blob Server");
2167 | ws_debug("SERVER REPLY add PQ Hybrid subtree - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2167, __func__, "SERVER REPLY add PQ Hybrid subtree - offset: %d" , offset); } } while (0); // debug trace offset
2168 |
2169 | // Make a new tvb for just the PQ hybrid blob string contents
2170 | tvbuff_t *string_tvb = tvb_new_subset_length(tvb, offset, hybrid_len);
2171 |
2172 | uint32_t pq_len;
2173 | uint32_t t_len;
2174 | if (g_str_has_prefix(kex_name, "sntrup761x25519-sha512")(__builtin_constant_p ("sntrup761x25519-sha512")? __extension__ ({ const char * const __str = (kex_name); const char * const __prefix = ("sntrup761x25519-sha512"); gboolean __result = ( 0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len ) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix )), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) ( kex_name, "sntrup761x25519-sha512") )) {
2175 | pq_len = 1039;
2176 | t_len = 32;
2177 | } else if (strcmp(kex_name, "mlkem768x25519-sha256") == 0) {
2178 | pq_len = 1088;
2179 | t_len = 32;
2180 | } else if (strcmp(kex_name, "mlkem768nistp256-sha256") == 0) {
2181 | pq_len = 1088;
2182 | t_len = 65;
2183 | } else if (strcmp(kex_name, "mlkem1024nistp384-sha384") == 0) {
2184 | pq_len = 1568;
2185 | t_len = 97;
2186 | } else {
2187 | DISSECTOR_ASSERT_NOT_REACHED()(proto_report_dissector_bug("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"" , "epan/dissectors/packet-ssh.c", 2187));
2188 | break;
2189 | }
2190 |
2191 | if (pq_len + t_len != hybrid_len) {
2192 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4,
2193 | "Invalid PQ hybrid server key length for %s: %u does not match %u + %u",
2194 | kex_name, hybrid_len, pq_len, t_len);
2195 | } else {
2196 | // Now dissect string inside the blob and add PQ server response and ECDH Q_S to GUI subtree
2197 | proto_tree_add_item(pq_tree, hf_ssh_pq_kem_server, string_tvb, 0, pq_len, ENC_NA0x00000000);
2198 | proto_tree_add_item(pq_tree, hf_ssh_ecdh_q_s, string_tvb, pq_len, t_len, ENC_NA0x00000000);
2199 | }
2200 |
2201 | // retrieve offset from read_f_pq() to shift blob length
2202 | offset = new_offset_server;
2203 | ws_debug("SERVER REPLY shift PQ blob - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2203, __func__, "SERVER REPLY shift PQ blob - offset: %d", offset ); } } while (0); // debug trace offset
2204 |
2205 | // Add the host's digital signature to the GUI tree
2206 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature",
2207 | ett_key_exchange_host_sig, global_data);
2208 | ws_debug("SERVER REPLY add signature tree - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2208, __func__, "SERVER REPLY add signature tree - offset: %d" , offset); } } while (0); // debug trace offset
2209 | break;
2210 | }
2211 | }
2212 |
2213 | if (msg_code == SSH_MSG_KEX_HYBRID_INIT30) {
2214 | ws_debug("OUT PQ HYBRID KEX - CLIENT INIT track offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2214, __func__, "OUT PQ HYBRID KEX - CLIENT INIT track offset: %d" , offset); } } while (0); // debug trace offset
2215 | } else if (msg_code == SSH_MSG_KEX_HYBRID_REPLY31) {
2216 | ws_debug("OUT PQ HYBRID KEX - SERVER REPLY track offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2216, __func__, "OUT PQ HYBRID KEX - SERVER REPLY track offset: %d" , offset); } } while (0); // debug trace offset
2217 | } else {
2218 | ws_debug("OUT PQ HYBRID KEX - track offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2218, __func__, "OUT PQ HYBRID KEX - track offset: %d", offset ); } } while (0); // debug trace offset
2219 | }
2220 |
2221 | return offset; // Final offset after packet is processed by ssh_dissect_kex_pq_hybrid()
2222 | }
2223 |
2224 | static ssh_message_info_t*
2225 | ssh_get_message(packet_info *pinfo, int record_id)
2226 | {
2227 | ssh_packet_info_t *packet = (ssh_packet_info_t *)p_get_proto_data(
2228 | wmem_file_scope(), pinfo, proto_ssh, 0);
2229 |
2230 | if (!packet) {
2231 | return NULL((void*)0);
2232 | }
2233 |
2234 | ssh_message_info_t *message = NULL((void*)0);
2235 | for (message = packet->messages; message; message = message->next) {
2236 | ws_noisy("%u:looking for message %d now %d", pinfo->num, record_id, message->id)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 2236, __func__, "%u:looking for message %d now %d", pinfo-> num, record_id, message->id); } } while (0);
2237 | if (message->id == record_id) {
2238 | return message;
2239 | }
2240 | }
2241 |
2242 | return NULL((void*)0);
2243 | }
2244 |
2245 | static int
2246 | ssh_try_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
2247 | struct ssh_peer_data *peer_data, int offset, proto_tree *tree)
2248 | {
2249 | bool_Bool can_decrypt = peer_data->cipher != NULL((void*)0) || peer_data->cipher_id == CIPHER_NULL0x00080000;
2250 | ssh_message_info_t *message = NULL((void*)0);
2251 |
2252 | if (can_decrypt) {
2253 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2254 | ssh_decrypt_packet(tvb, pinfo, peer_data, offset);
2255 | if (pinfo->desegment_len) {
2256 | return offset;
2257 | }
2258 | }
2259 |
2260 | int record_id = tvb_raw_offset(tvb) + offset;
2261 | message = ssh_get_message(pinfo, record_id);
2262 |
2263 | if (message) {
2264 | offset += ssh_dissect_decrypted_packet(tvb_new_subset_remaining(tvb, offset), pinfo, peer_data, tree, message);
2265 | return offset;
2266 | }
2267 | }
2268 |
2269 | return ssh_dissect_encrypted_packet(tvb, pinfo, peer_data, offset, tree);
2270 | }
2271 |
2272 | static int
2273 | ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
2274 | struct ssh_peer_data *peer_data,
2275 | int offset, proto_tree *tree)
2276 | {
2277 | int len;
2278 | unsigned plen;
2279 |
2280 | len = tvb_reported_length_remaining(tvb, offset);
2281 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (len=%d)", len);
2282 |
2283 | if (tree) {
2284 | int encrypted_len = len;
2285 |
2286 | if (len > 4 && peer_data->length_is_plaintext) {
2287 | plen = tvb_get_ntohl(tvb, offset) ;
2288 | proto_tree_add_uint(tree, hf_ssh_packet_length, tvb, offset, 4, plen);
2289 | encrypted_len -= 4;
2290 | }
2291 | else if (len > 4) {
2292 | proto_tree_add_item(tree, hf_ssh_packet_length_encrypted, tvb, offset, 4, ENC_NA0x00000000);
2293 | encrypted_len -= 4;
2294 | }
2295 |
2296 | if (peer_data->mac_length>0)
2297 | encrypted_len -= peer_data->mac_length;
2298 |
2299 | proto_tree_add_item(tree, hf_ssh_encrypted_packet,
2300 | tvb, offset+4, encrypted_len, ENC_NA0x00000000);
2301 |
2302 | if (peer_data->mac_length>0)
2303 | proto_tree_add_item(tree, hf_ssh_mac_string,
2304 | tvb, offset+4+encrypted_len,
2305 | peer_data->mac_length, ENC_NA0x00000000);
2306 | }
2307 | offset += len;
2308 | return offset;
2309 | }
2310 |
2311 | static int
2312 | ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
2313 | struct ssh_flow_data *global_data,
2314 | unsigned offset, proto_tree *tree, int is_response, unsigned * version,
2315 | bool_Bool *need_desegmentation)
2316 | {
2317 | unsigned protolen, next_offset;
2318 |
2319 | /*
2320 | * If the first packet do not contain the banner,
2321 | * it is dump in the middle of a flow or not a ssh at all
2322 | */
2323 | if (tvb_strncaseeql(tvb, offset, "SSH-", 4) != 0) {
2324 | offset = ssh_dissect_encrypted_packet(tvb, pinfo,
2325 | &global_data->peer_data[is_response], offset, tree);
2326 | return offset;
2327 | }
2328 |
2329 | if (!is_response) {
2330 | if (tvb_strncaseeql(tvb, offset, "SSH-2.", 6) == 0) {
2331 | *(version) = SSH_VERSION_22;
2332 | } else if (tvb_strncaseeql(tvb, offset, "SSH-1.99-", 9) == 0) {
2333 | *(version) = SSH_VERSION_22;
2334 | } else if (tvb_strncaseeql(tvb, offset, "SSH-1.", 6) == 0) {
2335 | *(version) = SSH_VERSION_11;
2336 | }
2337 | }
2338 |
2339 | if (!tvb_find_line_end_remaining(tvb, offset, &protolen, &next_offset)) {
2340 | if (ssh_desegment && pinfo->can_desegment) {
2341 | pinfo->desegment_offset = offset;
2342 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
2343 | *need_desegmentation = true1;
2344 | return offset;
2345 | }
2346 | }
2347 | /* Either we found it, or we're not reassembling and take everything. */
2348 |
2349 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Protocol (%s)",
2350 | tvb_format_text(pinfo->pool, tvb, offset, protolen));
2351 |
2352 | // V_C / V_S (client and server identification strings) RFC4253 4.2
2353 | // format: SSH-protoversion-softwareversion SP comments [CR LF not incl.]
2354 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2355 | uint8_t *data = (uint8_t *)tvb_memdup(pinfo->pool, tvb, offset, protolen);
2356 | if(!is_response){
2357 | ssh_hash_buffer_put_string(global_data->kex_client_version, data, protolen);
2358 | }else{
2359 | ssh_hash_buffer_put_string(global_data->kex_server_version, data, protolen);
2360 | }
2361 | }
2362 |
2363 | proto_tree_add_item(tree, hf_ssh_protocol,
2364 | tvb, offset, protolen, ENC_ASCII0x00000000);
2365 | offset += next_offset;
2366 | return offset;
2367 | }
2368 |
2369 | static void
2370 | ssh_set_mac_length(struct ssh_peer_data *peer_data)
2371 | {
2372 | char *size_str;
2373 | uint32_t size = 0;
2374 | char *mac_name = peer_data->mac;
2375 | char *strip;
2376 |
2377 | if (!mac_name)
2378 | return;
2379 |
2380 | /* wmem_strdup() never returns NULL */
2381 | mac_name = wmem_strdup(NULL((void*)0), (const char *)mac_name);
2382 |
2383 | /* strip trailing "-etm@openssh.com" or "@openssh.com" */
2384 | strip = strstr(mac_name, "-etm@openssh.com");
2385 | if (strip) {
2386 | peer_data->length_is_plaintext = 1;
2387 | *strip = '\0';
2388 | }
2389 | else {
2390 | strip = strstr(mac_name, "@openssh.com");
2391 | if (strip) *strip = '\0';
2392 | }
2393 |
2394 | size_str = g_strrstr(mac_name, "-");
2395 | if (size_str && ws_strtou32(size_str + 1, NULL((void*)0), &size) && size > 0 && size % 8 == 0) {
2396 | peer_data->mac_length = size / 8;
2397 | }
2398 | else if (strcmp(mac_name, "hmac-sha1") == 0) {
2399 | peer_data->mac_length = 20;
2400 | }
2401 | else if (strcmp(mac_name, "hmac-md5") == 0) {
2402 | peer_data->mac_length = 16;
2403 | }
2404 | else if (strcmp(mac_name, "hmac-ripemd160") == 0) {
2405 | peer_data->mac_length = 20;
2406 | }
2407 | else if (strcmp(mac_name, "none") == 0) {
2408 | peer_data->mac_length = 0;
2409 | }
2410 |
2411 | wmem_free(NULL((void*)0), mac_name);
2412 | }
2413 |
2414 | static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data)
2415 | {
2416 | const char *kex_name = global_data->kex;
2417 |
2418 | if (!kex_name) return;
2419 |
2420 | if (strcmp(kex_name, "diffie-hellman-group-exchange-sha1") == 0 ||
2421 | strcmp(kex_name, "diffie-hellman-group-exchange-sha256") == 0)
2422 | {
2423 | global_data->kex_specific_dissector = ssh_dissect_kex_dh_gex;
2424 | }
2425 | else if (g_str_has_prefix(kex_name, "ecdh-sha2-")(__builtin_constant_p ("ecdh-sha2-")? __extension__ ({ const char * const __str = (kex_name); const char * const __prefix = ("ecdh-sha2-" ); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix ))); if (__str_len >= __prefix_len) __result = memcmp (((__str ) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0 ; } __result; }) : (g_str_has_prefix) (kex_name, "ecdh-sha2-" ) ) ||
2426 | strcmp(kex_name, "curve25519-sha256@libssh.org") == 0 ||
2427 | strcmp(kex_name, "curve25519-sha256") == 0 ||
2428 | strcmp(kex_name, "curve448-sha512") == 0)
2429 | {
2430 | global_data->kex_specific_dissector = ssh_dissect_kex_ecdh;
2431 | }
2432 | else if (strcmp(kex_name, "diffie-hellman-group14-sha256") == 0 ||
2433 | strcmp(kex_name, "diffie-hellman-group16-sha512") == 0 ||
2434 | strcmp(kex_name, "diffie-hellman-group18-sha512") == 0 ||
2435 | strcmp(kex_name, "diffie-hellman-group1-sha1") == 0 ||
2436 | strcmp(kex_name, "diffie-hellman-group14-sha1") == 0)
2437 | {
2438 | global_data->kex_specific_dissector = ssh_dissect_kex_dh;
2439 | }
2440 | else if (g_str_has_prefix(kex_name, "sntrup761x25519-sha512")(__builtin_constant_p ("sntrup761x25519-sha512")? __extension__ ({ const char * const __str = (kex_name); const char * const __prefix = ("sntrup761x25519-sha512"); gboolean __result = ( 0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len ) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix )), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) ( kex_name, "sntrup761x25519-sha512") ) ||
2441 | strcmp(kex_name, "mlkem768x25519-sha256") == 0 ||
2442 | strcmp(kex_name, "mlkem768nistp256-sha256") == 0 ||
2443 | strcmp(kex_name, "mlkem1024nistp384-sha384") == 0)
2444 | {
2445 | global_data->kex_specific_dissector = ssh_dissect_kex_pq_hybrid;
2446 | }
2447 | else
2448 | {
2449 | ws_warning("NOT SUPPORTED OR UNKNOWN KEX DETECTED: ALGORITHM = %s", kex_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_WARNING, "epan/dissectors/packet-ssh.c" , 2449, __func__, "NOT SUPPORTED OR UNKNOWN KEX DETECTED: ALGORITHM = %s" , kex_name); } } while (0);
2450 | }
2451 | }
2452 |
2453 | static int
2454 | ssh_gslist_compare_strings(const void *a, const void *b)
2455 | {
2456 | if (a == NULL((void*)0) && b == NULL((void*)0))
2457 | return 0;
2458 | if (a == NULL((void*)0))
2459 | return -1;
2460 | if (b == NULL((void*)0))
2461 | return 1;
2462 | return strcmp((const char*)a, (const char*)b);
2463 | }
2464 |
2465 | /* expects that *result is NULL */
2466 | static bool_Bool
2467 | ssh_choose_algo(char *client, char *server, char **result)
2468 | {
2469 | char **server_strings = NULL((void*)0);
2470 | char **client_strings = NULL((void*)0);
2471 | char **step;
2472 | GSList *server_list = NULL((void*)0);
2473 |
2474 | static const char* client_strict = "kex-strict-c-v00@openssh.com";
2475 | static const char* server_strict = "kex-strict-s-v00@openssh.com";
2476 | bool_Bool kex_strict = false0;
2477 |
2478 | if (!client || !server || !result || *result)
2479 | return false0;
2480 |
2481 | server_strings = g_strsplit(server, ",", 0);
2482 | for (step = server_strings; *step; step++) {
2483 | server_list = g_slist_append(server_list, *step);
2484 | }
2485 |
2486 | client_strings = g_strsplit(client, ",", 0);
2487 | for (step = client_strings; *step; step++) {
2488 | GSList *agreed;
2489 | if ((agreed = g_slist_find_custom(server_list, *step, ssh_gslist_compare_strings))) {
2490 | *result = wmem_strdup(wmem_file_scope(), (const char *)agreed->data);
2491 | break;
2492 | }
2493 | }
2494 |
2495 | /* Check for the OpenSSH strict key exchange extension designed to
2496 | * mitigate the Terrapin attack by resetting the packet sequence
2497 | * number to zero after a SSH2_MSG_NEWKEYS message.
2498 | * https://www.openssh.com/txt/release-9.6
2499 | * Also see PROTOCOL in the OpenSSH source distribution.
2500 | *
2501 | * OpenSSH says this is activated "when an endpoint that supports this
2502 | * extension observes this algorithm name in a peer's KEXINIT packet".
2503 | * We'll have to assume that any endpoint that supports this also
2504 | * indicates support for it in its own first SSH2_MSG_KEXINIT.
2505 | */
2506 | if (g_strv_contains((const char* const*)client_strings, client_strict) &&
2507 | g_strv_contains((const char* const*)server_strings, server_strict)) {
2508 |
2509 | kex_strict = true1;
2510 | }
2511 |
2512 | g_strfreev(client_strings);
2513 | g_slist_free(server_list);
2514 | g_strfreev(server_strings);
2515 |
2516 | return kex_strict;
2517 | }
2518 |
2519 | static int
2520 | ssh_dissect_key_init(tvbuff_t *tvb, packet_info *pinfo, int offset,
2521 | proto_tree *tree, int is_response, struct ssh_flow_data *global_data)
2522 | {
2523 | int start_offset = offset;
2524 | int payload_length;
2525 | wmem_strbuf_t *hassh_algo;
2526 | char *hassh;
2527 |
2528 | proto_item *tf, *ti;
2529 | proto_tree *key_init_tree;
2530 |
2531 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response];
2532 |
2533 | key_init_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_key_init, &tf, "Algorithms");
2534 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2535 | peer_data->bn_cookie = ssh_kex_make_bignum(tvb_get_ptr(tvb, offset, 16), 16);
2536 | }
2537 | proto_tree_add_item(key_init_tree, hf_ssh_cookie,
2538 | tvb, offset, 16, ENC_NA0x00000000);
2539 | offset += 16;
2540 |
2541 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2542 | hf_ssh_kex_algorithms_length, hf_ssh_kex_algorithms,
2543 | &peer_data->kex_proposal);
2544 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2545 | hf_ssh_server_host_key_algorithms_length,
2546 | hf_ssh_server_host_key_algorithms, NULL((void*)0));
2547 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2548 | hf_ssh_encryption_algorithms_client_to_server_length,
2549 | hf_ssh_encryption_algorithms_client_to_server,
2550 | &peer_data->enc_proposals[CLIENT_TO_SERVER_PROPOSAL0]);
2551 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2552 | hf_ssh_encryption_algorithms_server_to_client_length,
2553 | hf_ssh_encryption_algorithms_server_to_client,
2554 | &peer_data->enc_proposals[SERVER_TO_CLIENT_PROPOSAL1]);
2555 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2556 | hf_ssh_mac_algorithms_client_to_server_length,
2557 | hf_ssh_mac_algorithms_client_to_server,
2558 | &peer_data->mac_proposals[CLIENT_TO_SERVER_PROPOSAL0]);
2559 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2560 | hf_ssh_mac_algorithms_server_to_client_length,
2561 | hf_ssh_mac_algorithms_server_to_client,
2562 | &peer_data->mac_proposals[SERVER_TO_CLIENT_PROPOSAL1]);
2563 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2564 | hf_ssh_compression_algorithms_client_to_server_length,
2565 | hf_ssh_compression_algorithms_client_to_server,
2566 | &peer_data->comp_proposals[CLIENT_TO_SERVER_PROPOSAL0]);
2567 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2568 | hf_ssh_compression_algorithms_server_to_client_length,
2569 | hf_ssh_compression_algorithms_server_to_client,
2570 | &peer_data->comp_proposals[SERVER_TO_CLIENT_PROPOSAL1]);
2571 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2572 | hf_ssh_languages_client_to_server_length,
2573 | hf_ssh_languages_client_to_server, NULL((void*)0));
2574 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree,
2575 | hf_ssh_languages_server_to_client_length,
2576 | hf_ssh_languages_server_to_client, NULL((void*)0));
2577 |
2578 | proto_tree_add_item(key_init_tree, hf_ssh_first_kex_packet_follows,
2579 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
2580 | offset+=1;
2581 |
2582 | proto_tree_add_item(key_init_tree, hf_ssh_kex_reserved,
2583 | tvb, offset, 4, ENC_NA0x00000000);
2584 | offset+=4;
2585 |
2586 | hassh_algo = wmem_strbuf_new(pinfo->pool, "");
2587 | if(!is_response) {
2588 | wmem_strbuf_append_printf(hassh_algo, "%s;%s;%s;%s", peer_data->kex_proposal, peer_data->enc_proposals[CLIENT_TO_SERVER_PROPOSAL0],
2589 | peer_data->mac_proposals[CLIENT_TO_SERVER_PROPOSAL0], peer_data->comp_proposals[CLIENT_TO_SERVER_PROPOSAL0]);
2590 | hassh = g_compute_checksum_for_string(G_CHECKSUM_MD5, wmem_strbuf_get_str(hassh_algo), wmem_strbuf_get_len(hassh_algo));
2591 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hassh_algo, tvb, offset, 0, wmem_strbuf_get_str(hassh_algo));
2592 | proto_item_set_generated(ti);
2593 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hassh, tvb, offset, 0, hassh);
2594 | proto_item_set_generated(ti);
2595 | g_free(hassh)(__builtin_object_size ((hassh), 0) != ((size_t) - 1)) ? g_free_sized (hassh, __builtin_object_size ((hassh), 0)) : (g_free) (hassh );
2596 | } else {
2597 | wmem_strbuf_append_printf(hassh_algo, "%s;%s;%s;%s", peer_data->kex_proposal, peer_data->enc_proposals[SERVER_TO_CLIENT_PROPOSAL1],
2598 | peer_data->mac_proposals[SERVER_TO_CLIENT_PROPOSAL1], peer_data->comp_proposals[SERVER_TO_CLIENT_PROPOSAL1]);
2599 | hassh = g_compute_checksum_for_string(G_CHECKSUM_MD5, wmem_strbuf_get_str(hassh_algo), wmem_strbuf_get_len(hassh_algo));
2600 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hasshserver_algo, tvb, offset, 0, wmem_strbuf_get_str(hassh_algo));
2601 | proto_item_set_generated(ti);
2602 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hasshserver, tvb, offset, 0, hassh);
2603 | proto_item_set_generated(ti);
2604 | g_free(hassh)(__builtin_object_size ((hassh), 0) != ((size_t) - 1)) ? g_free_sized (hassh, __builtin_object_size ((hassh), 0)) : (g_free) (hassh );
2605 | }
2606 |
2607 | if (global_data->peer_data[CLIENT_PEER_DATA0].kex_proposal &&
2608 | global_data->peer_data[SERVER_PEER_DATA1].kex_proposal &&
2609 | !global_data->kex)
2610 | {
2611 | /* Note: we're ignoring first_kex_packet_follows. */
2612 | global_data->ext_kex_strict = ssh_choose_algo(
2613 | global_data->peer_data[CLIENT_PEER_DATA0].kex_proposal,
2614 | global_data->peer_data[SERVER_PEER_DATA1].kex_proposal,
2615 | &global_data->kex);
2616 | ssh_set_kex_specific_dissector(global_data);
2617 | }
2618 |
2619 | payload_length = offset - start_offset;
2620 |
2621 | if (tf != NULL((void*)0)) {
2622 | proto_item_set_len(tf, payload_length);
2623 | }
2624 |
2625 | // I_C / I_S (client and server SSH_MSG_KEXINIT payload) RFC4253 4.2
2626 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
2627 | uint8_t *data = (uint8_t *)wmem_alloc(pinfo->pool, payload_length + 1);
2628 | tvb_memcpy(tvb, data + 1, start_offset, payload_length);
2629 | data[0] = SSH_MSG_KEXINIT20;
2630 | if(is_response){
2631 | ssh_hash_buffer_put_string(global_data->kex_server_key_exchange_init, data, payload_length + 1);
2632 | }else{
2633 | // Reset array while REKEY: sanitize client key
2634 | global_data->kex_client_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
2635 | ssh_hash_buffer_put_string(global_data->kex_client_key_exchange_init, data, payload_length + 1);
2636 | }
2637 | }
2638 |
2639 | return offset;
2640 | }
2641 |
2642 | static int
2643 | ssh_dissect_proposal(tvbuff_t *tvb, int offset, proto_tree *tree,
2644 | int hf_index_length, int hf_index_value, char **store)
2645 | {
2646 | uint32_t len = tvb_get_ntohl(tvb, offset);
2647 | proto_tree_add_uint(tree, hf_index_length, tvb, offset, 4, len);
2648 | offset += 4;
2649 |
2650 | proto_tree_add_item(tree, hf_index_value, tvb, offset, len,
2651 | ENC_ASCII0x00000000);
2652 | if (store)
2653 | *store = (char *) tvb_get_string_enc(wmem_file_scope(), tvb, offset, len, ENC_ASCII0x00000000);
2654 | offset += len;
2655 |
2656 | return offset;
2657 | }
2658 |
2659 | static void
2660 | ssh_keylog_read_file(void)
2661 | {
2662 | if (!pref_keylog_file || !*pref_keylog_file) {
11 | ← | Assuming 'pref_keylog_file' is non-null | →
12 | ← | Assuming the condition is false | →
2663 | ws_debug("no keylog file preference set")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2663, __func__, "no keylog file preference set"); } } while (0);
2664 | return;
2665 | }
2666 |
2667 | if (ssh_keylog_file && file_needs_reopen(ws_filenofileno(ssh_keylog_file),
13 | ← | Assuming 'ssh_keylog_file' is non-null | →
14 | ← | Assuming the condition is false | →
15 | ← | Taking false branch | →
2668 | pref_keylog_file)) {
2669 | ssh_keylog_reset();
2670 | g_hash_table_remove_all(ssh_master_key_map);
2671 | }
2672 |
2673 | if (!ssh_keylog_file) {
16 | ← | Assuming 'ssh_keylog_file' is non-null | →
17 | ← | Taking false branch | →
2674 | ssh_keylog_file = ws_fopenfopen(pref_keylog_file, "r");
2675 | if (!ssh_keylog_file) {
2676 | ws_debug("ssh: failed to open key log file %s: %s",do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2677, __func__, "ssh: failed to open key log file %s: %s", pref_keylog_file , g_strerror((*__errno_location ()))); } } while (0)
2677 | pref_keylog_file, g_strerror(errno))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2677, __func__, "ssh: failed to open key log file %s: %s", pref_keylog_file , g_strerror((*__errno_location ()))); } } while (0);
2678 | return;
2679 | }
2680 | }
2681 |
2682 | /* File format: each line follows the format "<cookie> <type> <key>".
2683 | * <cookie> is the hex-encoded (client or server) 16 bytes cookie
2684 | * (32 characters) found in the SSH_MSG_KEXINIT of the endpoint whose
2685 | * private random is disclosed.
2686 | * <type> is either SHARED_SECRET or PRIVATE_KEY depending on the
2687 | * type of key provided. PRIVAT_KEY is only supported for DH,
2688 | * DH group exchange, and ECDH (including Curve25519) key exchanges.
2689 | * <key> is the private random number that is used to generate the DH
2690 | * negotiation (length depends on algorithm). In RFC4253 it is called
2691 | * x for the client and y for the server.
2692 | * For openssh and DH group exchange, it can be retrieved using
2693 | * DH_get0_key(kex->dh, NULL, &server_random)
2694 | * for groupN in file kexdh.c function kex_dh_compute_key
2695 | * for custom group in file kexgexs.c function input_kex_dh_gex_init
2696 | * For openssh and curve25519, it can be found in function kex_c25519_enc
2697 | * in variable server_key. One may also provide the shared secret
2698 | * directly if <type> is set to SHARED_SECRET.
2699 | *
2700 | * Example:
2701 | * 90d886612f9c35903db5bb30d11f23c2 PRIVATE_KEY DEF830C22F6C927E31972FFB20B46C96D0A5F2D5E7BE5A3A8804D6BFC431619ED10AF589EEDFF4750DEA00EFD7AFDB814B6F3528729692B1F2482041521AE9DC
2702 | */
2703 | for (;;) {
18 | ← | Loop condition is true. Entering loop body | →
2704 | // XXX - What is a reasonable max line length here? Note at a certain
2705 | // point we have to increase the maximum ssh_kex_make_bignum supports (not needed for post quantum material (pure binary)).
2706 | char buf[4096];// 4096 is needed for mlkem1024 private_key binary meterial: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
2707 | buf[0] = 0;
2708 |
2709 | if (!fgets(buf, sizeof(buf), ssh_keylog_file)) {
19 | ← | Taking true branch | →
2710 | rewind(ssh_keylog_file); // Resets to start of file (to handle parallel multi sessions decryption)
20 | ← | After calling 'rewind' reading 'errno' is required to find out if the call has failed | →
2711 | if (ferror(ssh_keylog_file)) {
21 | ← | Value of 'errno' was not checked and may be overwritten by function 'ferror'
2712 | ws_debug("Error while reading %s, closing it.", pref_keylog_file)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2712, __func__, "Error while reading %s, closing it.", pref_keylog_file ); } } while (0);
2713 | ssh_keylog_reset();
2714 | g_hash_table_remove_all(ssh_master_key_map);
2715 | }
2716 | break;
2717 | }
2718 |
2719 | size_t len = strlen(buf);
2720 | while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n')){len-=1;buf[len]=0;}
2721 | ws_noisy("ssh: raw keylog line read: %s", buf)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 2721, __func__, "ssh: raw keylog line read: %s", buf); } } while (0);
2722 |
2723 | ssh_keylog_process_line(buf);
2724 | }
2725 | }
2726 |
2727 | static void
2728 | ssh_keylog_process_lines(const uint8_t *data, unsigned datalen)
2729 | {
2730 | const char *next_line = (const char *)data;
2731 | const char *line_end = next_line + datalen;
2732 | while (next_line && next_line < line_end) {
2733 | const char *line = next_line;
2734 | next_line = (const char *)memchr(line, '\n', line_end - line);
2735 | ssize_t linelen;
2736 |
2737 | if (next_line) {
2738 | linelen = next_line - line;
2739 | next_line++; /* drop LF */
2740 | } else {
2741 | linelen = (ssize_t)(line_end - line);
2742 | }
2743 | if (linelen > 0 && line[linelen - 1] == '\r') {
2744 | linelen--; /* drop CR */
2745 | }
2746 |
2747 | ssh_debug_printf(" checking keylog line: %.*s\n", (int)linelen, line);
2748 | ws_noisy("ssh: about to process line: %.*s", (int)linelen, line)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 2748, __func__, "ssh: about to process line: %.*s", (int)linelen , line); } } while (0);
2749 |
2750 | char * strippedline = g_strndup(line, linelen);
2751 | ssh_keylog_process_line(strippedline);
2752 | g_free(strippedline)(__builtin_object_size ((strippedline), 0) != ((size_t) - 1)) ? g_free_sized (strippedline, __builtin_object_size ((strippedline ), 0)) : (g_free) (strippedline);
2753 | }
2754 | }
2755 |
2756 | static void
2757 | ssh_keylog_process_line(const char *line)
2758 | {
2759 | ws_noisy("ssh: process line: %s", line)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 2759, __func__, "ssh: process line: %s", line); } } while ( 0);
2760 |
2761 | char **split = g_strsplit(line, " ", 3);
2762 | char *cookie, *type, *key;
2763 | size_t cookie_len, key_len;
2764 |
2765 | if (g_strv_length(split) == 3) {
2766 | // New format: [hex-encoded cookie] [key type] [hex-encoded key material]
2767 | cookie = split[0];
2768 | type = split[1];
2769 | key = split[2];
2770 | } else if (g_strv_length(split) == 2) {
2771 | // Old format: [hex-encoded cookie] [hex-encoded private key]
2772 | ws_debug("ssh keylog: detected old keylog format without explicit key type")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2772, __func__, "ssh keylog: detected old keylog format without explicit key type" ); } } while (0);
2773 | type = "PRIVATE_KEY";
2774 | cookie = split[0];
2775 | key = split[1];
2776 | } else {
2777 | ws_info("ssh keylog: invalid format")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_INFO, ((void *)0), -1, ((void*)0), "ssh keylog: invalid format"); } } while (0);
2778 | g_strfreev(split);
2779 | return;
2780 | }
2781 |
2782 | key_len = strlen(key);
2783 | cookie_len = strlen(cookie);
2784 | if(key_len & 1){
2785 | ws_info("ssh keylog: invalid format (key should at least be even!)")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_INFO, ((void *)0), -1, ((void*)0), "ssh keylog: invalid format (key should at least be even!)" ); } } while (0);
2786 | g_strfreev(split);
2787 | return;
2788 | }
2789 | if(cookie_len & 1){
2790 | ws_info("ssh keylog: invalid format (cookie should at least be even!)")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_INFO, ((void *)0), -1, ((void*)0), "ssh keylog: invalid format (cookie should at least be even!)" ); } } while (0);
2791 | g_strfreev(split);
2792 | return;
2793 | }
2794 | ssh_bignum * bn_cookie = ssh_kex_make_bignum(NULL((void*)0), (unsigned)(cookie_len/2));
2795 | if (bn_cookie == NULL((void*)0)) {
2796 | ws_info("ssh keylog: invalid format (invalid cookie length %zu)", cookie_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_INFO, ((void *)0), -1, ((void*)0), "ssh keylog: invalid format (invalid cookie length %zu)" , cookie_len); } } while (0);
2797 | g_strfreev(split);
2798 | return;
2799 | }
2800 | ssh_bignum * bn_priv = ssh_kex_make_bignum(NULL((void*)0), (unsigned)(key_len/2));
2801 | if (bn_priv == NULL((void*)0)) {
2802 | ws_info("ssh keylog: invalid format (invalid key length %zu)", key_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_INFO, ((void *)0), -1, ((void*)0), "ssh keylog: invalid format (invalid key length %zu)" , key_len); } } while (0);
2803 | g_strfreev(split);
2804 | return;
2805 | }
2806 | uint8_t c;
2807 | for (size_t i = 0; i < key_len/2; i ++) {
2808 | char v0 = key[i * 2];
2809 | int8_t h0 = ws_xton(v0);
2810 | char v1 = key[i * 2 + 1];
2811 | int8_t h1 = ws_xton(v1);
2812 |
2813 | if (h0==-1 || h1==-1) {
2814 | ws_debug("ssh: can't process key, invalid hex number: %c%c", v0, v1)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2814, __func__, "ssh: can't process key, invalid hex number: %c%c" , v0, v1); } } while (0);
2815 | g_strfreev(split);
2816 | return;
2817 | }
2818 |
2819 | c = (h0 << 4) | h1;
2820 |
2821 | bn_priv->data[i] = c;
2822 | }
2823 | for (size_t i = 0; i < cookie_len/2; i ++) {
2824 | char v0 = cookie[i * 2];
2825 | int8_t h0 = ws_xton(v0);
2826 | char v1 = cookie[i * 2 + 1];
2827 | int8_t h1 = ws_xton(v1);
2828 |
2829 | if (h0==-1 || h1==-1) {
2830 | ws_debug("ssh: can't process cookie, invalid hex number: %c%c", v0, v1)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2830, __func__, "ssh: can't process cookie, invalid hex number: %c%c" , v0, v1); } } while (0);
2831 | g_strfreev(split);
2832 | return;
2833 | }
2834 |
2835 | c = (h0 << 4) | h1;
2836 |
2837 | bn_cookie->data[i] = c;
2838 | }
2839 | ssh_bignum * bn_priv_ht = g_new(ssh_bignum, 1)((ssh_bignum *) g_malloc_n ((1), sizeof (ssh_bignum)));
2840 | bn_priv_ht->length = bn_priv->length;
2841 | bn_priv_ht->data = (uint8_t *) g_memdup2(bn_priv->data, bn_priv->length);
2842 | ssh_bignum * bn_cookie_ht = g_new(ssh_bignum, 1)((ssh_bignum *) g_malloc_n ((1), sizeof (ssh_bignum)));
2843 | bn_cookie_ht->length = bn_cookie->length;
2844 | bn_cookie_ht->data = (uint8_t *) g_memdup2(bn_cookie->data, bn_cookie->length);
2845 |
2846 | char * type_ht = (char *) g_memdup2(type, strlen(type) + 1);
2847 | ssh_key_map_entry_t * entry_ht = g_new(ssh_key_map_entry_t, 1)((ssh_key_map_entry_t *) g_malloc_n ((1), sizeof (ssh_key_map_entry_t )));
2848 | entry_ht->type = type_ht;
2849 | entry_ht->key_material = bn_priv_ht;
2850 | g_hash_table_insert(ssh_master_key_map, bn_cookie_ht, entry_ht);
2851 | g_strfreev(split);
2852 | }
2853 |
2854 | static void
2855 | ssh_keylog_reset(void)
2856 | {
2857 | if (ssh_keylog_file) {
2858 | fclose(ssh_keylog_file);
2859 | ssh_keylog_file = NULL((void*)0);
2860 | }
2861 | }
2862 |
2863 | static unsigned
2864 | ssh_kex_type(char *type)
2865 | {
2866 | if (type) {
2867 | if (g_str_has_prefix(type, "curve25519")(__builtin_constant_p ("curve25519")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("curve25519" ); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix ))); if (__str_len >= __prefix_len) __result = memcmp (((__str ) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0 ; } __result; }) : (g_str_has_prefix) (type, "curve25519") )) {
2868 | return SSH_KEX_CURVE255190x00010000;
2869 | }else if (g_str_has_prefix(type, "sntrup761x25519")(__builtin_constant_p ("sntrup761x25519")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ( "sntrup761x25519"); gboolean __result = (0); if (__str == ((void *)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (( (__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix ) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "sntrup761x25519" ) )) {
2870 | return SSH_KEX_SNTRUP761X255190x00040000;
2871 | }else if (g_str_has_prefix(type, "mlkem768x25519")(__builtin_constant_p ("mlkem768x25519")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ( "mlkem768x25519"); gboolean __result = (0); if (__str == ((void *)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (( (__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix ) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "mlkem768x25519" ) )) {
2872 | return SSH_KEX_MLKEM768X255190x00050000;
2873 | }else if (g_str_has_prefix(type, "diffie-hellman-group-exchange")(__builtin_constant_p ("diffie-hellman-group-exchange")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("diffie-hellman-group-exchange"); gboolean __result = (0) ; if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if (__str_len >= __prefix_len ) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix )), __prefix_len) == 0; } __result; }) : (g_str_has_prefix) ( type, "diffie-hellman-group-exchange") )) {
2874 | return SSH_KEX_DH_GEX0x00020000;
2875 | }else if (g_str_has_prefix(type, "diffie-hellman-group14")(__builtin_constant_p ("diffie-hellman-group14")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("diffie-hellman-group14"); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "diffie-hellman-group14" ) )) {
2876 | return SSH_KEX_DH_GROUP140x00030014;
2877 | }else if (g_str_has_prefix(type, "diffie-hellman-group16")(__builtin_constant_p ("diffie-hellman-group16")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("diffie-hellman-group16"); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "diffie-hellman-group16" ) )) {
2878 | return SSH_KEX_DH_GROUP160x00030016;
2879 | }else if (g_str_has_prefix(type, "diffie-hellman-group18")(__builtin_constant_p ("diffie-hellman-group18")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("diffie-hellman-group18"); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "diffie-hellman-group18" ) )) {
2880 | return SSH_KEX_DH_GROUP180x00030018;
2881 | }else if (g_str_has_prefix(type, "diffie-hellman-group1")(__builtin_constant_p ("diffie-hellman-group1")? __extension__ ({ const char * const __str = (type); const char * const __prefix = ("diffie-hellman-group1"); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix ) (__str, __prefix); else { const size_t __str_len = strlen ( ((__str) + !(__str))); const size_t __prefix_len = strlen ((( __prefix) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (type, "diffie-hellman-group1" ) )) {
2882 | return SSH_KEX_DH_GROUP10x00030001;
2883 | }
2884 | }
2885 |
2886 | return 0;
2887 | }
2888 |
2889 | static unsigned
2890 | ssh_kex_hash_type(char *type_string)
2891 | {
2892 | if (type_string && g_str_has_suffix(type_string, "sha1")(__builtin_constant_p ("sha1")? __extension__ ({ const char * const __str = (type_string); const char * const __suffix = ( "sha1"); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix ))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len ) == 0; } __result; }) : (g_str_has_suffix) (type_string, "sha1" ) )) {
2893 | return SSH_KEX_HASH_SHA11;
2894 | }else if (type_string && g_str_has_suffix(type_string, "sha256")(__builtin_constant_p ("sha256")? __extension__ ({ const char * const __str = (type_string); const char * const __suffix = ("sha256"); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str , __suffix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __suffix_len = strlen (((__suffix ) + !(__suffix))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !( __suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix ) (type_string, "sha256") )) {
2895 | return SSH_KEX_HASH_SHA2562;
2896 | }else if (type_string && g_str_has_suffix(type_string, "sha256@libssh.org")(__builtin_constant_p ("sha256@libssh.org")? __extension__ ({ const char * const __str = (type_string); const char * const __suffix = ("sha256@libssh.org"); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = ( g_str_has_suffix) (__str, __suffix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix))); if (__str_len >= __suffix_len ) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix ) + !(__suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix ) (type_string, "sha256@libssh.org") )) {
2897 | return SSH_KEX_HASH_SHA2562;
2898 | }else if (type_string && g_str_has_suffix(type_string, "sha512")(__builtin_constant_p ("sha512")? __extension__ ({ const char * const __str = (type_string); const char * const __suffix = ("sha512"); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str , __suffix); else { const size_t __str_len = strlen (((__str) + !(__str))); const size_t __suffix_len = strlen (((__suffix ) + !(__suffix))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !( __suffix)), __suffix_len) == 0; } __result; }) : (g_str_has_suffix ) (type_string, "sha512") )) {
2899 | return SSH_KEX_HASH_SHA5124;
2900 | } else {
2901 | ws_debug("hash type %s not supported", type_string)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2901, __func__, "hash type %s not supported", type_string); } } while (0);
2902 | return 0;
2903 | }
2904 | }
2905 |
2906 | static ssh_bignum *
2907 | ssh_kex_make_bignum(const uint8_t *data, unsigned length)
2908 | {
2909 | // 512 bytes (4096 bits) is the maximum bignum size we're supporting
2910 | // Actually we need 513 bytes, to make provision for signed values
2911 | // Diffie-Hellman group 18 has 8192 bits
2912 | if (length == 0 || length > 1025) {
2913 | return NULL((void*)0);
2914 | }
2915 |
2916 | ssh_bignum *bn = wmem_new0(wmem_file_scope(), ssh_bignum)((ssh_bignum*)wmem_alloc0((wmem_file_scope()), sizeof(ssh_bignum )));
2917 | bn->data = (uint8_t *)wmem_alloc0(wmem_file_scope(), length);
2918 |
2919 | if (data) {
2920 | memcpy(bn->data, data, length);
2921 | }
2922 |
2923 | bn->length = length;
2924 | return bn;
2925 | }
2926 |
2927 | static bool_Bool
2928 | ssh_read_e(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
2929 | {
2930 | // store the client's public part (e) for later usage
2931 | uint32_t length = tvb_get_ntohl(tvb, offset);
2932 | global_data->kex_e = ssh_kex_make_bignum(NULL((void*)0), length);
2933 | if (!global_data->kex_e) {
2934 | return false0;
2935 | }
2936 | tvb_memcpy(tvb, global_data->kex_e->data, offset + 4, length);
2937 | return true1;
2938 | }
2939 |
2940 | static bool_Bool
2941 | ssh_read_f(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
2942 | {
2943 | // store the server's public part (f) for later usage
2944 | uint32_t length = tvb_get_ntohl(tvb, offset);
2945 | global_data->kex_f = ssh_kex_make_bignum(NULL((void*)0), length);
2946 | if (!global_data->kex_f) {
2947 | return false0;
2948 | }
2949 | tvb_memcpy(tvb, global_data->kex_f->data, offset + 4, length);
2950 | return true1;
2951 | }
2952 |
2953 | static int // add support of client PQ hybrid key (e)
2954 | ssh_read_e_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
2955 | {
2956 | // Read length of PQ client key
2957 | uint32_t length = tvb_get_ntohl(tvb, offset);
2958 |
2959 | // Sanity check
2960 | if (length == 0 || length > 65535) {
2961 | ws_debug("ssh_read_e_pq: Invalid PQ key length: %u", length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2961, __func__, "ssh_read_e_pq: Invalid PQ key length: %u", length); } } while (0);
2962 | return false0;
2963 | }
2964 |
2965 | // Free any existing data (if dissecting multiple sessions)
2966 | wmem_free(wmem_file_scope(), global_data->kex_e_pq);
2967 |
2968 | // Allocate and store the PQ client key
2969 | global_data->kex_e_pq = (unsigned char *)wmem_alloc(wmem_file_scope(), length);
2970 | global_data->kex_e_pq_len = length;
2971 |
2972 | tvb_memcpy(tvb, global_data->kex_e_pq, offset + 4, length);
2973 |
2974 | ws_debug("Stored %u bytes of client PQ key - stored new_offset_client: %d - offset: %d", length, offset + 4 + length, offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2974, __func__, "Stored %u bytes of client PQ key - stored new_offset_client: %d - offset: %d" , length, offset + 4 + length, offset); } } while (0);
2975 | return offset + 4 + length; // consuming packet (advancing offset)
2976 | }
2977 |
2978 | static int // add support of server PQ hybrid key (f)
2979 | ssh_read_f_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data)
2980 | {
2981 | // Read length of PQ server key
2982 | uint32_t length = tvb_get_ntohl(tvb, offset);
2983 |
2984 | // Sanity check
2985 | if (length == 0 || length > 65535) {
2986 | ws_debug("ssh_read_f_pq: Invalid PQ key length: %u", length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2986, __func__, "ssh_read_f_pq: Invalid PQ key length: %u", length); } } while (0);
2987 | return false0;
2988 | }
2989 |
2990 | // Free any existing data
2991 | wmem_free(wmem_file_scope(), global_data->kex_f_pq);
2992 |
2993 | // Allocate and store the PQ server key
2994 | global_data->kex_f_pq = (unsigned char *)wmem_alloc(wmem_file_scope(), length);
2995 | global_data->kex_f_pq_len = length;
2996 |
2997 | tvb_memcpy(tvb, global_data->kex_f_pq, offset + 4, length);
2998 |
2999 | ws_debug("Stored %u bytes of server PQ key - stored new_offset_server: %d - offset: %d", length, offset + 4 + length, offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2999, __func__, "Stored %u bytes of server PQ key - stored new_offset_server: %d - offset: %d" , length, offset + 4 + length, offset); } } while (0);
3000 | return offset + 4 + length; // consuming packet (advancing offset)
3001 | }
3002 |
3003 |
3004 | static ssh_bignum *
3005 | ssh_read_mpint(tvbuff_t *tvb, int offset)
3006 | {
3007 | // store the DH group modulo (p) for later usage
3008 | int length = tvb_get_ntohl(tvb, offset);
3009 | ssh_bignum * bn = ssh_kex_make_bignum(NULL((void*)0), length);
3010 | if (!bn) {
3011 | ws_debug("invalid bignum length %u", length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3011, __func__, "invalid bignum length %u", length); } } while (0);
3012 | return NULL((void*)0);
3013 | }
3014 | tvb_memcpy(tvb, bn->data, offset + 4, length);
3015 | return bn;
3016 | }
3017 |
3018 | static void
3019 | ssh_keylog_hash_write_secret(struct ssh_flow_data *global_data, wmem_allocator_t* tmp_allocator)
3020 | {
3021 | /*
3022 | * This computation is defined differently for each key exchange method:
3023 | * https://tools.ietf.org/html/rfc4253#page-23
3024 | * https://tools.ietf.org/html/rfc5656#page-8
3025 | * https://tools.ietf.org/html/rfc4419#page-4
3026 | * All key exchange methods:
3027 | * https://www.iana.org/assignments/ssh-parameters/ssh-parameters.xhtml#ssh-parameters-16
3028 | */
3029 |
3030 | gcry_md_hd_t hd;
3031 | ssh_key_map_entry_t *entry;
3032 | ssh_bignum *secret = NULL((void*)0);
3033 | int length;
3034 | bool_Bool client_cookie = false0;
3035 |
3036 | ssh_keylog_read_file();
10 | ← | Calling 'ssh_keylog_read_file' | →
3037 |
3038 | unsigned kex_type = ssh_kex_type(global_data->kex);
3039 | unsigned kex_hash_type = ssh_kex_hash_type(global_data->kex);
3040 |
3041 | entry = (ssh_key_map_entry_t *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[SERVER_PEER_DATA1].bn_cookie);
3042 | if (!entry) {
3043 | entry = (ssh_key_map_entry_t *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[CLIENT_PEER_DATA0].bn_cookie);
3044 | client_cookie = true1;
3045 | }
3046 | if (!entry) {
3047 | ws_debug("ssh decryption: no entry in keylog file for this session")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3047, __func__, "ssh decryption: no entry in keylog file for this session" ); } } while (0);
3048 | global_data->do_decrypt = false0;
3049 | return;
3050 | }
3051 |
3052 | if (!strcmp(entry->type, "PRIVATE_KEY")) {
3053 | if (client_cookie) {
3054 | secret = ssh_kex_shared_secret(kex_type, global_data->kex_f, entry->key_material, global_data->kex_gex_p);
3055 | } else {
3056 | secret = ssh_kex_shared_secret(kex_type, global_data->kex_e, entry->key_material, global_data->kex_gex_p);
3057 | }
3058 | } else if (!strcmp(entry->type, "SHARED_SECRET")) {
3059 | secret = ssh_kex_make_bignum(entry->key_material->data, entry->key_material->length);
3060 | } else {
3061 | ws_debug("ssh decryption: unknown key type in keylog file")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3061, __func__, "ssh decryption: unknown key type in keylog file" ); } } while (0);
3062 | global_data->do_decrypt = false0;
3063 | return;
3064 | }
3065 |
3066 | if (!secret) {
3067 | ws_debug("ssh decryption: no key material for this session")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3067, __func__, "ssh decryption: no key material for this session" ); } } while (0);
3068 | global_data->do_decrypt = false0;
3069 | return;
3070 | }
3071 |
3072 | // shared secret data needs to be written as an mpint, and we need it later
3073 | if (kex_type == SSH_KEX_SNTRUP761X255190x00040000 || kex_type == SSH_KEX_MLKEM768X255190x00050000) {
3074 | // Reset array while REKEY: sanitize shared_secret:
3075 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1);
3076 | // For PQ KEMs: use shared_secret as-is, whether SHARED_SECRET or PRIVATE_KEY
3077 | // Do NOT prepend 0x00 (OpenSSH already encodes correctly for PQ KEM)
3078 | ssh_hash_buffer_put_string(global_data->kex_shared_secret, secret->data, secret->length);
3079 | } else {
3080 | // For all other KEX types (e.g., curve25519, ecdh-sha2, etc.)
3081 | // Pad with 0x00 if MSB is set, to comply with mpint format (RFC 4251)
3082 | if (secret->data[0] & 0x80) { // Stored in Big endian
3083 | length = secret->length + 1;
3084 | uint8_t *tmp = (uint8_t *)wmem_alloc0(tmp_allocator, length);
3085 | memcpy(tmp + 1, secret->data, secret->length);
3086 | tmp[0] = 0;
3087 | secret->data = tmp;
3088 | secret->length = length;
3089 | }
3090 | // Reset array while REKEY: sanitize shared_secret:
3091 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1);
3092 | ssh_hash_buffer_put_string(global_data->kex_shared_secret, secret->data, secret->length);
3093 | }
3094 |
3095 | wmem_array_t * kex_gex_p = wmem_array_new(tmp_allocator, 1);
3096 | if(global_data->kex_gex_p){ssh_hash_buffer_put_string(kex_gex_p, global_data->kex_gex_p->data, global_data->kex_gex_p->length);}
3097 | wmem_array_t * kex_gex_g = wmem_array_new(tmp_allocator, 1);
3098 | if(global_data->kex_gex_g){ssh_hash_buffer_put_string(kex_gex_g, global_data->kex_gex_g->data, global_data->kex_gex_g->length);}
3099 | wmem_array_t * kex_e = wmem_array_new(tmp_allocator, 1);
3100 | if(global_data->kex_e){ssh_hash_buffer_put_string(kex_e, global_data->kex_e->data, global_data->kex_e->length);}
3101 | wmem_array_t * kex_f = wmem_array_new(tmp_allocator, 1);
3102 | if(global_data->kex_f){ssh_hash_buffer_put_string(kex_f, global_data->kex_f->data, global_data->kex_f->length);}
3103 | wmem_array_t * kex_e_pq = wmem_array_new(tmp_allocator, 1);
3104 | if(global_data->kex_e_pq){ssh_hash_buffer_put_string(kex_e_pq, global_data->kex_e_pq, global_data->kex_e_pq_len);}
3105 | wmem_array_t * kex_f_pq = wmem_array_new(tmp_allocator, 1);
3106 | if(global_data->kex_f_pq){ssh_hash_buffer_put_string(kex_f_pq, global_data->kex_f_pq, global_data->kex_f_pq_len);}
3107 |
3108 | wmem_array_t * kex_hash_buffer = wmem_array_new(tmp_allocator, 1);
3109 | ssh_print_data("client_version", (const unsigned char *)wmem_array_get_raw(global_data->kex_client_version), wmem_array_get_count(global_data->kex_client_version));
3110 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_client_version), wmem_array_get_count(global_data->kex_client_version));
3111 | ssh_print_data("server_version", (const unsigned char *)wmem_array_get_raw(global_data->kex_server_version), wmem_array_get_count(global_data->kex_server_version));
3112 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_version), wmem_array_get_count(global_data->kex_server_version));
3113 | ssh_print_data("client_key_exchange_init", (const unsigned char *)wmem_array_get_raw(global_data->kex_client_key_exchange_init), wmem_array_get_count(global_data->kex_client_key_exchange_init));
3114 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_client_key_exchange_init), wmem_array_get_count(global_data->kex_client_key_exchange_init));
3115 | ssh_print_data("server_key_exchange_init", (const unsigned char *)wmem_array_get_raw(global_data->kex_server_key_exchange_init), wmem_array_get_count(global_data->kex_server_key_exchange_init));
3116 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_key_exchange_init), wmem_array_get_count(global_data->kex_server_key_exchange_init));
3117 | ssh_print_data("kex_server_host_key_blob", (const unsigned char *)wmem_array_get_raw(global_data->kex_server_host_key_blob), wmem_array_get_count(global_data->kex_server_host_key_blob));
3118 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_host_key_blob), wmem_array_get_count(global_data->kex_server_host_key_blob));
3119 | if(kex_type==SSH_KEX_DH_GEX0x00020000){
3120 | ssh_print_data("kex_gex_bits_min", (const unsigned char *)wmem_array_get_raw(global_data->kex_gex_bits_min), wmem_array_get_count(global_data->kex_gex_bits_min));
3121 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_gex_bits_min), wmem_array_get_count(global_data->kex_gex_bits_min));
3122 | ssh_print_data("kex_gex_bits_req", (const unsigned char *)wmem_array_get_raw(global_data->kex_gex_bits_req), wmem_array_get_count(global_data->kex_gex_bits_req));
3123 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_gex_bits_req), wmem_array_get_count(global_data->kex_gex_bits_req));
3124 | ssh_print_data("kex_gex_bits_max", (const unsigned char *)wmem_array_get_raw(global_data->kex_gex_bits_max), wmem_array_get_count(global_data->kex_gex_bits_max));
3125 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_gex_bits_max), wmem_array_get_count(global_data->kex_gex_bits_max));
3126 | ssh_print_data("key modulo (p)", (const unsigned char *)wmem_array_get_raw(kex_gex_p), wmem_array_get_count(kex_gex_p));
3127 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_gex_p), wmem_array_get_count(kex_gex_p));
3128 | ssh_print_data("key base (g)", (const unsigned char *)wmem_array_get_raw(kex_gex_g), wmem_array_get_count(kex_gex_g));
3129 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_gex_g), wmem_array_get_count(kex_gex_g));
3130 | ssh_print_data("key client (e)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3131 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3132 | ssh_print_data("key server (f)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3133 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3134 | }
3135 | if(kex_type==SSH_KEX_DH_GROUP10x00030001 || kex_type==SSH_KEX_DH_GROUP140x00030014 || kex_type==SSH_KEX_DH_GROUP160x00030016 || kex_type==SSH_KEX_DH_GROUP180x00030018){
3136 | ssh_print_data("key client (e)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3137 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3138 | ssh_print_data("key server (f)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3139 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3140 | }
3141 | if(kex_type==SSH_KEX_CURVE255190x00010000){
3142 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3143 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e));
3144 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3145 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f));
3146 | }
3147 | if (kex_type==SSH_KEX_SNTRUP761X255190x00040000){ // Add support of sntrup761x25519
3148 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq));
3149 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq));
3150 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq));
3151 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq));
3152 | ws_noisy("Switch to SSH_KEX_SNTRUP761X25519")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 3152, __func__, "Switch to SSH_KEX_SNTRUP761X25519"); } } while (0);
3153 | }
3154 | if (kex_type==SSH_KEX_MLKEM768X255190x00050000){ // Add support of mlkem768x25519
3155 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq));
3156 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq));
3157 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq));
3158 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq));
3159 | ws_noisy("Switch to SSH_KEX_MLKEM768X25519")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 3159, __func__, "Switch to SSH_KEX_MLKEM768X25519"); } } while (0);
3160 | }
3161 | ssh_print_data("shared secret", (const unsigned char *)wmem_array_get_raw(global_data->kex_shared_secret), wmem_array_get_count(global_data->kex_shared_secret));
3162 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_shared_secret), wmem_array_get_count(global_data->kex_shared_secret));
3163 |
3164 | ssh_print_data("exchange", (const unsigned char *)wmem_array_get_raw(kex_hash_buffer), wmem_array_get_count(kex_hash_buffer));
3165 |
3166 | unsigned hash_len = 32;
3167 | if(kex_hash_type==SSH_KEX_HASH_SHA11) {
3168 | gcry_md_open(&hd, GCRY_MD_SHA1, 0);
3169 | hash_len = 20;
3170 | } else if(kex_hash_type==SSH_KEX_HASH_SHA2562) {
3171 | gcry_md_open(&hd, GCRY_MD_SHA256, 0);
3172 | hash_len = 32;
3173 | } else if(kex_hash_type==SSH_KEX_HASH_SHA5124) {
3174 | gcry_md_open(&hd, GCRY_MD_SHA512, 0);
3175 | hash_len = 64;
3176 | } else {
3177 | ws_debug("kex_hash_type type %d not supported", kex_hash_type)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3177, __func__, "kex_hash_type type %d not supported", kex_hash_type ); } } while (0);
3178 | return;
3179 | }
3180 | uint8_t *exchange_hash = (uint8_t *)wmem_alloc0(wmem_file_scope(), hash_len);
3181 | gcry_md_write(hd, wmem_array_get_raw(kex_hash_buffer), wmem_array_get_count(kex_hash_buffer));
3182 | memcpy(exchange_hash, gcry_md_read(hd, 0), hash_len);
3183 | gcry_md_close(hd);
3184 | ssh_print_data("hash", exchange_hash, hash_len);
3185 | global_data->secret = secret;
3186 | ssh_derive_symmetric_keys(secret, exchange_hash, hash_len, global_data);
3187 | }
3188 |
3189 | // the purpose of this function is to deal with all different kex methods
3190 | static ssh_bignum *
3191 | ssh_kex_shared_secret(int kex_type, ssh_bignum *pub, ssh_bignum *priv, ssh_bignum *modulo)
3192 | {
3193 | DISSECTOR_ASSERT(pub != NULL)((void) ((pub != ((void*)0)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3193, "pub != ((void*)0)"))));
3194 | DISSECTOR_ASSERT(priv != NULL)((void) ((priv != ((void*)0)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3194, "priv != ((void*)0)"))));
3195 |
3196 | ssh_bignum *secret = ssh_kex_make_bignum(NULL((void*)0), pub->length);
3197 | if (!secret) {
3198 | ws_debug("invalid key length %u", pub->length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3198, __func__, "invalid key length %u", pub->length); } } while (0);
3199 | return NULL((void*)0);
3200 | }
3201 |
3202 | if(kex_type==SSH_KEX_DH_GEX0x00020000){
3203 | if (modulo == NULL((void*)0)) {
3204 | ws_debug("Missing group modulo")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3204, __func__, "Missing group modulo"); } } while (0);
3205 | return NULL((void*)0);
3206 | }
3207 | gcry_mpi_t b = NULL((void*)0);
3208 | gcry_mpi_scan(&b, GCRYMPI_FMT_USG, pub->data, pub->length, NULL((void*)0));
3209 | gcry_mpi_t d = NULL((void*)0), e = NULL((void*)0), m = NULL((void*)0);
3210 | size_t result_len = 0;
3211 | d = gcry_mpi_new(pub->length*8);
3212 | gcry_mpi_scan(&e, GCRYMPI_FMT_USG, priv->data, priv->length, NULL((void*)0));
3213 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, modulo->data, modulo->length, NULL((void*)0));
3214 | gcry_mpi_powm(d, b, e, m); // gcry_mpi_powm(d, b, e, m) => d = b^e % m
3215 | gcry_mpi_print(GCRYMPI_FMT_USG, secret->data, secret->length, &result_len, d);
3216 | secret->length = (unsigned)result_len; // Should not be larger than what fits in a 32-bit unsigned integer...
3217 | gcry_mpi_release(d);
3218 | gcry_mpi_release(b);
3219 | gcry_mpi_release(e);
3220 | gcry_mpi_release(m);
3221 |
3222 | }else if(kex_type==SSH_KEX_DH_GROUP10x00030001 || kex_type==SSH_KEX_DH_GROUP140x00030014 || kex_type==SSH_KEX_DH_GROUP160x00030016 || kex_type==SSH_KEX_DH_GROUP180x00030018){
3223 | gcry_mpi_t m = NULL((void*)0);
3224 | if(kex_type==SSH_KEX_DH_GROUP10x00030001){
3225 | static const uint8_t p[] = {
3226 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
3227 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
3228 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
3229 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
3230 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
3231 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
3232 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
3233 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,};
3234 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0));
3235 | }else if(kex_type==SSH_KEX_DH_GROUP140x00030014){
3236 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
3237 | static const uint8_t p[] = {
3238 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
3239 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
3240 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
3241 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
3242 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
3243 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
3244 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
3245 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
3246 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
3247 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
3248 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
3249 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
3250 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
3251 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
3252 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
3253 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
3254 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0));
3255 | }else if(kex_type==SSH_KEX_DH_GROUP160x00030016){
3256 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF
3257 | static const uint8_t p[] = {
3258 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
3259 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
3260 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
3261 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
3262 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
3263 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
3264 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
3265 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
3266 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
3267 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
3268 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
3269 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
3270 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
3271 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
3272 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
3273 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
3274 | 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
3275 | 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
3276 | 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
3277 | 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
3278 | 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
3279 | 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
3280 | 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
3281 | 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
3282 | 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
3283 | 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
3284 | 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
3285 | 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
3286 | 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
3287 | 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
3288 | 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
3289 | 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,};
3290 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0));
3291 | }else if(kex_type==SSH_KEX_DH_GROUP180x00030018){
3292 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF
3293 | static const uint8_t p[] = {
3294 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
3295 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
3296 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
3297 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
3298 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
3299 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
3300 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
3301 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
3302 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
3303 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
3304 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
3305 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
3306 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
3307 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
3308 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
3309 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
3310 | 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
3311 | 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
3312 | 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
3313 | 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
3314 | 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
3315 | 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
3316 | 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
3317 | 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
3318 | 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
3319 | 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
3320 | 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
3321 | 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
3322 | 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
3323 | 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
3324 | 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
3325 | 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
3326 | 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
3327 | 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
3328 | 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
3329 | 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
3330 | 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
3331 | 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
3332 | 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
3333 | 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
3334 | 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
3335 | 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
3336 | 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
3337 | 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
3338 | 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
3339 | 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
3340 | 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
3341 | 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
3342 | 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
3343 | 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
3344 | 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
3345 | 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
3346 | 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
3347 | 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
3348 | 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
3349 | 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
3350 | 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
3351 | 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
3352 | 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
3353 | 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
3354 | 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
3355 | 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
3356 | 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
3357 | 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,};
3358 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0));
3359 | }
3360 |
3361 | gcry_mpi_t b = NULL((void*)0);
3362 | gcry_mpi_scan(&b, GCRYMPI_FMT_USG, pub->data, pub->length, NULL((void*)0));
3363 | gcry_mpi_t d = NULL((void*)0), e = NULL((void*)0);
3364 | size_t result_len = 0;
3365 | d = gcry_mpi_new(pub->length*8);
3366 | gcry_mpi_scan(&e, GCRYMPI_FMT_USG, priv->data, priv->length, NULL((void*)0));
3367 | gcry_mpi_powm(d, b, e, m); // gcry_mpi_powm(d, b, e, m) => d = b^e % m
3368 | gcry_mpi_print(GCRYMPI_FMT_USG, secret->data, secret->length, &result_len, d);
3369 | secret->length = (unsigned)result_len; // Should not be larger than what fits in a 32-bit unsigned integer...
3370 | gcry_mpi_release(d);
3371 | gcry_mpi_release(b);
3372 | gcry_mpi_release(e);
3373 | gcry_mpi_release(m);
3374 | }else if(kex_type==SSH_KEX_CURVE255190x00010000){
3375 | if (crypto_scalarmult_curve25519(secret->data, priv->data, pub->data)) {
3376 | ws_debug("curve25519: can't compute shared secret")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3376, __func__, "curve25519: can't compute shared secret"); } } while (0);
3377 | return NULL((void*)0);
3378 | }
3379 | } else {
3380 | ws_debug("kex_type type %d not supported", kex_type)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3380, __func__, "kex_type type %d not supported", kex_type) ; } } while (0);
3381 | return 0;
3382 | }
3383 |
3384 | return secret;
3385 | }
3386 |
3387 | static char *
3388 | ssh_string(wmem_allocator_t* allocator, const uint8_t *string, unsigned length)
3389 | {
3390 | char *ssh_string = (char *)wmem_alloc(allocator, length + 4);
3391 | ssh_string[0] = (length >> 24) & 0xff;
3392 | ssh_string[1] = (length >> 16) & 0xff;
3393 | ssh_string[2] = (length >> 8) & 0xff;
3394 | ssh_string[3] = length & 0xff;
3395 | memcpy(ssh_string + 4, string, length);
3396 | return ssh_string;
3397 | }
3398 |
3399 | static void
3400 | ssh_hash_buffer_put_string(wmem_array_t *buffer, const uint8_t *string,
3401 | unsigned length)
3402 | {
3403 | if (!buffer) {
3404 | return;
3405 | }
3406 |
3407 | char *string_with_length = ssh_string(wmem_array_get_allocator(buffer), string, length);
3408 | wmem_array_append(buffer, string_with_length, length + 4);
3409 | }
3410 |
3411 | static void
3412 | ssh_hash_buffer_put_uint32(wmem_array_t *buffer, unsigned val)
3413 | {
3414 | if (!buffer) {
3415 | return;
3416 | }
3417 |
3418 | char buf[4];
3419 | buf[0] = (val >> 24); buf[1] = (val >> 16); buf[2] = (val >> 8); buf[3] = (val >> 0);
3420 | wmem_array_append(buffer, buf, 4);
3421 | }
3422 |
3423 | static void ssh_derive_symmetric_keys(ssh_bignum *secret, uint8_t *exchange_hash,
3424 | unsigned hash_length, struct ssh_flow_data *global_data)
3425 | {
3426 | if (!global_data->session_id) {
3427 | global_data->session_id = exchange_hash;
3428 | global_data->session_id_length = hash_length;
3429 | }
3430 |
3431 | unsigned int we_need = 0;
3432 | for(int peer_cnt=0;peer_cnt<2;peer_cnt++){
3433 | struct ssh_peer_data * peer_data = &global_data->peer_data[peer_cnt];
3434 | // required size of key depends on cipher used. chacha20 wants 64 bytes
3435 | unsigned need = 0;
3436 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) {
3437 | need = 64;
3438 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id || CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id) {
3439 | need = 16;
3440 | } else if (CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id) {
3441 | need = 24;
3442 | } else if (CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) {
3443 | need = 32;
3444 | } else {
3445 | ssh_debug_printf("ssh: cipher (%d) is unknown or not set\n", peer_data->cipher_id);
3446 | ssh_debug_flush();
3447 | }
3448 | if(peer_data->mac_id == CIPHER_MAC_SHA2_2560x00020001){
3449 | need = 32;
3450 | }else{
3451 | ssh_debug_printf("ssh: MAC (%d) is unknown or not set\n", peer_data->mac_id);
3452 | ssh_debug_flush();
3453 | }
3454 | if (we_need<need) {
3455 | we_need = need;
3456 | }
3457 | }
3458 |
3459 | for (int i = 0; i < 6; i ++) {
3460 | ssh_derive_symmetric_key(secret, exchange_hash, hash_length,
3461 | 'A' + i, &global_data->new_keys[i], global_data, we_need);
3462 | if(i==0){ ssh_print_data("Initial IV client to server", global_data->new_keys[i].data, global_data->new_keys[i].length);
3463 | }else if(i==1){ ssh_print_data("Initial IV server to client", global_data->new_keys[i].data, global_data->new_keys[i].length);
3464 | }else if(i==2){ ssh_print_data("Encryption key client to server", global_data->new_keys[i].data, global_data->new_keys[i].length);
3465 | }else if(i==3){ ssh_print_data("Encryption key server to client", global_data->new_keys[i].data, global_data->new_keys[i].length);
3466 | }else if(i==4){ ssh_print_data("Integrity key client to server", global_data->new_keys[i].data, global_data->new_keys[i].length);
3467 | }else if(i==5){ ssh_print_data("Integrity key server to client", global_data->new_keys[i].data, global_data->new_keys[i].length);
3468 | }
3469 | }
3470 | }
3471 |
3472 | static void ssh_derive_symmetric_key(ssh_bignum *secret, const uint8_t *exchange_hash,
3473 | unsigned hash_length, char id, ssh_bignum *result_key,
3474 | struct ssh_flow_data *global_data, unsigned we_need)
3475 | {
3476 | gcry_md_hd_t hd;
3477 |
3478 | unsigned kex_hash_type = ssh_kex_hash_type(global_data->kex);
3479 | int algo = GCRY_MD_SHA256;
3480 | if(kex_hash_type==SSH_KEX_HASH_SHA11){
3481 | algo = GCRY_MD_SHA1;
3482 | }else if(kex_hash_type==SSH_KEX_HASH_SHA2562){
3483 | algo = GCRY_MD_SHA256;
3484 | }else if(kex_hash_type==SSH_KEX_HASH_SHA5124){
3485 | algo = GCRY_MD_SHA512;
3486 | }
3487 | unsigned len = gcry_md_get_algo_dlen(algo);
3488 |
3489 | result_key->data = (unsigned char *)wmem_alloc(wmem_file_scope(), we_need);
3490 |
3491 | char *secret_with_length = ssh_string(NULL((void*)0), secret->data, secret->length);
3492 |
3493 | if (gcry_md_open(&hd, algo, 0) == 0) {
3494 | gcry_md_write(hd, secret_with_length, secret->length + 4);
3495 | gcry_md_write(hd, exchange_hash, hash_length);
3496 | gcry_md_putc(hd, id)do { gcry_md_hd_t h__ = (hd); if( (h__)->bufpos == (h__)-> bufsize ) gcry_md_write( (h__), ((void*)0), 0 ); (h__)->buf [(h__)->bufpos++] = (id) & 0xff; } while(0);
3497 | gcry_md_write(hd, global_data->session_id, hash_length);
3498 | unsigned add_length = MIN(len, we_need)(((len) < (we_need)) ? (len) : (we_need));
3499 | memcpy(result_key->data, gcry_md_read(hd, 0), add_length);
3500 | gcry_md_close(hd);
3501 | }
3502 |
3503 | // expand key
3504 | for (unsigned have = len; have < we_need; have += len) {
3505 | if (gcry_md_open(&hd, algo, 0) == 0) {
3506 | gcry_md_write(hd, secret_with_length, secret->length + 4);
3507 | gcry_md_write(hd, exchange_hash, hash_length);
3508 | gcry_md_write(hd, result_key->data+have-len, len);
3509 | unsigned add_length = MIN(len, we_need - have)(((len) < (we_need - have)) ? (len) : (we_need - have));
3510 | memcpy(result_key->data+have, gcry_md_read(hd, 0), add_length);
3511 | gcry_md_close(hd);
3512 | }
3513 | }
3514 | wmem_free(NULL((void*)0), secret_with_length);
3515 |
3516 | result_key->length = we_need;
3517 | }
3518 |
3519 | static void
3520 | ssh_choose_enc_mac(struct ssh_flow_data *global_data)
3521 | {
3522 | for(int peer_cnt=0;peer_cnt<2;peer_cnt++){
3523 | struct ssh_peer_data * peer_data = &global_data->peer_data[peer_cnt];
3524 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].enc_proposals[peer_cnt],
3525 | global_data->peer_data[SERVER_PEER_DATA1].enc_proposals[peer_cnt],
3526 | &peer_data->enc);
3527 | /* some ciphers have their own MAC so the "negotiated" one is meaningless */
3528 | if(peer_data->enc && (0 == strcmp(peer_data->enc, "aes128-gcm@openssh.com") ||
3529 | 0 == strcmp(peer_data->enc, "aes256-gcm@openssh.com"))) {
3530 | peer_data->mac = wmem_strdup(wmem_file_scope(), (const char *)"<implicit>");
3531 | peer_data->mac_length = 16;
3532 | peer_data->length_is_plaintext = 1;
3533 | }
3534 | else if(peer_data->enc && 0 == strcmp(peer_data->enc, "chacha20-poly1305@openssh.com")) {
3535 | peer_data->mac = wmem_strdup(wmem_file_scope(), (const char *)"<implicit>");
3536 | peer_data->mac_length = 16;
3537 | }
3538 | else {
3539 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].mac_proposals[peer_cnt],
3540 | global_data->peer_data[SERVER_PEER_DATA1].mac_proposals[peer_cnt],
3541 | &peer_data->mac);
3542 | ssh_set_mac_length(peer_data);
3543 | }
3544 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].comp_proposals[peer_cnt],
3545 | global_data->peer_data[SERVER_PEER_DATA1].comp_proposals[peer_cnt],
3546 | &peer_data->comp);
3547 | }
3548 |
3549 | ssh_decryption_set_cipher_id(&global_data->peer_data[CLIENT_PEER_DATA0]);
3550 | ssh_decryption_set_mac_id(&global_data->peer_data[CLIENT_PEER_DATA0]);
3551 | ssh_decryption_set_cipher_id(&global_data->peer_data[SERVER_PEER_DATA1]);
3552 | ssh_decryption_set_mac_id(&global_data->peer_data[SERVER_PEER_DATA1]);
3553 | }
3554 |
3555 | static void
3556 | ssh_decryption_set_cipher_id(struct ssh_peer_data *peer)
3557 | {
3558 | char *cipher_name = peer->enc;
3559 |
3560 | if (!cipher_name) {
3561 | peer->cipher = NULL((void*)0);
3562 | ws_debug("ERROR: cipher_name is NULL")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3562, __func__, "ERROR: cipher_name is NULL"); } } while (0 );
3563 | } else if (0 == strcmp(cipher_name, "chacha20-poly1305@openssh.com")) { // add chacha20-poly1305@openssh.com
3564 | peer->cipher_id = GCRY_CIPHER_CHACHA20;
3565 | } else if (0 == strcmp(cipher_name, "chacha20-poly1305")) { // add chacha20-poly1305
3566 | peer->cipher_id = GCRY_CIPHER_CHACHA20;
3567 | } else if (0 == strcmp(cipher_name, "aes128-gcm@openssh.com")) {
3568 | peer->cipher_id = CIPHER_AES128_GCM0x00040001;
3569 | } else if (0 == strcmp(cipher_name, "aes128-gcm")) {
3570 | peer->cipher_id = CIPHER_AES128_GCM0x00040001;
3571 | } else if (0 == strcmp(cipher_name, "aes256-gcm@openssh.com")) {
3572 | peer->cipher_id = CIPHER_AES256_GCM0x00040004;
3573 | } else if (0 == strcmp(cipher_name, "aes256-gcm")) {
3574 | peer->cipher_id = CIPHER_AES256_GCM0x00040004;
3575 | } else if (0 == strcmp(cipher_name, "aes128-cbc")) {
3576 | peer->cipher_id = CIPHER_AES128_CBC0x00020001;
3577 | } else if (0 == strcmp(cipher_name, "aes192-cbc")) {
3578 | peer->cipher_id = CIPHER_AES192_CBC0x00020002;
3579 | } else if (0 == strcmp(cipher_name, "aes256-cbc")) {
3580 | peer->cipher_id = CIPHER_AES256_CBC0x00020004;
3581 | } else if (0 == strcmp(cipher_name, "aes128-ctr")) {
3582 | peer->cipher_id = CIPHER_AES128_CTR0x00010001;
3583 | } else if (0 == strcmp(cipher_name, "aes192-ctr")) {
3584 | peer->cipher_id = CIPHER_AES192_CTR0x00010003;
3585 | } else if (0 == strcmp(cipher_name, "aes256-ctr")) {
3586 | peer->cipher_id = CIPHER_AES256_CTR0x00010004;
3587 | } else if (0 == strcmp(cipher_name, "none")) {
3588 | peer->cipher_id = CIPHER_NULL0x00080000;
3589 | peer->length_is_plaintext = 1;
3590 | } else {
3591 | peer->cipher = NULL((void*)0);
3592 | ws_debug("decryption not supported: %s", cipher_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3592, __func__, "decryption not supported: %s", cipher_name ); } } while (0);
3593 | }
3594 | }
3595 |
3596 | static void
3597 | ssh_decryption_set_mac_id(struct ssh_peer_data *peer)
3598 | {
3599 | char *mac_name = peer->mac;
3600 |
3601 | if (!mac_name) {
3602 | peer->mac = NULL((void*)0);
3603 | ws_debug("ERROR: mac_name is NULL")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3603, __func__, "ERROR: mac_name is NULL"); } } while (0);
3604 | } else if (0 == strcmp(mac_name, "hmac-sha2-256")) {
3605 | peer->mac_id = CIPHER_MAC_SHA2_2560x00020001;
3606 | } else {
3607 | ws_debug("decryption MAC not supported: %s", mac_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3607, __func__, "decryption MAC not supported: %s", mac_name ); } } while (0);
3608 | }
3609 | }
3610 |
3611 | static bool_Bool
3612 | gcry_cipher_destroy_cb(wmem_allocator_t *allocator _U___attribute__((unused)), wmem_cb_event_t event _U___attribute__((unused)), void *user_data)
3613 | {
3614 | gcry_cipher_hd_t hd = (gcry_cipher_hd_t)user_data;
3615 |
3616 | gcry_cipher_close(hd);
3617 |
3618 | return false0;
3619 | }
3620 |
3621 | static void
3622 | ssh_decryption_setup_cipher(struct ssh_peer_data *peer_data,
3623 | ssh_bignum *iv, ssh_bignum *key)
3624 | {
3625 | gcry_error_t err;
3626 | gcry_cipher_hd_t *hd1, *hd2;
3627 |
3628 | hd1 = &peer_data->cipher;
3629 | hd2 = &peer_data->cipher_2;
3630 |
3631 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) {
3632 | if (gcry_cipher_open(hd1, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_STREAM, 0) ||
3633 | gcry_cipher_open(hd2, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_STREAM, 0)) {
3634 | gcry_cipher_close(*hd1);
3635 | gcry_cipher_close(*hd2);
3636 | ws_debug("ssh: can't open chacha20 cipher handles")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3636, __func__, "ssh: can't open chacha20 cipher handles"); } } while (0);
3637 | return;
3638 | }
3639 |
3640 | uint8_t k1[32];
3641 | uint8_t k2[32];
3642 | if(key->data){
3643 | memcpy(k1, key->data, 32);
3644 | memcpy(k2, key->data + 32, 32);
3645 | }else{
3646 | memset(k1, 0, 32);
3647 | memset(k2, 0, 32);
3648 | }
3649 |
3650 | ssh_debug_printf("ssh: cipher is chacha20\n");
3651 | ssh_print_data("key 1", k1, 32);
3652 | ssh_print_data("key 2", k2, 32);
3653 |
3654 | if ((err = gcry_cipher_setkey(*hd1, k1, 32))) {
3655 | gcry_cipher_close(*hd1);
3656 | ws_debug("ssh: can't set chacha20 cipher key %s", gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3656, __func__, "ssh: can't set chacha20 cipher key %s", gcry_strerror (err)); } } while (0);
3657 | return;
3658 | }
3659 |
3660 | if ((err = gcry_cipher_setkey(*hd2, k2, 32))) {
3661 | gcry_cipher_close(*hd1);
3662 | gcry_cipher_close(*hd2);
3663 | ws_debug("ssh: can't set chacha20 cipher key %s", gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3663, __func__, "ssh: can't set chacha20 cipher key %s", gcry_strerror (err)); } } while (0);
3664 | return;
3665 | }
3666 |
3667 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1);
3668 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd2);
3669 |
3670 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id) {
3671 | int iKeyLen = CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id?16:CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id?24:32;
3672 | if (gcry_cipher_open(hd1, CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id?GCRY_CIPHER_AES128GCRY_CIPHER_AES:CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id?GCRY_CIPHER_AES192:GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 0)) {
3673 | gcry_cipher_close(*hd1);
3674 | ws_debug("ssh: can't open aes%d cipher handle", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3674, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0);
3675 | return;
3676 | }
3677 | uint8_t k1[32], iv1[16];
3678 | if(key->data){
3679 | memcpy(k1, key->data, iKeyLen);
3680 | }else{
3681 | memset(k1, 0, iKeyLen);
3682 | }
3683 | if(iv->data){
3684 | memcpy(iv1, iv->data, 16);
3685 | }else{
3686 | memset(iv1, 0, 16);
3687 | }
3688 |
3689 | ssh_debug_printf("ssh: cipher is aes%d-cbc\n", iKeyLen*8);
3690 | ssh_print_data("key", k1, iKeyLen);
3691 | ssh_print_data("iv", iv1, 16);
3692 |
3693 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) {
3694 | gcry_cipher_close(*hd1);
3695 | ws_debug("ssh: can't set aes%d cipher key", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3695, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0);
3696 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3696, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
3697 | return;
3698 | }
3699 |
3700 | if ((err = gcry_cipher_setiv(*hd1, iv1, 16))) {
3701 | gcry_cipher_close(*hd1);
3702 | ws_debug("ssh: can't set aes%d cipher iv", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3702, __func__, "ssh: can't set aes%d cipher iv", iKeyLen*8 ); } } while (0);
3703 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3703, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
3704 | return;
3705 | }
3706 |
3707 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1);
3708 |
3709 | } else if (CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id) {
3710 | int iKeyLen = CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id?16:CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id?24:32;
3711 | if (gcry_cipher_open(hd1, CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id?GCRY_CIPHER_AES128GCRY_CIPHER_AES:CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id?GCRY_CIPHER_AES192:GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR, 0)) {
3712 | gcry_cipher_close(*hd1);
3713 | ws_debug("ssh: can't open aes%d cipher handle", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3713, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0);
3714 | return;
3715 | }
3716 | uint8_t k1[32], iv1[16];
3717 | if(key->data){
3718 | memcpy(k1, key->data, iKeyLen);
3719 | }else{
3720 | memset(k1, 0, iKeyLen);
3721 | }
3722 | if(iv->data){
3723 | memcpy(iv1, iv->data, 16);
3724 | }else{
3725 | memset(iv1, 0, 16);
3726 | }
3727 |
3728 | ssh_debug_printf("ssh: cipher is aes%d-ctr\n", iKeyLen*8);
3729 | ssh_print_data("key", k1, iKeyLen);
3730 | ssh_print_data("iv", iv1, 16);
3731 |
3732 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) {
3733 | gcry_cipher_close(*hd1);
3734 | ws_debug("ssh: can't set aes%d cipher key", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3734, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0);
3735 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3735, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
3736 | return;
3737 | }
3738 |
3739 | if ((err = gcry_cipher_setctr(*hd1, iv1, 16))) {
3740 | gcry_cipher_close(*hd1);
3741 | ws_debug("ssh: can't set aes%d cipher iv", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3741, __func__, "ssh: can't set aes%d cipher iv", iKeyLen*8 ); } } while (0);
3742 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3742, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
3743 | return;
3744 | }
3745 |
3746 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1);
3747 |
3748 | } else if (CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) {
3749 | int iKeyLen = CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id?16:32;
3750 | if (gcry_cipher_open(hd1, CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id?GCRY_CIPHER_AES128GCRY_CIPHER_AES:GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_GCM, 0)) {
3751 | gcry_cipher_close(*hd1);
3752 | ws_debug("ssh: can't open aes%d cipher handle", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3752, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0);
3753 | return;
3754 | }
3755 |
3756 | uint8_t k1[32], iv2[12];
3757 | if(key->data){
3758 | memcpy(k1, key->data, iKeyLen);
3759 | }else{
3760 | memset(k1, 0, iKeyLen);
3761 | }
3762 | if(iv->data){
3763 | memcpy(peer_data->iv, iv->data, 12);
3764 | }else{
3765 | memset(iv2, 0, 12);
3766 | }
3767 |
3768 | ssh_debug_printf("ssh: cipher is aes%d-gcm\n", iKeyLen*8);
3769 | ssh_print_data("key", k1, iKeyLen);
3770 | ssh_print_data("iv", peer_data->iv, 12);
3771 |
3772 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) {
3773 | gcry_cipher_close(*hd1);
3774 | ws_debug("ssh: can't set aes%d cipher key", iKeyLen*8)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3774, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0);
3775 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3775, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
3776 | return;
3777 | }
3778 |
3779 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1);
3780 |
3781 | } else {
3782 | ssh_debug_printf("ssh: cipher (%d) is unknown or not set\n", peer_data->cipher_id);
3783 | }
3784 | }
3785 |
3786 | static void
3787 | ssh_decryption_setup_mac(struct ssh_peer_data *peer_data,
3788 | ssh_bignum *iv)
3789 | {
3790 | if(peer_data->mac_id == CIPHER_MAC_SHA2_2560x00020001){
3791 | if(iv->data){
3792 | memcpy(peer_data->hmac_iv, iv->data, 32);
3793 | }else{
3794 | memset(peer_data->hmac_iv, 0, 32);
3795 | }
3796 | peer_data->hmac_iv_len = 32;
3797 | ssh_debug_printf("ssh: mac is hmac-sha2-256\n");
3798 | ssh_print_data("iv", peer_data->hmac_iv, peer_data->hmac_iv_len);
3799 | }else{
3800 | ws_debug("ssh: unsupported MAC")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3800, __func__, "ssh: unsupported MAC"); } } while (0);
3801 | }
3802 | }
3803 |
3804 | /* libgcrypt wrappers for HMAC/message digest operations {{{ */
3805 | /* hmac abstraction layer */
3806 | #define SSH_HMACgcry_md_hd_t gcry_md_hd_t
3807 |
3808 | static inline int
3809 | ssh_hmac_init(SSH_HMACgcry_md_hd_t* md, const void * key, int len, int algo)
3810 | {
3811 | gcry_error_t err;
3812 | const char *err_str, *err_src;
3813 |
3814 | err = gcry_md_open(md,algo, GCRY_MD_FLAG_HMAC);
3815 | if (err != 0) {
3816 | err_str = gcry_strerror(err);
3817 | err_src = gcry_strsource(err);
3818 | ssh_debug_printf("ssh_hmac_init(): gcry_md_open failed %s/%s", err_str, err_src);
3819 | return -1;
3820 | }
3821 | err = gcry_md_setkey(*(md), key, len);
3822 | if (err != 0) {
3823 | err_str = gcry_strerror(err);
3824 | err_src = gcry_strsource(err);
3825 | ssh_debug_printf("ssh_hmac_init(): gcry_md_setkey(..., ..., %d) failed %s/%s", len, err_str, err_src);
3826 | return -1;
3827 | }
3828 | return 0;
3829 | }
3830 |
3831 | static inline void
3832 | ssh_hmac_update(SSH_HMACgcry_md_hd_t* md, const void* data, int len)
3833 | {
3834 | gcry_md_write(*(md), data, len);
3835 | }
3836 |
3837 | static inline void
3838 | ssh_hmac_final(SSH_HMACgcry_md_hd_t* md, unsigned char* data, unsigned* datalen)
3839 | {
3840 | int algo;
3841 | unsigned len;
3842 |
3843 | algo = gcry_md_get_algo (*(md));
3844 | len = gcry_md_get_algo_dlen(algo);
3845 | DISSECTOR_ASSERT(len <= *datalen)((void) ((len <= *datalen) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3845, "len <= *datalen"))));
3846 | memcpy(data, gcry_md_read(*(md), algo), len);
3847 | *datalen = len;
3848 | }
3849 |
3850 | static inline void
3851 | ssh_hmac_cleanup(SSH_HMACgcry_md_hd_t* md)
3852 | {
3853 | gcry_md_close(*(md));
3854 | }
3855 | /* libgcrypt wrappers for HMAC/message digest operations }}} */
3856 |
3857 | /* Decryption integrity check {{{ */
3858 |
3859 | static int
3860 | ssh_get_digest_by_id(unsigned mac_id)
3861 | {
3862 | if(mac_id==CIPHER_MAC_SHA2_2560x00020001){
3863 | return GCRY_MD_SHA256;
3864 | }
3865 | return -1;
3866 | }
3867 |
3868 | static void
3869 | ssh_calc_mac(struct ssh_peer_data *peer_data, uint32_t seqnr, uint8_t* data, uint32_t datalen, uint8_t* calc_mac)
3870 | {
3871 | SSH_HMACgcry_md_hd_t hm;
3872 | int md;
3873 | uint32_t len;
3874 | uint8_t buf[DIGEST_MAX_SIZE48];
3875 |
3876 | md=ssh_get_digest_by_id(peer_data->mac_id);
3877 | // ssl_debug_printf("ssh_check_mac mac type:%s md %d\n",
3878 | // ssl_cipher_suite_dig(decoder->cipher_suite)->name, md);
3879 |
3880 | memset(calc_mac, 0, DIGEST_MAX_SIZE48);
3881 |
3882 | if (md == -1) {
3883 | return;
3884 | }
3885 | if (ssh_hmac_init(&hm, peer_data->hmac_iv, peer_data->hmac_iv_len, md) != 0)
3886 | return;
3887 |
3888 | /* hash sequence number */
3889 | phtonu32(buf, seqnr);
3890 |
3891 | ssh_print_data("Mac IV", peer_data->hmac_iv, peer_data->hmac_iv_len);
3892 | ssh_print_data("Mac seq", buf, 4);
3893 | ssh_print_data("Mac data", data, datalen);
3894 |
3895 | ssh_hmac_update(&hm,buf,4);
3896 |
3897 | ssh_hmac_update(&hm,data,datalen);
3898 |
3899 | /* get digest and digest len*/
3900 | len = sizeof(buf);
3901 | ssh_hmac_final(&hm,buf,&len);
3902 | ssh_hmac_cleanup(&hm);
3903 | ssh_print_data("Mac", buf, len);
3904 | memcpy(calc_mac, buf, len);
3905 |
3906 | return;
3907 | }
3908 | /* Decryption integrity check }}} */
3909 |
3910 | static ssh_packet_info_t *
3911 | ssh_get_packet_info(packet_info *pinfo, bool_Bool is_response)
3912 | {
3913 | ssh_packet_info_t *packet = (ssh_packet_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ssh, 0);
3914 | if(!packet){
3915 | packet = wmem_new0(wmem_file_scope(), ssh_packet_info_t)((ssh_packet_info_t*)wmem_alloc0((wmem_file_scope()), sizeof( ssh_packet_info_t)));
3916 | packet->from_server = is_response;
3917 | packet->messages = NULL((void*)0);
3918 | p_add_proto_data(wmem_file_scope(), pinfo, proto_ssh, 0, packet);
3919 | }
3920 | return packet;
3921 | }
3922 |
3923 | static unsigned
3924 | ssh_decrypt_packet(tvbuff_t *tvb, packet_info *pinfo,
3925 | struct ssh_peer_data *peer_data, int offset)
3926 | {
3927 | bool_Bool is_response = ssh_peer_data_from_server(peer_data);
3928 |
3929 | gcry_error_t err;
3930 | unsigned message_length = 0, seqnr;
3931 | uint8_t *plain = NULL((void*)0);
3932 | const uint8_t *mac;
3933 | unsigned mac_len, data_len = 0;
3934 | uint8_t calc_mac[DIGEST_MAX_SIZE48];
3935 | memset(calc_mac, 0, DIGEST_MAX_SIZE48);
3936 | unsigned remaining = tvb_captured_length_remaining(tvb, offset);
3937 |
3938 | mac_len = peer_data->mac_length > 0 ? peer_data->mac_length : 0;
3939 | seqnr = peer_data->sequence_number;
3940 |
3941 | /* General algorithm:
3942 | * 1. If there are not enough bytes for the packet_length, and we can
3943 | * do reassembly, ask for one more segment.
3944 | * 2. Retrieve packet_length (encrypted in some modes).
3945 | * 3. Sanity check packet_length (the field is 4 bytes, but packet_length
3946 | * is unlikely to be much larger than 32768, which provides good indication
3947 | * a packet is continuation data or, in some modes, failed decryption.
3948 | * https://www.rfc-editor.org/rfc/rfc4253.html#section-6.1 )
3949 | * 4. If there are not enough bytes for packet_length, and we can do
3950 | * reassembly, tell the TCP dissector how many more bytes we need.
3951 | * 5. If the packet is truncated and we cannot reassemble, at this
3952 | * point we conclude that it is the next SSH packet, and advance the
3953 | * sequence number, invocation_counter, etc. before throwing an exception.
3954 | * 6. If we do have all the data, we decrypt and check the MAC before
3955 | * doing all that. (XXX - Advancing seqnr regardless could make sense
3956 | * in some ciphers.)
3957 | * 7. Possibly the MAC should be checked before decryption in some ciphers
3958 | * if we have all the data; possibly there should be a "do not check the
3959 | * MAC" preference a la TLS.
3960 | */
3961 |
3962 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) {
3963 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) {
3964 | /* Can do reassembly, and the packet length is split across
3965 | * segment boundaries. */
3966 | pinfo->desegment_offset = offset;
3967 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
3968 | return tvb_captured_length(tvb);
3969 | }
3970 |
3971 | const uint8_t *ctext = tvb_get_ptr(tvb, offset, 4);
3972 | uint8_t plain_length_buf[4];
3973 |
3974 | if (!ssh_decrypt_chacha20(peer_data->cipher_2, seqnr, 0, ctext, 4,
3975 | plain_length_buf, 4)) {
3976 | ws_debug("ERROR: could not decrypt packet len")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3976, __func__, "ERROR: could not decrypt packet len"); } } while (0);
3977 | return tvb_captured_length(tvb);
3978 | }
3979 |
3980 | message_length = pntohu32(plain_length_buf);
3981 |
3982 | ssh_debug_printf("chachapoly_crypt seqnr=%d [%u]\n", seqnr, message_length);
3983 |
3984 | ssh_debug_printf("%s plain for seq = %d len = %u\n", is_response?"s2c":"c2s", seqnr, message_length);
3985 | if (message_length > SSH_MAX_PACKET_LEN32768) {
3986 | ws_debug("ssh: unreasonable message length %u", message_length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3986, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0);
3987 | return tvb_captured_length(tvb);
3988 | }
3989 | if (remaining < message_length + 4 + mac_len) {
3990 | // Need desegmentation; as "the chacha20-poly1305@openssh.com AEAD
3991 | // uses the sequence number as an initialisation vector (IV) to
3992 | // generate its per-packet MAC key and is otherwise stateless
3993 | // between packets," we need no special handling here.
3994 | // https://datatracker.ietf.org/doc/draft-miller-sshm-strict-kex/
3995 | //
3996 | if (ssh_desegment && pinfo->can_desegment) {
3997 | pinfo->desegment_offset = offset;
3998 | pinfo->desegment_len = message_length + 4 + mac_len - remaining;
3999 | return tvb_captured_length(tvb);
4000 | }
4001 | // If we can't desegment, we will have an exception below in
4002 | // the tvb_get_ptr. Advance the sequence number so that the
4003 | // next SSH packet start will decrypt correctly.
4004 | peer_data->sequence_number++;
4005 | }
4006 |
4007 | plain = (uint8_t *)wmem_alloc0(pinfo->pool, message_length+4);
4008 | memcpy(plain, plain_length_buf, 4);
4009 | const uint8_t *ctext2 = tvb_get_ptr(tvb, offset+4, message_length);
4010 |
4011 | /* XXX - "Once the entire packet has been received, the MAC MUST be
4012 | * checked before decryption," but we decrypt first.
4013 | * https://datatracker.ietf.org/doc/html/draft-ietf-sshm-chacha20-poly1305-01
4014 | */
4015 | if (!ssh_decrypt_chacha20(peer_data->cipher, seqnr, 1, ctext2,
4016 | message_length, plain+4, message_length)) {
4017 | ws_debug("ERROR: could not decrypt packet payload")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4017, __func__, "ERROR: could not decrypt packet payload"); } } while (0);
4018 | return tvb_captured_length(tvb);
4019 | }
4020 |
4021 | mac = tvb_get_ptr(tvb, offset + 4 + message_length, mac_len);
4022 | uint8_t poly_key[32], iv[16];
4023 |
4024 | memset(poly_key, 0, 32);
4025 | memset(iv, 0, 8);
4026 | phtonu64(iv+8, (uint64_t)seqnr);
4027 | gcry_cipher_setiv(peer_data->cipher, iv, mac_len);
4028 | gcry_cipher_encrypt(peer_data->cipher, poly_key, 32, poly_key, 32);
4029 |
4030 | gcry_mac_hd_t mac_hd;
4031 | gcry_mac_open(&mac_hd, GCRY_MAC_POLY1305, 0, NULL((void*)0));
4032 | gcry_mac_setkey(mac_hd, poly_key, 32);
4033 | gcry_mac_write(mac_hd, ctext, 4);
4034 | gcry_mac_write(mac_hd, ctext2, message_length);
4035 | if (gcry_mac_verify(mac_hd, mac, mac_len)) {
4036 | ws_debug("ssh: MAC does not match")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4036, __func__, "ssh: MAC does not match"); } } while (0);
4037 | }
4038 | size_t buflen = DIGEST_MAX_SIZE48;
4039 | gcry_mac_read(mac_hd, calc_mac, &buflen);
4040 | gcry_mac_close(mac_hd);
4041 |
4042 | data_len = message_length + 4;
4043 |
4044 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr);
4045 | ssh_print_data("", plain, message_length+4);
4046 | } else if (CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) {
4047 |
4048 | /* AES GCM for Secure Shell [RFC 5647] */
4049 | /* The message length is Additional Authenticated Data */
4050 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) {
4051 | /* Can do reassembly, and the packet length is split across
4052 | * segment boundaries. */
4053 | pinfo->desegment_offset = offset;
4054 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
4055 | return tvb_captured_length(tvb);
4056 | }
4057 | message_length = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
4058 | ssh_debug_printf("length: %d, remaining: %d\n", message_length, remaining);
4059 | /* The minimum size of a packet (not counting mac) is 16. */
4060 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 16) {
4061 | ws_debug("ssh: unreasonable message length %u", message_length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4061, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0);
4062 | return tvb_captured_length(tvb);
4063 | }
4064 |
4065 | /* SSH requires that the data to be encrypted (not including the AAD,
4066 | * so message_length) be a multiple of the block size, 16 octets */
4067 | if (message_length % 16 != 0) {
4068 | ssh_debug_printf("length not a multiple of block length (16)!\n");
4069 | }
4070 |
4071 | if (message_length + 4 + mac_len > remaining) {
4072 | // Need desegmentation; as the message length was unencrypted
4073 | // AAD, we need no special handling here.
4074 | if (pinfo->can_desegment) {
4075 | pinfo->desegment_offset = offset;
4076 | pinfo->desegment_len = message_length + 4 + mac_len - remaining;
4077 | return tvb_captured_length(tvb);
4078 | }
4079 | // If we can't desegment, we will have an exception below in
4080 | // the tvb_get_ptr. Advance the sequence number (less crucial
4081 | // than with ChaCha20, as it's not an input.)
4082 | peer_data->sequence_number++;
4083 | }
4084 |
4085 | /* Set the IV and increment the invocation_counter for the next
4086 | * packet. Do this before retrieving the ciphertext with tvb_get_ptr
4087 | * in case this packet is truncated.
4088 | */
4089 | if ((err = gcry_cipher_setiv(peer_data->cipher, peer_data->iv, 12))) {
4090 | //gcry_cipher_close(peer_data->cipher);
4091 | //Don't close this unless we also remove the wmem callback
4092 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests
4093 | #ifndef _WIN32
4094 | ws_debug("ssh: can't set aes128 cipher iv")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4094, __func__, "ssh: can't set aes128 cipher iv"); } } while (0);
4095 | ws_debug("libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4095, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0);
4096 | #endif //ndef _WIN32
4097 | return tvb_captured_length(tvb);
4098 | }
4099 | // Increment invocation_counter for next packet
4100 | int idx = 12;
4101 | do{
4102 | idx -= 1;
4103 | peer_data->iv[idx] += 1;
4104 | }while(idx>4 && peer_data->iv[idx]==0);
4105 |
4106 | const char *ctext = (const char *)tvb_get_ptr(tvb, offset + 4,
4107 | message_length);
4108 | plain = (uint8_t *)wmem_alloc(pinfo->pool, message_length+4);
4109 | phtonu32(plain, message_length);
4110 |
4111 | if ((err = gcry_cipher_authenticate(peer_data->cipher, plain, 4))) {
4112 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests
4113 | #ifndef _WIN32
4114 | ws_debug("can't authenticate using aes128-gcm: %s\n", gpg_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4114, __func__, "can't authenticate using aes128-gcm: %s\n" , gpg_strerror(err)); } } while (0);
4115 | #endif //ndef _WIN32
4116 | return tvb_captured_length(tvb);
4117 | }
4118 |
4119 | if ((err = gcry_cipher_decrypt(peer_data->cipher, plain+4, message_length,
4120 | ctext, message_length))) {
4121 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests
4122 | #ifndef _WIN32
4123 | ws_debug("can't decrypt aes-gcm %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4123, __func__, "can't decrypt aes-gcm %d %s %s", gcry_err_code (err), gcry_strsource(err), gcry_strerror(err)); } } while (0 );
4124 |
4125 | #endif //ndef _WIN32
4126 | return tvb_captured_length(tvb);
4127 | }
4128 |
4129 | if (gcry_cipher_gettag (peer_data->cipher, calc_mac, 16)) {
4130 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests
4131 | #ifndef _WIN32
4132 | ws_debug ("aes128-gcm, gcry_cipher_gettag() failed\n")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4132, __func__, "aes128-gcm, gcry_cipher_gettag() failed\n" ); } } while (0);
4133 | #endif //ndef _WIN32
4134 | return tvb_captured_length(tvb);
4135 | }
4136 |
4137 | if ((err = gcry_cipher_reset(peer_data->cipher)gcry_cipher_ctl ((peer_data->cipher), GCRYCTL_RESET, ((void *)0), 0))) {
4138 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests
4139 | #ifndef _WIN32
4140 | ws_debug("aes-gcm, gcry_cipher_reset failed: %s\n", gpg_strerror (err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4140, __func__, "aes-gcm, gcry_cipher_reset failed: %s\n", gpg_strerror (err)); } } while (0);
4141 | #endif //ndef _WIN32
4142 | return tvb_captured_length(tvb);
4143 | }
4144 |
4145 | data_len = message_length + 4;
4146 |
4147 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr);
4148 | ssh_print_data("", plain, message_length+4);
4149 |
4150 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id ||
4151 | CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id ||
4152 | CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id) {
4153 |
4154 | ws_noisy("Getting raw bytes of length %d", tvb_reported_length_remaining(tvb, offset))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4154, __func__, "Getting raw bytes of length %d", tvb_reported_length_remaining (tvb, offset)); } } while (0);
4155 | /* In CBC and CTR mode, the message length is encrypted as well.
4156 | * We need to decrypt one block, 16 octets, to get the length.
4157 | */
4158 | if (ssh_desegment && pinfo->can_desegment && remaining < 16) {
4159 | /* Can do reassembly, and the packet length is split across
4160 | * segment boundaries. */
4161 | pinfo->desegment_offset = offset;
4162 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
4163 | return tvb_captured_length(tvb);
4164 | }
4165 | /* Do we already have the first block decrypted from when the packet
4166 | * was too large and segmented?
4167 | */
4168 | if (!peer_data->plain0_valid) {
4169 | const char *cypher_buf0 = (const char *)tvb_get_ptr(tvb, offset, 16);
4170 |
4171 | if (gcry_cipher_decrypt(peer_data->cipher, peer_data->plain0, 16, cypher_buf0, 16))
4172 | {
4173 | ws_debug("can\'t decrypt aes128")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4173, __func__, "can\'t decrypt aes128"); } } while (0);
4174 | return tvb_captured_length(tvb);
4175 | }
4176 | }
4177 |
4178 | message_length = pntohu32(peer_data->plain0);
4179 |
4180 | /* The message_length value doesn't include the length of the
4181 | * message_length field itself, so it must be at least 12 bytes.
4182 | */
4183 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 12){
4184 | ws_debug("ssh: unreasonable message length %u", message_length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4184, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0);
4185 | return tvb_captured_length(tvb);
4186 | }
4187 |
4188 | /* SSH requires that the data to be encrypted (message_length+4)
4189 | * be a multiple of the block size, 16 octets. */
4190 | if (message_length % 16 != 12) {
4191 | ssh_debug_printf("total length not a multiple of block length (16)!\n");
4192 | }
4193 | if (remaining < message_length + 4 + mac_len) {
4194 | /* Need desegmentation
4195 | *
4196 | * We will be handed the full encrypted packet again. We can either
4197 | * store the decrypted first block, or will need to reset the CTR
4198 | * or IV appropriately before decrypting the first block again.
4199 | * libgcrypt does not provide an easy way to get the current value
4200 | * of the CTR or (or IV/last block for CBC), so we just store the
4201 | * decrypted first block.
4202 | */
4203 | if (ssh_desegment && pinfo->can_desegment) {
4204 | ws_noisy(" need_desegmentation: offset = %d, reported_length_remaining = %d\n",do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4205, __func__, " need_desegmentation: offset = %d, reported_length_remaining = %d\n" , offset, tvb_reported_length_remaining(tvb, offset)); } } while (0)
4205 | offset, tvb_reported_length_remaining(tvb, offset))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4205, __func__, " need_desegmentation: offset = %d, reported_length_remaining = %d\n" , offset, tvb_reported_length_remaining(tvb, offset)); } } while (0);
4206 | peer_data->plain0_valid = true1;
4207 | pinfo->desegment_offset = offset;
4208 | pinfo->desegment_len = message_length + 4 + mac_len - remaining;
4209 | return tvb_captured_length(tvb);
4210 | } else {
4211 | // If we can't desegment, we will have an exception below in
4212 | // the tvb_get_ptr. Advance the sequence number so that the
4213 | // the hash will work for the next packet.
4214 | //
4215 | // XXX - In CTR mode, we should advance the CTR based on the
4216 | // known length so we can dissect the next block. We would
4217 | // also need to reset the CTR after failing to dissect a
4218 | // packet_length on the continuation data that comes next.
4219 | peer_data->sequence_number++;
4220 | }
4221 | }
4222 | peer_data->plain0_valid = false0;
4223 | plain = (uint8_t *)wmem_alloc(pinfo->pool, message_length+4);
4224 | memcpy(plain, peer_data->plain0, 16);
4225 |
4226 | if (message_length > 12) {
4227 | /* All of these functions actually do handle the case where
4228 | * there is no data left, so the check is unnecessary.
4229 | */
4230 | char *ct = (char *)tvb_get_ptr(tvb, offset + 16, message_length - 12);
4231 | if ((err = gcry_cipher_decrypt(peer_data->cipher, plain + 16, message_length - 12, ct, message_length - 12)))
4232 | {
4233 | ws_debug("can't decrypt aes-cbc/ctr %d %s %s", gcry_err_code(err), gcry_strsource(err), gcry_strerror(err))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4233, __func__, "can't decrypt aes-cbc/ctr %d %s %s", gcry_err_code (err), gcry_strsource(err), gcry_strerror(err)); } } while (0 );
4234 | return tvb_captured_length(tvb);
4235 | }
4236 | }
4237 |
4238 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr);
4239 | ssh_print_data("", plain, message_length+4);
4240 |
4241 | data_len = message_length + 4;
4242 |
4243 | // XXX - In -etm modes, should calculate MAC based on ciphertext.
4244 | ssh_calc_mac(peer_data, seqnr, plain, data_len, calc_mac);
4245 | } else if (CIPHER_NULL0x00080000 == peer_data->cipher_id) {
4246 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) {
4247 | /* Can do reassembly, and the packet length is split across
4248 | * segment boundaries. */
4249 | pinfo->desegment_offset = offset;
4250 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
4251 | return tvb_captured_length(tvb);
4252 | }
4253 | message_length = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
4254 | ssh_debug_printf("length: %d, remaining: %d\n", message_length, remaining);
4255 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 8) {
4256 | ws_debug("ssh: unreasonable message length %u", message_length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4256, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0);
4257 | return tvb_captured_length(tvb);
4258 | }
4259 |
4260 | if (message_length + 4 + mac_len > remaining) {
4261 | // Need desegmentation; as the message length was unencrypted
4262 | // AAD, we need no special handling here.
4263 | if (pinfo->can_desegment) {
4264 | pinfo->desegment_offset = offset;
4265 | pinfo->desegment_len = message_length + 4 + mac_len - remaining;
4266 | return tvb_captured_length(tvb);
4267 | }
4268 | // If we can't desegment, we will have an exception below in
4269 | // the tvb_memdup. Advance the sequence number (not crucial).
4270 | peer_data->sequence_number++;
4271 | }
4272 | data_len = message_length + 4;
4273 | plain = tvb_memdup(pinfo->pool, tvb, offset, data_len);
4274 |
4275 | // XXX - In -etm modes, should calculate MAC based on ciphertext.
4276 | ssh_calc_mac(peer_data, seqnr, plain, data_len, calc_mac);
4277 | }
4278 |
4279 | if (mac_len && data_len) {
4280 | if (mac_len <= DIGEST_MAX_SIZE48 && !memcmp(tvb_get_ptr(tvb, offset + data_len, mac_len), calc_mac, mac_len)){
4281 | ws_noisy("MAC OK")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4281, __func__, "MAC OK"); } } while (0);
4282 | }else{
4283 | ws_debug("MAC ERR")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4283, __func__, "MAC ERR"); } } while (0);
4284 | /* Bad MAC, just show the packet as encrypted. We can get
4285 | * this for a known encryption type with no keys currently. */
4286 | if (!ssh_ignore_mac_failed) {
4287 | return tvb_captured_length(tvb);
4288 | }
4289 | }
4290 | }
4291 |
4292 | if(plain){
4293 | // Save message
4294 |
4295 | ssh_packet_info_t *packet = ssh_get_packet_info(pinfo, is_response);
4296 |
4297 | int record_id = tvb_raw_offset(tvb)+offset;
4298 | ssh_message_info_t *message;
4299 |
4300 | message = wmem_new(wmem_file_scope(), ssh_message_info_t)((ssh_message_info_t*)wmem_alloc((wmem_file_scope()), sizeof( ssh_message_info_t)));
4301 | message->sequence_number = peer_data->sequence_number++;
4302 | message->plain_data = wmem_memdup(wmem_file_scope(), plain, data_len);
4303 | message->data_len = data_len;
4304 | message->id = record_id;
4305 | message->next = NULL((void*)0);
4306 | memcpy(message->calc_mac, calc_mac, DIGEST_MAX_SIZE48);
4307 | ssh_debug_printf("%s->sequence_number++ > %d\n", is_response?"server":"client", peer_data->sequence_number);
4308 |
4309 | ssh_message_info_t **pmessage = &packet->messages;
4310 | while(*pmessage){
4311 | pmessage = &(*pmessage)->next;
4312 | }
4313 | *pmessage = message;
4314 | }
4315 |
4316 | offset += message_length + mac_len + 4;
4317 | return offset;
4318 | }
4319 |
4320 | static bool_Bool
4321 | ssh_decrypt_chacha20(gcry_cipher_hd_t hd,
4322 | uint32_t seqnr, uint32_t counter, const unsigned char *ctext, unsigned ctext_len,
4323 | unsigned char *plain, unsigned plain_len)
4324 | {
4325 | unsigned char seq[8];
4326 | unsigned char iv[16];
4327 |
4328 | phtonu64(seq, (uint64_t)seqnr);
4329 |
4330 | // chacha20 uses a different cipher handle for the packet payload & length
4331 | // the payload uses a block counter
4332 | if (counter) {
4333 | const unsigned char ctr[8] = {1,0,0,0,0,0,0,0};
4334 | memcpy(iv, ctr, 8);
4335 | memcpy(iv+8, seq, 8);
4336 | }
4337 |
4338 | return ((!counter && gcry_cipher_setiv(hd, seq, 8) == 0) ||
4339 | (counter && gcry_cipher_setiv(hd, iv, 16) == 0)) &&
4340 | gcry_cipher_decrypt(hd, plain, plain_len, ctext, ctext_len) == 0;
4341 | }
4342 |
4343 | static int
4344 | ssh_dissect_decrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
4345 | struct ssh_peer_data *peer_data, proto_tree *tree,
4346 | ssh_message_info_t *message)
4347 | {
4348 | unsigned offset = 0; // TODO:
4349 | int dissected_len = 0;
4350 | tvbuff_t* payload_tvb;
4351 |
4352 | const uint8_t* plaintext = message->plain_data;
4353 | unsigned plaintext_len = message->data_len;
4354 |
4355 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (plaintext_len=%d)", plaintext_len);
4356 |
4357 | tvbuff_t *packet_tvb = tvb_new_child_real_data(tvb, plaintext, plaintext_len, plaintext_len);
4358 | add_new_data_source(pinfo, packet_tvb, "Decrypted Packet");
4359 |
4360 | unsigned plen;
4361 | uint32_t padding_length;
4362 | unsigned remain_length;
4363 | unsigned msg_code;
4364 |
4365 | proto_item *ti, *padding_ti;
4366 | proto_item *msg_type_tree = NULL((void*)0);
4367 |
4368 | /*
4369 | * We use "tvb_ensure_captured_length_remaining()" to make sure there
4370 | * actually *is* data remaining.
4371 | *
4372 | * This means we're guaranteed that "remain_length" is positive.
4373 | */
4374 | remain_length = tvb_ensure_captured_length_remaining(packet_tvb, offset);
4375 | /*
4376 | * Can we do reassembly?
4377 | */
4378 | if (ssh_desegment && pinfo->can_desegment) {
4379 | /*
4380 | * Yes - would an SSH header starting at this offset
4381 | * be split across segment boundaries?
4382 | */
4383 | if (remain_length < 4) {
4384 | /*
4385 | * Yes. Tell the TCP dissector where the data for
4386 | * this message starts in the data it handed us and
4387 | * that we need "some more data." Don't tell it
4388 | * exactly how many bytes we need because if/when we
4389 | * ask for even more (after the header) that will
4390 | * break reassembly.
4391 | */
4392 | pinfo->desegment_offset = offset;
4393 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff;
4394 | return offset;
4395 | }
4396 | }
4397 | /* XXX - Defragmentation needs to be done in ssh_decrypt_packet, and the
4398 | * checks there should mean that the above never has an effect. (It's
4399 | * copied from ssh_dissect_key_exchange.)
4400 | */
4401 | plen = tvb_get_ntohl(packet_tvb, offset);
4402 |
4403 | if (ssh_desegment && pinfo->can_desegment) {
4404 | if (plen + 4 > remain_length) {
4405 | pinfo->desegment_offset = offset;
4406 | pinfo->desegment_len = plen+4 - remain_length;
4407 | return offset;
4408 | }
4409 | }
4410 | /*
4411 | * Need to check plen > 0x80000000 here
4412 | */
4413 |
4414 | ti = proto_tree_add_uint(tree, hf_ssh_packet_length, packet_tvb,
4415 | offset, 4, plen);
4416 | if (plen < 8) {
4417 | /* RFC 4253 6: "[T]he length of the concatenation of 'packet_length',
4418 | * 'padding_length', 'payload', and 'random padding' MUST be a multiple
4419 | * of the cipher block size or 8, whichever is larger,... even when
4420 | * using stream ciphers."
4421 | *
4422 | * Modes that do not encrypt plen with the same key as the other three
4423 | * cannot follow this as written and delete 'packet_length' from the
4424 | * above sentence. As padding_length is one byte and random_padding at
4425 | * least four, packet_length must be at least 8 in all modes.
4426 | */
4427 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Packet length is %d, MUST be at least 8", plen);
4428 | } else if (plen >= SSH_MAX_PACKET_LEN32768) {
4429 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Overly large number %d", plen);
4430 | plen = remain_length-4;
4431 | }
4432 | offset+=4;
4433 |
4434 | /* padding length */
4435 | padding_ti = proto_tree_add_item_ret_uint(tree, hf_ssh_padding_length, packet_tvb, offset, 1, ENC_NA0x00000000, &padding_length);
4436 | /* RFC 4253 6: "There MUST be at least four bytes of padding." */
4437 | if (padding_length < 4) {
4438 | expert_add_info_format(pinfo, padding_ti, &ei_ssh_padding_length, "Padding length is %d, MUST be at least 4", padding_length);
4439 | }
4440 | unsigned payload_length;
4441 | if (ckd_sub(&payload_length, plen, padding_length + 1)__builtin_sub_overflow((plen), (padding_length + 1), (&payload_length ))) {
4442 | expert_add_info_format(pinfo, padding_ti, &ei_ssh_padding_length, "Padding length is too large [%d], implies a negative payload length", padding_length);
4443 | payload_length = 0;
4444 | }
4445 | offset += 1;
4446 |
4447 | /* msg_code */
4448 | msg_code = tvb_get_uint8(packet_tvb, offset);
4449 | /* XXX - Payload compression could have been negotiated */
4450 | payload_tvb = tvb_new_subset_length(packet_tvb, offset, (int)payload_length);
4451 | bool_Bool is_response = ssh_peer_data_from_server(peer_data);
4452 |
4453 | /* Transport layer protocol */
4454 | /* Generic (1-19) */
4455 | if(msg_code >= 1 && msg_code <= 19) {
4456 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4457 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Transport (generic)");
4458 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4459 | dissected_len = ssh_dissect_transport_generic(payload_tvb, pinfo, 1, peer_data, msg_type_tree, msg_code);
4460 | }
4461 | /* Algorithm negotiation (20-29) */
4462 | /* Normally these messages are all dissected in ssh_dissect_key_exchange */
4463 | else if(msg_code >=20 && msg_code <= 29) {
4464 | //TODO: See if the complete dissector should be refactored to always go through here first offset = ssh_dissect_transport_algorithm_negotiation(packet_tvb, pinfo, global_data, offset, msg_type_tree, is_response, msg_code);
4465 |
4466 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4467 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Transport (algorithm negotiation)");
4468 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4469 | dissected_len = 1;
4470 |
4471 | ws_debug("SSH dissect: pass %u, frame %u, msg_code %u, do_decrypt=%d", pinfo->fd->visited, pinfo->fd->num, msg_code, peer_data->global_data->do_decrypt)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4471, __func__, "SSH dissect: pass %u, frame %u, msg_code %u, do_decrypt=%d" , pinfo->fd->visited, pinfo->fd->num, msg_code, peer_data ->global_data->do_decrypt); } } while (0);
4472 | switch(msg_code)
4473 | {
4474 | case SSH_MSG_KEXINIT20:
4475 | {
4476 | ws_debug("ssh: REKEY msg_code 20: storing frame %u number, offset %d" , pinfo->num, offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4476, __func__, "ssh: REKEY msg_code 20: storing frame %u number, offset %d" , pinfo->num, offset); } } while (0);
4477 | peer_data->rekey_trigger_frame = pinfo->num;
4478 | // Reset array while REKEY: sanitize server_key_exchange_init and force do_decrypt :
4479 | peer_data->global_data->kex_server_key_exchange_init = wmem_array_new(wmem_file_scope(), 1);
4480 | peer_data->global_data->do_decrypt = true1;
4481 | dissected_len = ssh_dissect_key_init(payload_tvb, pinfo, offset - 4, msg_type_tree, is_response, peer_data->global_data);
4482 | break;
4483 | }
4484 | case SSH_MSG_NEWKEYS21:
4485 | {
4486 | if (peer_data->rekey_pending) {
4487 | ws_debug("ssh: REKEY pending... NEWKEYS frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4487, __func__, "ssh: REKEY pending... NEWKEYS frame %u", pinfo ->num); } } while (0);
4488 | ws_debug("ssh: decrypting frame %u with key ID %u, seq=%u", pinfo->num, peer_data->cipher_id, peer_data->sequence_number)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4488, __func__, "ssh: decrypting frame %u with key ID %u, seq=%u" , pinfo->num, peer_data->cipher_id, peer_data->sequence_number ); } } while (0);
4489 | if (peer_data->global_data->ext_kex_strict) {
4490 | peer_data->sequence_number = 0;
4491 | ssh_debug_printf("%s->sequence_number reset to 0 (Strict KEX)\n", is_response ? "server" : "client");
4492 | ws_debug("ssh: REKEY reset %s sequence number to 0 at frame %u (Strict KEX)", is_response ? "server" : "client", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4492, __func__, "ssh: REKEY reset %s sequence number to 0 at frame %u (Strict KEX)" , is_response ? "server" : "client", pinfo->num); } } while (0);
4493 | }
4494 | // finalize the rekey (activate the new keys)
4495 | if (!is_response) { // Only process client-sent NEWKEYS
4496 | // Activate new key material into peer_data->cipher
4497 | ssh_debug_printf("Activating new keys for CLIENT => SERVER\n");
4498 | ssh_decryption_setup_cipher(peer_data, &peer_data->global_data->new_keys[0], &peer_data->global_data->new_keys[2]);
4499 | ssh_decryption_setup_mac(peer_data, &peer_data->global_data->new_keys[4]);
4500 | } else { // Only process server-sent NEWKEYS
4501 | // Activate new key material into peer_data->cipher
4502 | ssh_debug_printf("Activating new keys for SERVER => CLIENT\n");
4503 | ssh_decryption_setup_cipher(peer_data, &peer_data->global_data->new_keys[1], &peer_data->global_data->new_keys[3]);
4504 | ssh_decryption_setup_mac(peer_data, &peer_data->global_data->new_keys[5]);
4505 | }
4506 | // Finishing REKEY
4507 | peer_data->rekey_pending = false0;
4508 | ws_debug("ssh: REKEY done... switched to NEWKEYS at frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4508, __func__, "ssh: REKEY done... switched to NEWKEYS at frame %u" , pinfo->num); } } while (0);
4509 | }
4510 | break;
4511 | }
4512 | }
4513 | }
4514 | /* Key exchange method specific (reusable) (30-49) */
4515 | /* Normally these messages are all dissected in ssh_dissect_key_exchange */
4516 | else if (msg_code >=30 && msg_code <= 49) {
4517 | //TODO: See if the complete dissector should be refactored to always go through here first offset = global_data->kex_specific_dissector(msg_code, packet_tvb, pinfo, offset, msg_type_tree);
4518 |
4519 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Transport (key exchange method specific)");
4520 | ws_debug("ssh: rekey KEX_xxx_INIT/KEX_xxx_REPLY detected in frame %u", pinfo->num)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4520, __func__, "ssh: rekey KEX_xxx_INIT/KEX_xxx_REPLY detected in frame %u" , pinfo->num); } } while (0);
4521 | peer_data->rekey_pending = true1;
4522 | dissected_len = peer_data->global_data->kex_specific_dissector(msg_code, payload_tvb, pinfo, offset -5, msg_type_tree, peer_data->global_data);
4523 | }
4524 |
4525 | /* User authentication protocol */
4526 | /* Generic (50-59) */
4527 | else if (msg_code >= 50 && msg_code <= 59) {
4528 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4529 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: User Authentication (generic)");
4530 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4531 | dissected_len = ssh_dissect_userauth_generic(payload_tvb, pinfo, 1, msg_type_tree, msg_code);
4532 | }
4533 | /* User authentication method specific (reusable) (60-79) */
4534 | else if (msg_code >= 60 && msg_code <= 79) {
4535 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4536 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: User Authentication: (method specific)");
4537 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4538 | dissected_len = ssh_dissect_userauth_specific(payload_tvb, pinfo, 1, msg_type_tree, msg_code);
4539 | }
4540 |
4541 | /* Connection protocol */
4542 | /* Generic (80-89) */
4543 | else if (msg_code >= 80 && msg_code <= 89) {
4544 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4545 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Connection (generic)");
4546 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4547 | dissected_len = ssh_dissect_connection_generic(payload_tvb, pinfo, 1, msg_type_tree, msg_code);
4548 | }
4549 | /* Channel related messages (90-127) */
4550 | else if (msg_code >= 90 && msg_code <= 127) {
4551 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4552 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Connection: (channel related message)");
4553 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4554 | dissected_len = ssh_dissect_connection_specific(payload_tvb, pinfo, peer_data, 1, msg_type_tree, msg_code, message);
4555 | }
4556 |
4557 | /* Reserved for client protocols (128-191) */
4558 | else if (msg_code >= 128 && msg_code <= 191) {
4559 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
4560 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Client protocol");
4561 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4562 | offset+=1;
4563 | // TODO: dissected_len = ssh_dissect_client(payload_tvb, pinfo, global_data, 1, msg_type_tree, is_response, msg_code);
4564 | }
4565 |
4566 | /* Local extensions (192-255) */
4567 | else if (msg_code >= 192 && msg_code <= 255) {
4568 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Local extension");
4569 | dissected_len = ssh_dissect_local_extension(payload_tvb, pinfo, 0, peer_data, msg_type_tree, msg_code);
4570 | }
4571 |
4572 | /* XXX - ssh_dissect_key_exchange only adds undecoded payload here,
4573 | * i.e., tvb_reported_length_remaining(payload_tvb, dissected_len)
4574 | */
4575 | if (payload_length > 0) {
4576 | proto_tree_add_item(msg_type_tree, hf_ssh_payload, packet_tvb, offset, payload_length, ENC_NA0x00000000);
4577 | }
4578 | if(dissected_len!=(int)payload_length){
4579 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but payload length is %d bytes [%d]", dissected_len, payload_length, msg_code);
4580 | }
4581 | offset += payload_length;
4582 |
4583 | /* padding */
4584 | proto_tree_add_item(tree, hf_ssh_padding_string, packet_tvb, offset, padding_length, ENC_NA0x00000000);
4585 | offset += padding_length;
4586 |
4587 | if (peer_data->mac_length > 0) {
4588 | proto_tree_add_checksum_bytes(tree, tvb, offset, hf_ssh_mac_string, hf_ssh_mac_status, &ei_ssh_mac_bad, pinfo, message->calc_mac, peer_data->mac_length, PROTO_CHECKSUM_VERIFY0x01);
4589 | offset += peer_data->mac_length;
4590 | }
4591 | ti = proto_tree_add_uint(tree, hf_ssh_seq_num, tvb, offset, 0, message->sequence_number);
4592 | proto_item_set_generated(ti);
4593 | return offset;
4594 | }
4595 |
4596 | static int
4597 | ssh_dissect_transport_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
4598 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code)
4599 | {
4600 | (void)pinfo;
4601 | if(msg_code==SSH_MSG_DISCONNECT1){
4602 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_reason, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4603 | offset += 4;
4604 | unsigned nlen;
4605 | nlen = tvb_get_ntohl(packet_tvb, offset) ;
4606 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_description_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4607 | offset += 4;
4608 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_description, packet_tvb, offset, nlen, ENC_ASCII0x00000000);
4609 | offset += nlen;
4610 | nlen = tvb_get_ntohl(packet_tvb, offset) ;
4611 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4612 | offset += 4;
4613 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag, packet_tvb, offset, nlen, ENC_ASCII0x00000000);
4614 | offset += nlen;
4615 | }else if(msg_code==SSH_MSG_IGNORE2){
4616 | offset += ssh_tree_add_string(packet_tvb, offset, msg_type_tree, hf_ssh_ignore_data, hf_ssh_ignore_data_length);
4617 | }else if(msg_code==SSH_MSG_DEBUG4){
4618 | unsigned slen;
4619 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_always_display, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4620 | offset += 1;
4621 | slen = tvb_get_ntohl(packet_tvb, offset) ;
4622 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_message_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4623 | offset += 4;
4624 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_message, packet_tvb, offset, slen, ENC_UTF_80x00000002);
4625 | offset += slen;
4626 | slen = tvb_get_ntohl(packet_tvb, offset) ;
4627 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4628 | offset += 4;
4629 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4630 | offset += slen;
4631 | }else if(msg_code==SSH_MSG_SERVICE_REQUEST5){
4632 | unsigned nlen;
4633 | nlen = tvb_get_ntohl(packet_tvb, offset) ;
4634 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4635 | offset += 4;
4636 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name, packet_tvb, offset, nlen, ENC_ASCII0x00000000);
4637 | offset += nlen;
4638 | }else if(msg_code==SSH_MSG_SERVICE_ACCEPT6){
4639 | unsigned nlen;
4640 | nlen = tvb_get_ntohl(packet_tvb, offset) ;
4641 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4642 | offset += 4;
4643 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name, packet_tvb, offset, nlen, ENC_ASCII0x00000000);
4644 | offset += nlen;
4645 | }else if(msg_code==SSH_MSG_EXT_INFO7){
4646 | unsigned ext_cnt;
4647 | ext_cnt = tvb_get_ntohl(packet_tvb, offset);
4648 | proto_tree_add_item(msg_type_tree, hf_ssh_ext_count, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4649 | offset += 4;
4650 | for(unsigned ext_index = 0; ext_index < ext_cnt; ext_index++) {
4651 | offset = ssh_dissect_rfc8308_extension(packet_tvb, pinfo, offset, peer_data, msg_type_tree);
4652 | }
4653 | }
4654 | return offset;
4655 | }
4656 |
4657 | static int
4658 | ssh_dissect_rfc8308_extension(tvbuff_t *packet_tvb, packet_info *pinfo,
4659 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree)
4660 | {
4661 | (void)pinfo;
4662 | unsigned ext_name_slen = tvb_get_ntohl(packet_tvb, offset);
4663 | uint8_t *ext_name = tvb_get_string_enc(pinfo->pool, packet_tvb, offset + 4, ext_name_slen, ENC_ASCII0x00000000);
4664 | unsigned ext_value_slen = tvb_get_ntohl(packet_tvb, offset + 4 + ext_name_slen);
4665 | unsigned ext_len = 8 + ext_name_slen + ext_value_slen;
4666 | proto_item *ext_tree = proto_tree_add_subtree_format(msg_type_tree, packet_tvb, offset, ext_len, ett_extension, NULL((void*)0), "Extension: %s", ext_name);
4667 |
4668 | proto_tree_add_item(ext_tree, hf_ssh_ext_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4669 | offset += 4;
4670 | proto_tree_add_item(ext_tree, hf_ssh_ext_name, packet_tvb, offset, ext_name_slen, ENC_ASCII0x00000000);
4671 | offset += ext_name_slen;
4672 | proto_tree_add_item(ext_tree, hf_ssh_ext_value_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4673 | offset += 4;
4674 | proto_tree_add_item(ext_tree, hf_ssh_ext_value, packet_tvb, offset, ext_value_slen, ENC_NA0x00000000);
4675 |
4676 | if (g_str_equal(ext_name, "server-sig-algs")(strcmp ((const char *) (ext_name), (const char *) ("server-sig-algs" )) == 0)) {
4677 | // server-sig-algs (RFC8308 Sec. 3.1)
4678 | proto_tree_add_item(ext_tree, hf_ssh_ext_server_sig_algs_algorithms, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000);
4679 | offset += ext_value_slen;
4680 | } else if (g_str_equal(ext_name, "delay-compression")(strcmp ((const char *) (ext_name), (const char *) ("delay-compression" )) == 0)) {
4681 | // delay-compression (RFC8308 Sec 3.2)
4682 | unsigned slen;
4683 | slen = tvb_get_ntohl(packet_tvb, offset);
4684 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_client_to_server_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4685 | offset += 4;
4686 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_client_to_server, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4687 | offset += slen;
4688 | slen = tvb_get_ntohl(packet_tvb, offset);
4689 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_server_to_client_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4690 | offset += 4;
4691 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_server_to_client, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4692 | offset += slen;
4693 | } else if (g_str_equal(ext_name, "no-flow-control")(strcmp ((const char *) (ext_name), (const char *) ("no-flow-control" )) == 0)) {
4694 | // no-flow-control (RFC 8308 Sec 3.3)
4695 | proto_tree_add_item(ext_tree, hf_ssh_ext_no_flow_control_value, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000);
4696 | offset += ext_value_slen;
4697 | } else if (g_str_equal(ext_name, "elevation")(strcmp ((const char *) (ext_name), (const char *) ("elevation" )) == 0)) {
4698 | // elevation (RFC 8308 Sec 3.4)
4699 | proto_tree_add_item(ext_tree, hf_ssh_ext_elevation_value, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000);
4700 | offset += ext_value_slen;
4701 | } else if (g_str_equal(ext_name, "publickey-algorithms@roumenpetrov.info")(strcmp ((const char *) (ext_name), (const char *) ("publickey-algorithms@roumenpetrov.info" )) == 0)) {
4702 | // publickey-algorithms@roumenpetrov.info (proprietary)
4703 | proto_tree_add_item(ext_tree, hf_ssh_ext_prop_publickey_algorithms_algorithms, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000);
4704 | offset += ext_value_slen;
4705 | } else if (g_str_equal(ext_name, "ping@openssh.com")(strcmp ((const char *) (ext_name), (const char *) ("ping@openssh.com" )) == 0)) {
4706 | // ping@openssh.com (proprietary w/ primitive extension value)
4707 | peer_data->global_data->ext_ping_openssh_offered = true1;
4708 | offset += ext_value_slen;
4709 | } else {
4710 | offset += ext_value_slen;
4711 | }
4712 |
4713 | // The following extensions do not require advanced dissection:
4714 | // - global-requests-ok
4715 | // - ext-auth-info
4716 | // - publickey-hostbound@openssh.com
4717 | // - ext-info-in-auth@openssh.com
4718 |
4719 | return offset;
4720 | }
4721 |
4722 | static int
4723 | ssh_dissect_userauth_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
4724 | int offset, proto_item *msg_type_tree, unsigned msg_code)
4725 | {
4726 | if(msg_code==SSH_MSG_USERAUTH_REQUEST50){
4727 | uint32_t slen;
4728 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_user_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4729 | offset += 4;
4730 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_user_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4731 | offset += slen;
4732 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4733 | offset += 4;
4734 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_service_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4735 | offset += slen;
4736 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_method_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4737 | offset += 4;
4738 | const char* key_type;
4739 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_userauth_method_name, packet_tvb, offset, slen, ENC_ASCII0x00000000, pinfo->pool, (const uint8_t**)&key_type);
4740 | offset += slen;
4741 | if (0 == strcmp(key_type, "none")) {
4742 | }else if (0 == strcmp(key_type, "publickey") || 0 == strcmp(key_type, "publickey-hostbound-v00@openssh.com")) {
4743 | uint8_t bHaveSignature = tvb_get_uint8(packet_tvb, offset);
4744 | int dissected_len = 0;
4745 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_have_signature, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4746 | offset += 1;
4747 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_pka_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4748 | offset += 4;
4749 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4750 | offset += slen;
4751 | proto_item *ti;
4752 | ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_blob_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4753 | offset += 4;
4754 | dissected_len = ssh_dissect_public_key_blob(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree);
4755 | if(dissected_len!=(int)slen){
4756 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen);
4757 | }
4758 | offset += slen;
4759 | if (0 == strcmp(key_type, "publickey-hostbound-v00@openssh.com")) {
4760 | // Host key - but should we add it to global data or not?
4761 | offset += ssh_tree_add_hostkey(packet_tvb, pinfo, offset, msg_type_tree, "Server host key",
4762 | ett_key_exchange_host_key, NULL((void*)0));
4763 | }
4764 | if(bHaveSignature){
4765 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_signature_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4766 | offset += 4;
4767 | proto_item *signature_tree = NULL((void*)0);
4768 | signature_tree = proto_tree_add_subtree(msg_type_tree, packet_tvb, offset, slen, ett_userauth_pk_signature, NULL((void*)0), "Public key signature");
4769 | dissected_len = ssh_dissect_public_key_signature(packet_tvb, pinfo, offset, signature_tree) - offset;
4770 | if(dissected_len!=(int)slen){
4771 | expert_add_info_format(pinfo, signature_tree, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen);
4772 | }
4773 | offset += slen;
4774 | }
4775 | }else if (0 == strcmp(key_type, "password")) {
4776 | uint8_t bChangePassword = tvb_get_uint8(packet_tvb, offset);
4777 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_change_password, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4778 | offset += 1;
4779 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_password_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4780 | offset += 4;
4781 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_password, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4782 | offset += slen;
4783 | if(bChangePassword){
4784 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_new_password_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4785 | offset += 4;
4786 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_new_password, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4787 | offset += slen;
4788 | }
4789 | }else{
4790 | }
4791 |
4792 | }else if(msg_code==SSH_MSG_USERAUTH_FAILURE51){
4793 | unsigned slen;
4794 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_auth_failure_list_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4795 | offset += 4;
4796 | proto_tree_add_item(msg_type_tree, hf_ssh_auth_failure_list, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4797 | offset += slen;
4798 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_partial_success, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
4799 | offset += 1;
4800 | }
4801 | return offset;
4802 | }
4803 |
4804 | static int
4805 | ssh_dissect_userauth_specific(tvbuff_t *packet_tvb, packet_info *pinfo,
4806 | int offset, proto_item *msg_type_tree, unsigned msg_code)
4807 | {
4808 | if(msg_code==SSH_MSG_USERAUTH_PK_OK60){
4809 | proto_item *ti;
4810 | int dissected_len = 0;
4811 | unsigned slen;
4812 | slen = tvb_get_ntohl(packet_tvb, offset) ;
4813 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
4814 | offset += 4;
4815 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
4816 | offset += slen;
4817 | ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_blob_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
4818 | offset += 4;
4819 | dissected_len = ssh_dissect_public_key_blob(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree);
4820 | if(dissected_len!=(int)slen){
4821 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen);
4822 | }
4823 | offset += slen;
4824 | }
4825 | return offset;
4826 | }
4827 |
4828 | static void
4829 | ssh_process_payload(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, ssh_channel_info_t *channel)
4830 | {
4831 | tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset);
4832 | if (channel->handle) {
4833 | call_dissector(channel->handle, next_tvb, pinfo, proto_tree_get_root(tree));
4834 | } else {
4835 | call_data_dissector(next_tvb, pinfo, proto_tree_get_root(tree));
4836 | }
4837 | }
4838 |
4839 | static void
4840 | print_ssh_fragment_tree(fragment_head *ipfd_head, proto_tree *tree, proto_tree *ssh_tree, packet_info *pinfo, tvbuff_t *next_tvb)
4841 | {
4842 | proto_item *ssh_tree_item, *frag_tree_item;
4843 |
4844 | /*
4845 | * The subdissector thought it was completely
4846 | * desegmented (although the stuff at the
4847 | * end may, in turn, require desegmentation),
4848 | * so we show a tree with all segments.
4849 | */
4850 | show_fragment_tree(ipfd_head, &ssh_segment_items,
4851 | tree, pinfo, next_tvb, &frag_tree_item);
4852 | /*
4853 | * The toplevel fragment subtree is now
4854 | * behind all desegmented data; move it
4855 | * right behind the SSH tree.
4856 | */
4857 | ssh_tree_item = proto_tree_get_parent(ssh_tree);
4858 | /* The SSH protocol item is up a few levels from the message tree */
4859 | ssh_tree_item = proto_item_get_parent_nth(ssh_tree_item, 2);
4860 | if (frag_tree_item && ssh_tree_item) {
4861 | proto_tree_move_item(tree, ssh_tree_item, frag_tree_item);
4862 | }
4863 | }
4864 |
4865 | static uint32_t
4866 | ssh_msp_fragment_id(struct tcp_multisegment_pdu *msp)
4867 | {
4868 | /*
4869 | * If a frame contains multiple PDUs, then "first_frame" is not
4870 | * sufficient to uniquely identify groups of fragments. Therefore we use
4871 | * the tcp reassembly functions that also test msp->seq (the position of
4872 | * the initial fragment in the SSH channel).
4873 | */
4874 | return msp->first_frame;
4875 | }
4876 |
4877 | static void
4878 | ssh_proto_tree_add_segment_data(
4879 | proto_tree *tree,
4880 | tvbuff_t *tvb,
4881 | int offset,
4882 | int length,
4883 | const char *prefix)
4884 | {
4885 | proto_tree_add_bytes_format(
4886 | tree,
4887 | hf_ssh_segment_data,
4888 | tvb,
4889 | offset,
4890 | length,
4891 | NULL((void*)0),
4892 | "%sSSH segment data (%u %s)",
4893 | prefix != NULL((void*)0) ? prefix : "",
4894 | length,
4895 | plurality(length, "byte", "bytes")((length) == 1 ? ("byte") : ("bytes")));
4896 | }
4897 |
4898 | static void
4899 | desegment_ssh(tvbuff_t *tvb, packet_info *pinfo, uint32_t seq,
4900 | uint32_t nxtseq, proto_tree *tree, ssh_channel_info_t *channel)
4901 | {
4902 | fragment_head *ipfd_head;
4903 | bool_Bool must_desegment;
4904 | bool_Bool called_dissector;
4905 | unsigned another_pdu_follows;
4906 | bool_Bool another_segment_in_frame = false0;
4907 | int deseg_offset, offset = 0;
4908 | uint32_t deseg_seq;
4909 | int nbytes;
4910 | proto_item *item;
4911 | struct tcp_multisegment_pdu *msp;
4912 | bool_Bool first_pdu = true1;
4913 |
4914 | again:
4915 | ipfd_head = NULL((void*)0);
4916 | must_desegment = false0;
4917 | called_dissector = false0;
4918 | another_pdu_follows = 0;
4919 | msp = NULL((void*)0);
4920 |
4921 | /*
4922 | * Initialize these to assume no desegmentation.
4923 | * If that's not the case, these will be set appropriately
4924 | * by the subdissector.
4925 | */
4926 | pinfo->desegment_offset = 0;
4927 | pinfo->desegment_len = 0;
4928 |
4929 | /*
4930 | * Initialize this to assume that this segment will just be
4931 | * added to the middle of a desegmented chunk of data, so
4932 | * that we should show it all as data.
4933 | * If that's not the case, it will be set appropriately.
4934 | */
4935 | deseg_offset = offset;
4936 |
4937 | /* If we've seen this segment before (e.g., it's a retransmission),
4938 | * there's nothing for us to do. Certainly, don't add it to the list
4939 | * of multisegment_pdus (that would cause subsequent lookups to find
4940 | * the retransmission instead of the original transmission, breaking
4941 | * dissection of the desegmented pdu if we'd already seen the end of
4942 | * the pdu).
4943 | */
4944 | if ((msp = (struct tcp_multisegment_pdu *)wmem_tree_lookup32(channel->multisegment_pdus, seq))) {
4945 | const char *prefix;
4946 | bool_Bool is_retransmission = false0;
4947 |
4948 | if (msp->first_frame == pinfo->num) {
4949 | /* This must be after the first pass. */
4950 | prefix = "";
4951 | if (msp->last_frame == pinfo->num) {
4952 | col_clear(pinfo->cinfo, COL_INFO);
4953 | } else {
4954 | if (first_pdu) {
4955 | col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[SSH segment of a reassembled PDU]");
4956 | }
4957 | }
4958 | } else {
4959 | prefix = "Retransmitted ";
4960 | is_retransmission = true1;
4961 | }
4962 |
4963 | if (!is_retransmission) {
4964 | ipfd_head = fragment_get(&ssh_reassembly_table, pinfo, msp->first_frame, msp);
4965 | if (ipfd_head != NULL((void*)0) && ipfd_head->reassembled_in !=0 &&
4966 | ipfd_head->reassembled_in != pinfo->num) {
4967 | /* Show what frame this was reassembled in if not this one. */
4968 | item=proto_tree_add_uint(tree, *ssh_segment_items.hf_reassembled_in,
4969 | tvb, 0, 0, ipfd_head->reassembled_in);
4970 | proto_item_set_generated(item);
4971 | }
4972 | }
4973 | nbytes = tvb_reported_length_remaining(tvb, offset);
4974 | ssh_proto_tree_add_segment_data(tree, tvb, offset, nbytes, prefix);
4975 | return;
4976 | }
4977 |
4978 | /* Else, find the most previous PDU starting before this sequence number */
4979 | msp = (struct tcp_multisegment_pdu *)wmem_tree_lookup32_le(channel->multisegment_pdus, seq-1);
4980 | if (msp && msp->seq <= seq && msp->nxtpdu > seq) {
4981 | unsigned len;
4982 |
4983 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
4984 | msp->last_frame = pinfo->num;
4985 | msp->last_frame_time = pinfo->abs_ts;
4986 | }
4987 |
4988 | /* OK, this PDU was found, which means the segment continues
4989 | * a higher-level PDU and that we must desegment it.
4990 | */
4991 | if (msp->flags & MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001) {
4992 | /* The dissector asked for the entire segment */
4993 | len = tvb_reported_length_remaining(tvb, offset);
4994 | } else {
4995 | len = MIN(nxtseq, msp->nxtpdu)(((nxtseq) < (msp->nxtpdu)) ? (nxtseq) : (msp->nxtpdu )) - seq;
4996 | }
4997 |
4998 | ipfd_head = fragment_add(&ssh_reassembly_table, tvb, offset,
4999 | pinfo, ssh_msp_fragment_id(msp), msp,
5000 | seq - msp->seq,
5001 | len, (LT_SEQ (nxtseq,msp->nxtpdu)((int32_t)((nxtseq) - (msp->nxtpdu)) < 0)));
5002 |
5003 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)
5004 | && msp->flags & MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001) {
5005 | msp->flags &= (~MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001);
5006 |
5007 | /* If we consumed the entire segment there is no
5008 | * other pdu starting anywhere inside this segment.
5009 | * So update nxtpdu to point at least to the start
5010 | * of the next segment.
5011 | * (If the subdissector asks for even more data we
5012 | * will advance nxtpdu even further later down in
5013 | * the code.)
5014 | */
5015 | msp->nxtpdu = nxtseq;
5016 | }
5017 |
5018 | if ( (msp->nxtpdu < nxtseq)
5019 | && (msp->nxtpdu >= seq)
5020 | && (len > 0)) {
5021 | another_pdu_follows = msp->nxtpdu - seq;
5022 | }
5023 | } else {
5024 | /* This segment was not found in our table, so it doesn't
5025 | * contain a continuation of a higher-level PDU.
5026 | * Call the normal subdissector.
5027 | */
5028 | ssh_process_payload(tvb, offset, pinfo, tree, channel);
5029 | called_dissector = true1;
5030 |
5031 | /* Did the subdissector ask us to desegment some more data
5032 | * before it could handle the packet?
5033 | * If so we have to create some structures in our table but
5034 | * this is something we only do the first time we see this
5035 | * packet.
5036 | */
5037 | if (pinfo->desegment_len) {
5038 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))
5039 | must_desegment = true1;
5040 |
5041 | /*
5042 | * Set "deseg_offset" to the offset in "tvb"
5043 | * of the first byte of data that the
5044 | * subdissector didn't process.
5045 | */
5046 | deseg_offset = offset + pinfo->desegment_offset;
5047 | }
5048 |
5049 | /* Either no desegmentation is necessary, or this is
5050 | * segment contains the beginning but not the end of
5051 | * a higher-level PDU and thus isn't completely
5052 | * desegmented.
5053 | */
5054 | ipfd_head = NULL((void*)0);
5055 | }
5056 |
5057 | /* is it completely desegmented? */
5058 | if (ipfd_head && ipfd_head->reassembled_in == pinfo->num) {
5059 | /*
5060 | * Yes, we think it is.
5061 | * We only call subdissector for the last segment.
5062 | * Note that the last segment may include more than what
5063 | * we needed.
5064 | */
5065 | if (nxtseq < msp->nxtpdu) {
5066 | /*
5067 | * This is *not* the last segment. It is part of a PDU in the same
5068 | * frame, so no another PDU can follow this one.
5069 | * Do not reassemble SSH yet, it will be done in the final segment.
5070 | * (If we are reassembling at FIN, we will do that in dissect_ssl()
5071 | * after iterating through all the records.)
5072 | * Clear the Info column and avoid displaying [SSH segment of a
5073 | * reassembled PDU], the payload dissector will typically set it.
5074 | * (This is needed here for the second pass.)
5075 | */
5076 | another_pdu_follows = 0;
5077 | col_clear(pinfo->cinfo, COL_INFO);
5078 | another_segment_in_frame = true1;
5079 | } else {
5080 | /*
5081 | * OK, this is the last segment of the PDU and also the
5082 | * last segment in this frame.
5083 | * Let's call the subdissector with the desegmented
5084 | * data.
5085 | */
5086 | tvbuff_t *next_tvb;
5087 | int old_len;
5088 |
5089 | /*
5090 | * Reset column in case multiple SSH segments form the PDU
5091 | * and this last SSH segment is not in the first TCP segment of
5092 | * this frame.
5093 | * XXX prevent clearing the column if the last layer is not SSH?
5094 | */
5095 | /* Clear column during the first pass. */
5096 | col_clear(pinfo->cinfo, COL_INFO);
5097 |
5098 | /* create a new TVB structure for desegmented data */
5099 | next_tvb = tvb_new_chain(tvb, ipfd_head->tvb_data);
5100 |
5101 | /* add desegmented data to the data source list */
5102 | add_new_data_source(pinfo, next_tvb, "Reassembled SSH");
5103 |
5104 | /* call subdissector */
5105 | ssh_process_payload(next_tvb, 0, pinfo, tree, channel);
5106 | called_dissector = true1;
5107 |
5108 | /*
5109 | * OK, did the subdissector think it was completely
5110 | * desegmented, or does it think we need even more
5111 | * data?
5112 | */
5113 | old_len = (int)(tvb_reported_length(next_tvb) - tvb_reported_length_remaining(tvb, offset));
5114 | if (pinfo->desegment_len && pinfo->desegment_offset <= old_len) {
5115 | /*
5116 | * "desegment_len" isn't 0, so it needs more
5117 | * data for something - and "desegment_offset"
5118 | * is before "old_len", so it needs more data
5119 | * to dissect the stuff we thought was
5120 | * completely desegmented (as opposed to the
5121 | * stuff at the beginning being completely
5122 | * desegmented, but the stuff at the end
5123 | * being a new higher-level PDU that also
5124 | * needs desegmentation).
5125 | */
5126 | fragment_set_partial_reassembly(&ssh_reassembly_table,
5127 | pinfo, ssh_msp_fragment_id(msp), msp);
5128 | /* Update msp->nxtpdu to point to the new next
5129 | * pdu boundary.
5130 | */
5131 | if (pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT0x0fffffff) {
5132 | /* We want reassembly of at least one
5133 | * more segment so set the nxtpdu
5134 | * boundary to one byte into the next
5135 | * segment.
5136 | * This means that the next segment
5137 | * will complete reassembly even if it
5138 | * is only one single byte in length.
5139 | */
5140 | msp->nxtpdu = seq + tvb_reported_length_remaining(tvb, offset) + 1;
5141 | msp->flags |= MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001;
5142 | } else if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) {
5143 | /* This is not the first segment, and we thought reassembly
5144 | * would be done now, but now we know we desegment at FIN.
5145 | * E.g., a HTTP response where the headers were split
5146 | * across segments (so previous ONE_MORE_SEGMENT) and
5147 | * also no Content-Length (so now DESEGMENT_UNTIL_FIN).
5148 | */
5149 | channel->flags |= TCP_FLOW_REASSEMBLE_UNTIL_FIN0x0001;
5150 | msp->nxtpdu = nxtseq + 0x40000000;
5151 | } else {
5152 | msp->nxtpdu = seq + tvb_reported_length_remaining(tvb, offset) + pinfo->desegment_len;
5153 | }
5154 | /* Since we need at least some more data
5155 | * there can be no pdu following in the
5156 | * tail of this segment.
5157 | */
5158 | another_pdu_follows = 0;
5159 | } else {
5160 | /*
5161 | * Show the stuff in this TCP segment as
5162 | * just raw TCP segment data.
5163 | */
5164 | nbytes = another_pdu_follows > 0
5165 | ? another_pdu_follows
5166 | : tvb_reported_length_remaining(tvb, offset);
5167 | ssh_proto_tree_add_segment_data(tree, tvb, offset, nbytes, NULL((void*)0));
5168 |
5169 | /* Show details of the reassembly */
5170 | print_ssh_fragment_tree(ipfd_head, proto_tree_get_root(tree), tree, pinfo, next_tvb);
5171 |
5172 | /* Did the subdissector ask us to desegment
5173 | * some more data? This means that the data
5174 | * at the beginning of this segment completed
5175 | * a higher-level PDU, but the data at the
5176 | * end of this segment started a higher-level
5177 | * PDU but didn't complete it.
5178 | *
5179 | * If so, we have to create some structures
5180 | * in our table, but this is something we
5181 | * only do the first time we see this packet.
5182 | */
5183 | if (pinfo->desegment_len) {
5184 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))
5185 | must_desegment = true1;
5186 |
5187 | /* The stuff we couldn't dissect
5188 | * must have come from this segment,
5189 | * so it's all in "tvb".
5190 | *
5191 | * "pinfo->desegment_offset" is
5192 | * relative to the beginning of
5193 | * "next_tvb"; we want an offset
5194 | * relative to the beginning of "tvb".
5195 | *
5196 | * First, compute the offset relative
5197 | * to the *end* of "next_tvb" - i.e.,
5198 | * the number of bytes before the end
5199 | * of "next_tvb" at which the
5200 | * subdissector stopped. That's the
5201 | * length of "next_tvb" minus the
5202 | * offset, relative to the beginning
5203 | * of "next_tvb, at which the
5204 | * subdissector stopped.
5205 | */
5206 | deseg_offset = ipfd_head->datalen - pinfo->desegment_offset;
5207 |
5208 | /* "tvb" and "next_tvb" end at the
5209 | * same byte of data, so the offset
5210 | * relative to the end of "next_tvb"
5211 | * of the byte at which we stopped
5212 | * is also the offset relative to
5213 | * the end of "tvb" of the byte at
5214 | * which we stopped.
5215 | *
5216 | * Convert that back into an offset
5217 | * relative to the beginning of
5218 | * "tvb", by taking the length of
5219 | * "tvb" and subtracting the offset
5220 | * relative to the end.
5221 | */
5222 | deseg_offset = tvb_reported_length(tvb) - deseg_offset;
5223 | }
5224 | }
5225 | }
5226 | }
5227 |
5228 | if (must_desegment) {
5229 | /* If the dissector requested "reassemble until FIN"
5230 | * just set this flag for the flow and let reassembly
5231 | * proceed at normal. We will check/pick up these
5232 | * reassembled PDUs later down in dissect_tcp() when checking
5233 | * for the FIN flag.
5234 | */
5235 | if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) {
5236 | channel->flags |= TCP_FLOW_REASSEMBLE_UNTIL_FIN0x0001;
5237 | }
5238 | /*
5239 | * The sequence number at which the stuff to be desegmented
5240 | * starts is the sequence number of the byte at an offset
5241 | * of "deseg_offset" into "tvb".
5242 | *
5243 | * The sequence number of the byte at an offset of "offset"
5244 | * is "seq", i.e. the starting sequence number of this
5245 | * segment, so the sequence number of the byte at
5246 | * "deseg_offset" is "seq + (deseg_offset - offset)".
5247 | */
5248 | deseg_seq = seq + (deseg_offset - offset);
5249 |
5250 | if (((nxtseq - deseg_seq) <= 1024*1024)
5251 | && (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))) {
5252 | if (pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT0x0fffffff) {
5253 | /* The subdissector asked to reassemble using the
5254 | * entire next segment.
5255 | * Just ask reassembly for one more byte
5256 | * but set this msp flag so we can pick it up
5257 | * above.
5258 | */
5259 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
5260 | deseg_seq, nxtseq+1, channel->multisegment_pdus);
5261 | msp->flags |= MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001;
5262 | } else if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) {
5263 | /* Set nxtseq very large so that reassembly won't happen
5264 | * until we force it at the end of the stream in dissect_ssl()
5265 | * outside this function.
5266 | */
5267 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
5268 | deseg_seq, nxtseq+0x40000000, channel->multisegment_pdus);
5269 | } else {
5270 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo,
5271 | deseg_seq, nxtseq+pinfo->desegment_len, channel->multisegment_pdus);
5272 | }
5273 |
5274 | /* add this segment as the first one for this new pdu */
5275 | fragment_add(&ssh_reassembly_table, tvb, deseg_offset,
5276 | pinfo, ssh_msp_fragment_id(msp), msp,
5277 | 0, nxtseq - deseg_seq,
5278 | LT_SEQ(nxtseq, msp->nxtpdu)((int32_t)((nxtseq) - (msp->nxtpdu)) < 0));
5279 | }
5280 | }
5281 |
5282 | if (!called_dissector || pinfo->desegment_len != 0) {
5283 | if (ipfd_head != NULL((void*)0) && ipfd_head->reassembled_in != 0 &&
5284 | ipfd_head->reassembled_in != pinfo->num &&
5285 | !(ipfd_head->flags & FD_PARTIAL_REASSEMBLY0x0040)) {
5286 | /*
5287 | * We know what other frame this PDU is reassembled in;
5288 | * let the user know.
5289 | */
5290 | item=proto_tree_add_uint(tree, *ssh_segment_items.hf_reassembled_in,
5291 | tvb, 0, 0, ipfd_head->reassembled_in);
5292 | proto_item_set_generated(item);
5293 | }
5294 |
5295 | /*
5296 | * Either we didn't call the subdissector at all (i.e.,
5297 | * this is a segment that contains the middle of a
5298 | * higher-level PDU, but contains neither the beginning
5299 | * nor the end), or the subdissector couldn't dissect it
5300 | * all, as some data was missing (i.e., it set
5301 | * "pinfo->desegment_len" to the amount of additional
5302 | * data it needs).
5303 | */
5304 | if (!another_segment_in_frame && pinfo->desegment_offset == 0) {
5305 | /*
5306 | * It couldn't, in fact, dissect any of it (the
5307 | * first byte it couldn't dissect is at an offset
5308 | * of "pinfo->desegment_offset" from the beginning
5309 | * of the payload, and that's 0).
5310 | * Just mark this as SSH.
5311 | */
5312 |
5313 | /* SFTP checks the length before setting the protocol column.
5314 | * If other subdissectors don't do this, we'd want to set the
5315 | * protocol column back - but we want to get the SSH version
5316 | */
5317 | //col_set_str(pinfo->cinfo, COL_PROTOCOL,
5318 | // val_to_str_const(session->version, ssl_version_short_names, "SSH"));
5319 | if (first_pdu) {
5320 | col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[SSH segment of a reassembled PDU]");
5321 | }
5322 | }
5323 |
5324 | /*
5325 | * Show what's left in the packet as just raw SSH segment data.
5326 | * XXX - remember what protocol the last subdissector
5327 | * was, and report it as a continuation of that, instead?
5328 | */
5329 | nbytes = tvb_reported_length_remaining(tvb, deseg_offset);
5330 | ssh_proto_tree_add_segment_data(tree, tvb, deseg_offset, nbytes, NULL((void*)0));
5331 | }
5332 | pinfo->can_desegment = 0;
5333 | pinfo->desegment_offset = 0;
5334 | pinfo->desegment_len = 0;
5335 |
5336 | if (another_pdu_follows) {
5337 | /* there was another pdu following this one. */
5338 | pinfo->can_desegment=2;
5339 | /* we also have to prevent the dissector from changing the
5340 | * PROTOCOL and INFO colums since what follows may be an
5341 | * incomplete PDU and we don't want it be changed back from
5342 | * <Protocol> to <SSH>
5343 | */
5344 | col_set_fence(pinfo->cinfo, COL_INFO);
5345 | col_set_writable(pinfo->cinfo, COL_PROTOCOL, false0);
5346 | first_pdu = false0;
5347 | offset += another_pdu_follows;
5348 | seq += another_pdu_follows;
5349 | goto again;
5350 | }
5351 | }
5352 |
5353 | static void
5354 | ssh_dissect_channel_data(tvbuff_t *tvb, packet_info *pinfo,
5355 | struct ssh_peer_data *peer_data _U___attribute__((unused)), proto_tree *tree,
5356 | ssh_message_info_t *message _U___attribute__((unused)), ssh_channel_info_t *channel)
5357 | {
5358 |
5359 | uint16_t save_can_desegment = pinfo->can_desegment;
5360 |
5361 | if (ssh_desegment) {
5362 | pinfo->can_desegment = 2;
5363 | desegment_ssh(tvb, pinfo, message->byte_seq, message->next_byte_seq, tree, channel);
5364 | } else {
5365 | pinfo->can_desegment = 0;
5366 | bool_Bool save_fragmented = pinfo->fragmented;
5367 | pinfo->fragmented = true1;
5368 |
5369 | ssh_process_payload(tvb, 0, pinfo, tree, channel);
5370 | pinfo->fragmented = save_fragmented;
5371 | }
5372 |
5373 | pinfo->can_desegment = save_can_desegment;
5374 | }
5375 |
5376 | static int
5377 | ssh_dissect_term_modes(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree)
5378 | {
5379 | proto_item *ti;
5380 | proto_tree *term_mode_tree, *subtree;
5381 | unsigned offset = 0;
5382 | uint32_t opcode, value, idx;
5383 | bool_Bool boolval;
5384 |
5385 | struct tty_opt_info {
5386 | unsigned id;
5387 | int *hfindex;
5388 | };
5389 | static const struct tty_opt_info tty_opts[] = {
5390 | { SSH_TTY_OP_END0, NULL((void*)0)},
5391 | { SSH_TTY_OP_VINTR1, &hf_ssh_pty_term_mode_vintr },
5392 | { SSH_TTY_OP_VQUIT2, &hf_ssh_pty_term_mode_vquit },
5393 | { SSH_TTY_OP_VERASE3, &hf_ssh_pty_term_mode_verase },
5394 | { SSH_TTY_OP_VKILL4, &hf_ssh_pty_term_mode_vkill },
5395 | { SSH_TTY_OP_VEOF5, &hf_ssh_pty_term_mode_veof },
5396 | { SSH_TTY_OP_VEOL6, &hf_ssh_pty_term_mode_veol },
5397 | { SSH_TTY_OP_VEOL27, &hf_ssh_pty_term_mode_veol2 },
5398 | { SSH_TTY_OP_VSTART8, &hf_ssh_pty_term_mode_vstart },
5399 | { SSH_TTY_OP_VSTOP9, &hf_ssh_pty_term_mode_vstop },
5400 | { SSH_TTY_OP_VSUSP10, &hf_ssh_pty_term_mode_vsusp },
5401 | { SSH_TTY_OP_VDSUSP11, &hf_ssh_pty_term_mode_vdsusp },
5402 | { SSH_TTY_OP_VREPRINT12, &hf_ssh_pty_term_mode_vreprint },
5403 | { SSH_TTY_OP_VWERASE13, &hf_ssh_pty_term_mode_vwerase },
5404 | { SSH_TTY_OP_VLNEXT14, &hf_ssh_pty_term_mode_vlnext },
5405 | { SSH_TTY_OP_VFLUSH15, &hf_ssh_pty_term_mode_vflush },
5406 | { SSH_TTY_OP_VSWTCH16, &hf_ssh_pty_term_mode_vswtch },
5407 | { SSH_TTY_OP_VSTATUS17, &hf_ssh_pty_term_mode_vstatus },
5408 | { SSH_TTY_OP_VDISCARD18, &hf_ssh_pty_term_mode_vdiscard },
5409 | { SSH_TTY_OP_IGNPAR30, &hf_ssh_pty_term_mode_ignpar },
5410 | { SSH_TTY_OP_PARMRK31, &hf_ssh_pty_term_mode_parmrk },
5411 | { SSH_TTY_OP_INPCK32, &hf_ssh_pty_term_mode_inpck },
5412 | { SSH_TTY_OP_ISTRIP33, &hf_ssh_pty_term_mode_istrip },
5413 | { SSH_TTY_OP_INLCR34, &hf_ssh_pty_term_mode_inlcr },
5414 | { SSH_TTY_OP_IGNCR35, &hf_ssh_pty_term_mode_igncr },
5415 | { SSH_TTY_OP_ICRNL36, &hf_ssh_pty_term_mode_icrnl },
5416 | { SSH_TTY_OP_IUCLC37, &hf_ssh_pty_term_mode_iuclc },
5417 | { SSH_TTY_OP_IXON38, &hf_ssh_pty_term_mode_ixon },
5418 | { SSH_TTY_OP_IXANY39, &hf_ssh_pty_term_mode_ixany },
5419 | { SSH_TTY_OP_IXOFF40, &hf_ssh_pty_term_mode_ixoff },
5420 | { SSH_TTY_OP_IMAXBEL41, &hf_ssh_pty_term_mode_imaxbel },
5421 | { SSH_TTY_OP_IUTF842, &hf_ssh_pty_term_mode_iutf8 },
5422 | { SSH_TTY_OP_ISIG50, &hf_ssh_pty_term_mode_isig },
5423 | { SSH_TTY_OP_ICANON51, &hf_ssh_pty_term_mode_icanon },
5424 | { SSH_TTY_OP_XCASE52, &hf_ssh_pty_term_mode_xcase },
5425 | { SSH_TTY_OP_ECHO53, &hf_ssh_pty_term_mode_echo },
5426 | { SSH_TTY_OP_ECHOE54, &hf_ssh_pty_term_mode_echoe },
5427 | { SSH_TTY_OP_ECHOK55, &hf_ssh_pty_term_mode_echok },
5428 | { SSH_TTY_OP_ECHONL56, &hf_ssh_pty_term_mode_echonl },
5429 | { SSH_TTY_OP_NOFLSH57, &hf_ssh_pty_term_mode_noflsh },
5430 | { SSH_TTY_OP_TOSTOP58, &hf_ssh_pty_term_mode_tostop },
5431 | { SSH_TTY_OP_IEXTEN59, &hf_ssh_pty_term_mode_iexten },
5432 | { SSH_TTY_OP_ECHOCTL60, &hf_ssh_pty_term_mode_echoctl },
5433 | { SSH_TTY_OP_ECHOKE61, &hf_ssh_pty_term_mode_echoke },
5434 | { SSH_TTY_OP_PENDIN62, &hf_ssh_pty_term_mode_pendin },
5435 | { SSH_TTY_OP_OPOST70, &hf_ssh_pty_term_mode_opost },
5436 | { SSH_TTY_OP_OLCUC71, &hf_ssh_pty_term_mode_olcuc },
5437 | { SSH_TTY_OP_ONLCR72, &hf_ssh_pty_term_mode_onlcr },
5438 | { SSH_TTY_OP_OCRNL73, &hf_ssh_pty_term_mode_ocrnl },
5439 | { SSH_TTY_OP_ONOCR74, &hf_ssh_pty_term_mode_onocr },
5440 | { SSH_TTY_OP_ONLRET75, &hf_ssh_pty_term_mode_onlret },
5441 | { SSH_TTY_OP_CS790, &hf_ssh_pty_term_mode_cs7 },
5442 | { SSH_TTY_OP_CS891, &hf_ssh_pty_term_mode_cs8 },
5443 | { SSH_TTY_OP_PARENB92, &hf_ssh_pty_term_mode_parenb },
5444 | { SSH_TTY_OP_PARODD93, &hf_ssh_pty_term_mode_parodd },
5445 | { SSH_TTY_OP_ISPEED128, &hf_ssh_pty_term_mode_ispeed },
5446 | { SSH_TTY_OP_OSPEED129, &hf_ssh_pty_term_mode_ospeed }
5447 | };
5448 |
5449 | ti = proto_tree_add_item(tree, hf_ssh_pty_term_modes, tvb, offset, tvb_reported_length(tvb), ENC_NA0x00000000);
5450 | term_mode_tree = proto_item_add_subtree(ti, ett_term_modes);
5451 | while (tvb_reported_length_remaining(tvb, offset)) {
5452 | ti = proto_tree_add_item(term_mode_tree, hf_ssh_pty_term_mode, tvb, offset, 5, ENC_NA0x00000000);
5453 | subtree = proto_item_add_subtree(ti, ett_term_mode);
5454 | proto_tree_add_item_ret_uint(subtree, hf_ssh_pty_term_mode_opcode, tvb, offset, 1, ENC_NA0x00000000, &opcode);
5455 | proto_item_append_text(ti, ": %s", val_to_str_const(opcode, ssh_tty_op_vals, "Unknown"));
5456 | offset += 1;
5457 | if (opcode == SSH_TTY_OP_END0) {
5458 | break;
5459 | }
5460 | for (idx = 0; idx < array_length(tty_opts)(sizeof (tty_opts) / sizeof (tty_opts)[0]); idx++) {
5461 | if (tty_opts[idx].id == opcode) break;
5462 | }
5463 | if (idx >= array_length(tty_opts)(sizeof (tty_opts) / sizeof (tty_opts)[0])) {
5464 | proto_tree_add_item_ret_uint(subtree, hf_ssh_pty_term_mode_value, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &value);
5465 | proto_item_append_text(ti, "=%d", value);
5466 | } else {
5467 | DISSECTOR_ASSERT(tty_opts[idx].hfindex)((void) ((tty_opts[idx].hfindex) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 5467, "tty_opts[idx].hfindex"))));
5468 | int hfindex = *tty_opts[idx].hfindex;
5469 | switch (proto_registrar_get_ftype(hfindex)) {
5470 | case FT_BOOLEAN:
5471 | proto_tree_add_item_ret_boolean(subtree, hfindex, tvb, offset + 3, 1, ENC_NA0x00000000, &boolval);
5472 | proto_item_append_text(ti, "=%s", boolval ? "True" : "False");
5473 | break;
5474 | case FT_CHAR:
5475 | proto_tree_add_item_ret_uint(subtree, hfindex, tvb, offset + 3, 1, ENC_NA0x00000000, &value);
5476 | proto_item_append_text(ti, "='%s'", format_char(pinfo->pool, (char)value));
5477 | break;
5478 | case FT_UINT32:
5479 | proto_tree_add_item_ret_uint(subtree, hfindex, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &value);
5480 | proto_item_append_text(ti, "=%d", value);
5481 | break;
5482 | default:
5483 | DISSECTOR_ASSERT_NOT_REACHED()(proto_report_dissector_bug("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"" , "epan/dissectors/packet-ssh.c", 5483));
5484 | }
5485 | }
5486 | offset += 4;
5487 | }
5488 | return offset;
5489 | }
5490 |
5491 | static int
5492 | ssh_dissect_connection_specific(tvbuff_t *packet_tvb, packet_info *pinfo,
5493 | struct ssh_peer_data *peer_data, int offset, proto_tree *msg_type_tree,
5494 | unsigned msg_code, ssh_message_info_t *message)
5495 | {
5496 | uint32_t recipient_channel, sender_channel;
5497 |
5498 | if (msg_code == SSH_MSG_CHANNEL_OPEN90) {
5499 | uint32_t slen;
5500 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_type_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5501 | offset += 4;
5502 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_type_name, packet_tvb, offset, slen, ENC_UTF_80x00000002);
5503 | offset += slen;
5504 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_sender_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5505 | offset += 4;
5506 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_initial_window, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5507 | offset += 4;
5508 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_maximum_packet_size, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5509 | offset += 4;
5510 | } else if (msg_code == SSH_MSG_CHANNEL_OPEN_CONFIRMATION91) {
5511 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel);
5512 | offset += 4;
5513 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_sender_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &sender_channel);
5514 | offset += 4;
5515 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
5516 | create_channel(peer_data, recipient_channel, sender_channel);
5517 | }
5518 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_initial_window, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5519 | offset += 4;
5520 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_maximum_packet_size, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5521 | offset += 4;
5522 | } else if (msg_code == SSH_MSG_CHANNEL_WINDOW_ADJUST93) {
5523 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5524 | offset += 4;
5525 | proto_tree_add_item(msg_type_tree, hf_ssh_channel_window_adjust, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); // TODO: maintain count of transferred bytes and window size
5526 | offset += 4;
5527 | } else if (msg_code == SSH_MSG_CHANNEL_DATA94) {
5528 | proto_item* ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel);
5529 | offset += 4;
5530 | // TODO: process according to the type of channel
5531 | uint32_t slen;
5532 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_data_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5533 | offset += 4;
5534 | tvbuff_t* next_tvb = tvb_new_subset_length(packet_tvb, offset, slen);
5535 |
5536 | ssh_channel_info_t* channel = get_channel_info_for_channel(peer_data, recipient_channel);
5537 | if (channel) {
5538 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
5539 | message->byte_seq = channel->byte_seq;
5540 | channel->byte_seq += slen;
5541 | message->next_byte_seq = channel->byte_seq;
5542 | }
5543 | ssh_dissect_channel_data(next_tvb, pinfo, peer_data, msg_type_tree, message, channel);
5544 | } else {
5545 | expert_add_info_format(pinfo, ti, &ei_ssh_channel_number, "Could not find configuration for channel %d", recipient_channel);
5546 | }
5547 | offset += slen;
5548 | } else if (msg_code == SSH_MSG_CHANNEL_EXTENDED_DATA95) {
5549 | proto_item* ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel);
5550 | offset += 4;
5551 | // TODO: process according to the type of channel
5552 | proto_tree_add_item(msg_type_tree, hf_ssh_channel_data_type_code, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5553 | offset += 4;
5554 | uint32_t slen;
5555 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_data_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5556 | offset += 4;
5557 | tvbuff_t* next_tvb = tvb_new_subset_length(packet_tvb, offset, slen);
5558 |
5559 | ssh_channel_info_t* channel = get_channel_info_for_channel(peer_data, recipient_channel);
5560 | if (channel) {
5561 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) {
5562 | message->byte_seq = channel->byte_seq;
5563 | channel->byte_seq += slen;
5564 | message->next_byte_seq = channel->byte_seq;
5565 | }
5566 | ssh_dissect_channel_data(next_tvb, pinfo, peer_data, msg_type_tree, message, channel);
5567 | } else {
5568 | expert_add_info_format(pinfo, ti, &ei_ssh_channel_number, "Could not find configuration for channel %d", recipient_channel);
5569 | }
5570 | offset += slen;
5571 | } else if (msg_code == SSH_MSG_CHANNEL_EOF96) {
5572 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5573 | offset += 4;
5574 | } else if (msg_code == SSH_MSG_CHANNEL_CLOSE97) {
5575 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5576 | offset += 4;
5577 | } else if (msg_code == SSH_MSG_CHANNEL_REQUEST98) {
5578 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel);
5579 | offset += 4;
5580 | const char* request_name;
5581 | uint32_t slen;
5582 | int item_len;
5583 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_request_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5584 | offset += 4;
5585 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_channel_request_name, packet_tvb, offset, slen, ENC_UTF_80x00000002, pinfo->pool, (const uint8_t**)&request_name);
5586 | offset += slen;
5587 | proto_tree_add_item(msg_type_tree, hf_ssh_channel_request_want_reply, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
5588 | offset += 1;
5589 | /* RFC 4254 6.5: "Only one of these requests ["shell", "exec",
5590 | * or "subsystem"] can succeed per channel." Set up the
5591 | * appropriate handler for future CHANNEL_DATA and
5592 | * CHANNEL_EXTENDED_DATA messages on the channel.
5593 | *
5594 | * XXX - For "shell" and "exec", it might make more sense to send
5595 | * CHANNEL_DATA to the "data-text-lines" dissector rather than "data".
5596 | * Ideally if a pty has been setup there would be a way to interpret
5597 | * the escape codes.
5598 | */
5599 | if (0 == strcmp(request_name, "subsystem")) {
5600 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_subsystem_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5601 | offset += 4;
5602 | const char* subsystem_name;
5603 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_subsystem_name, packet_tvb, offset, slen, ENC_UTF_80x00000002, pinfo->pool, (const uint8_t**)&subsystem_name);
5604 | set_subdissector_for_channel(peer_data, recipient_channel, subsystem_name);
5605 | offset += slen;
5606 | } else if (0 == strcmp(request_name, "env")) {
5607 | /* The encoding for "env" variables and "exec" commands is not
5608 | * specified in the SSH protocol, and must match whatever the
5609 | * server expects. (Unlike CHANNEL_DATA, it is not affected by
5610 | * whatever is in "env" or anything else in the protocol, and the
5611 | * strings are passed to execve directly.) In practice the strings
5612 | * must not have internal NULs (no UTF-16), and OpenSSH for Windows
5613 | * and IBM z/OS force the use of UTF-8 and ISO-8859-1, respectively.
5614 | *
5615 | * These will probably be ASCII-compatible.
5616 | */
5617 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_env_name, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &item_len);
5618 | offset += item_len;
5619 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_env_value, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &item_len);
5620 | offset += item_len;
5621 | } else if (0 == strcmp(request_name, "exec")) {
5622 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_exec_cmd, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &item_len);
5623 | offset += item_len;
5624 | set_subdissector_for_channel(peer_data, recipient_channel, "exec");
5625 | } else if (0 == strcmp(request_name, "exit-status")) {
5626 | proto_tree_add_item(msg_type_tree, hf_ssh_exit_status, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5627 | offset += 4;
5628 | } else if (0 == strcmp(request_name, "shell")) {
5629 | set_subdissector_for_channel(peer_data, recipient_channel, "shell");
5630 | } else if (0 == strcmp(request_name, "pty-req")) {
5631 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_pty_term, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &item_len);
5632 | offset += item_len;
5633 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_width_char, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5634 | offset += 4;
5635 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_height_row, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5636 | offset += 4;
5637 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_width_pixel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5638 | offset += 4;
5639 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_height_pixel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5640 | offset += 4;
5641 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_pty_term_modes_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5642 | offset += 4;
5643 | offset += ssh_dissect_term_modes(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree);
5644 | }
5645 | } else if (msg_code == SSH_MSG_CHANNEL_SUCCESS99) {
5646 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5647 | offset += 4;
5648 | }
5649 | return offset;
5650 | }
5651 |
5652 | /* Channel mapping {{{ */
5653 |
5654 | /* The usual flow:
5655 | * 1. client sends SSH_MSG_CHANNEL_OPEN with its (sender) channel number
5656 | * 2. server responds with SSH_MSG_CHANNEL_OPEN_CONFIRMATION with
5657 | * its channel number and echoing the client's number, creating
5658 | * a bijective map
5659 | * 3. client sends SSH_MSG_CHANNEL_REQUEST which has the name of
5660 | * the shell, command, or subsystem to start. This has the recipient's
5661 | * channel number (i.e. the server's)
5662 | * 4. server may send back a SSG_MSG_CHANNEL_SUCCESS (or _FAILURE) with
5663 | * the the recipient (i.e., client) channel number, but this does not
5664 | * contain the subsystem name or anything identifying the request to
5665 | * which it responds. It MUST be sent in the same order as the
5666 | * corresponding request message (RFC 4254 4 Global Requests), so we
5667 | * could track it that way, but for our purposes we just treat all
5668 | * requests as successes. (If not, either there won't be data or another
5669 | * request will supercede it later.)
5670 | *
5671 | * Either side can open a channel (RFC 4254 5 Channel Mechanism). The
5672 | * typical flow is the client opening a channel, but in the case of
5673 | * remote port forwarding (7 TCP/IP Port Forwarding) the directions are
5674 | * swapped. For port forwarding, all the information is contained in the
5675 | * SSH_MSG_CHANNEL_OPEN, there is no SSH_MSG_CHANNEL_REQUEST.
5676 | *
5677 | * XXX: Channel numbers can be re-used after being closed (5.3 Closing a
5678 | * Channel), but not necessarily mapped to the same channel number on the
5679 | * other side. If that actually happens, the right way to handle this is
5680 | * to track the state changes over time for random packet access (e.g.,
5681 | * using a multimap with the packet number instead of maps.)
5682 | */
5683 |
5684 | static struct ssh_peer_data*
5685 | get_other_peer_data(struct ssh_peer_data *peer_data)
5686 | {
5687 | bool_Bool is_server = &peer_data->global_data->peer_data[SERVER_PEER_DATA1]==peer_data;
5688 | if (is_server) {
5689 | return &peer_data->global_data->peer_data[CLIENT_PEER_DATA0];
5690 | } else {
5691 | return &peer_data->global_data->peer_data[SERVER_PEER_DATA1];
5692 | }
5693 | }
5694 |
5695 | /* Create pairings between a recipient channel and the sender's channel,
5696 | * from a SSH_MSG_CHANNEL_OPEN_CONFIRMATION. */
5697 | static void
5698 | create_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, uint32_t sender_channel)
5699 | {
5700 | if (peer_data->channel_info == NULL((void*)0)) {
5701 | peer_data->channel_info = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
5702 | }
5703 | wmem_map_insert(peer_data->channel_info, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel)), GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)));
5704 |
5705 | if (peer_data->channel_handles == NULL((void*)0)) {
5706 | peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
5707 | }
5708 |
5709 | ssh_channel_info_t *new_channel = wmem_new0(wmem_file_scope(), ssh_channel_info_t)((ssh_channel_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_channel_info_t)));
5710 | new_channel->multisegment_pdus = wmem_tree_new(wmem_file_scope());
5711 | wmem_map_insert(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), new_channel);
5712 |
5713 | /* If the recipient channel is already configured in the other direction,
5714 | * set the handle. We need this if we eventually handle port forwarding,
5715 | * where all the information to handle the traffic is sent in the
5716 | * SSH_MSG_CHANNEL_OPEN message before the CONFIRMATION. It might also
5717 | * help if the packets are out of order (i.e. we get the client
5718 | * CHANNEL_REQUEST before the CHANNEL_OPEN_CONFIRMATION.)
5719 | */
5720 | struct ssh_peer_data *other_peer_data = get_other_peer_data(peer_data);
5721 | if (other_peer_data->channel_handles) {
5722 | ssh_channel_info_t *peer_channel = wmem_map_lookup(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel)));
5723 | if (peer_channel) {
5724 | new_channel->handle = peer_channel->handle;
5725 | }
5726 | }
5727 | }
5728 |
5729 | static ssh_channel_info_t*
5730 | get_channel_info_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel)
5731 | {
5732 | if (peer_data->channel_handles == NULL((void*)0)) {
5733 | return NULL((void*)0);
5734 | }
5735 | ssh_channel_info_t *channel = wmem_map_lookup(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)));
5736 |
5737 | return channel;
5738 | }
5739 |
5740 | static void
5741 | set_subdissector_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, const char* subsystem_name)
5742 | {
5743 | dissector_handle_t handle = NULL((void*)0);
5744 | if (0 == strcmp(subsystem_name, "sftp")) {
5745 | handle = sftp_handle;
5746 | } else if (0 == strcmp(subsystem_name, "shell") ||
5747 | 0 == strcmp(subsystem_name, "exec")) {
5748 | handle = data_text_lines_handle;
5749 | }
5750 |
5751 | if (handle) {
5752 | /* Map this handle to the recipient channel */
5753 | ssh_channel_info_t *channel = NULL((void*)0);
5754 | if (peer_data->channel_handles == NULL((void*)0)) {
5755 | peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
5756 | } else {
5757 | channel = wmem_map_lookup(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)));
5758 | }
5759 | if (channel == NULL((void*)0)) {
5760 | channel = wmem_new0(wmem_file_scope(), ssh_channel_info_t)((ssh_channel_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_channel_info_t)));
5761 | channel->multisegment_pdus = wmem_tree_new(wmem_file_scope());
5762 | wmem_map_insert(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), channel);
5763 | }
5764 | channel->handle = handle;
5765 |
5766 | /* This recipient channel is the sender channel for the other side.
5767 | * Do we know what the recipient channel on the other side is? */
5768 | struct ssh_peer_data *other_peer_data = get_other_peer_data(peer_data);
5769 |
5770 | wmem_map_t *channel_info = other_peer_data->channel_info;
5771 | if (channel_info) {
5772 | void *sender_channel_p;
5773 | if (wmem_map_lookup_extended(channel_info, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), NULL((void*)0), &sender_channel_p)) {
5774 | uint32_t sender_channel = GPOINTER_TO_UINT(sender_channel_p)((guint) (gulong) (sender_channel_p));
5775 | /* Yes. See the handle for the other side too. */
5776 | if (other_peer_data->channel_handles == NULL((void*)0)) {
5777 | other_peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
5778 | channel = NULL((void*)0);
5779 | } else {
5780 | channel = wmem_map_lookup(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel)));
5781 | }
5782 | if (channel == NULL((void*)0)) {
5783 | channel = wmem_new0(wmem_file_scope(), ssh_channel_info_t)((ssh_channel_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_channel_info_t)));
5784 | channel->multisegment_pdus = wmem_tree_new(wmem_file_scope());
5785 | wmem_map_insert(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel)), channel);
5786 | }
5787 | channel->handle = handle;
5788 | }
5789 | }
5790 | }
5791 | }
5792 |
5793 | /* Channel mapping. }}} */
5794 |
5795 | static int
5796 | ssh_dissect_connection_generic(tvbuff_t *packet_tvb, packet_info *pinfo,
5797 | int offset, proto_item *msg_type_tree, unsigned msg_code)
5798 | {
5799 | (void)pinfo;
5800 | if(msg_code==SSH_MSG_GLOBAL_REQUEST80){
5801 | const char* request_name;
5802 | unsigned slen;
5803 | slen = tvb_get_ntohl(packet_tvb, offset) ;
5804 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5805 | offset += 4;
5806 | request_name = (char*)tvb_get_string_enc(pinfo->pool, packet_tvb, offset, slen, ENC_ASCII0x00000000|ENC_NA0x00000000);
5807 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
5808 | offset += slen;
5809 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_want_reply, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
5810 | offset += 1;
5811 | if (0 == strcmp(request_name, "hostkeys-00@openssh.com") ||
5812 | 0 == strcmp(request_name, "hostkeys-prove-00@openssh.com")) {
5813 | while (tvb_reported_length_remaining(packet_tvb, offset)) {
5814 | offset += ssh_tree_add_hostkey(packet_tvb, pinfo, offset, msg_type_tree,
5815 | "Server host key", ett_key_exchange_host_key, NULL((void*)0));
5816 | }
5817 | }
5818 | }
5819 | return offset;
5820 | }
5821 |
5822 | static int
5823 | ssh_dissect_local_extension(tvbuff_t *packet_tvb, packet_info *pinfo,
5824 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code) {
5825 | unsigned slen;
5826 | if (peer_data->global_data->ext_ping_openssh_offered && msg_code >= SSH_MSG_PING192 && msg_code <= SSH_MSG_PONG193) {
5827 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_ext_ping_msg_vals, "Unknown (%u)"));
5828 | proto_tree_add_item(msg_type_tree, hf_ssh2_ext_ping_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
5829 | offset += 1;
5830 | if (msg_code == SSH_MSG_PING192) {
5831 | slen = tvb_get_ntohl(packet_tvb, offset) ;
5832 | proto_tree_add_item(msg_type_tree, hf_ssh_ping_data_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5833 | offset += 4;
5834 | proto_tree_add_item(msg_type_tree, hf_ssh_ping_data, packet_tvb, offset, slen, ENC_NA0x00000000);
5835 | offset += slen;
5836 | } else if (msg_code == SSH_MSG_PONG193) {
5837 | slen = tvb_get_ntohl(packet_tvb, offset) ;
5838 | proto_tree_add_item(msg_type_tree, hf_ssh_pong_data_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5839 | offset += 4;
5840 | proto_tree_add_item(msg_type_tree, hf_ssh_pong_data, packet_tvb, offset, slen, ENC_NA0x00000000);
5841 | offset += slen;
5842 | }
5843 | } else {
5844 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(pinfo->pool, msg_code, ssh2_msg_vals, "Unknown (%u)"));
5845 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000);
5846 | offset += 1;
5847 | }
5848 | return offset;
5849 | }
5850 |
5851 | static int
5852 | ssh_dissect_public_key_blob(tvbuff_t *tvb, packet_info *pinfo, proto_item *tree)
5853 | {
5854 | uint32_t slen;
5855 | const char* key_type;
5856 |
5857 | unsigned offset = 0;
5858 | proto_tree *blob_tree = NULL((void*)0);
5859 | proto_item *blob_item = NULL((void*)0);
5860 |
5861 | blob_item = proto_tree_add_item(tree, hf_ssh_blob, tvb, offset, tvb_reported_length(tvb), ENC_NA0x00000000);
5862 | blob_tree = proto_item_add_subtree(blob_item, ett_userauth_pk_blob);
5863 | proto_tree_add_item_ret_uint(blob_tree, hf_ssh_pk_blob_name_length, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen);
5864 | offset += 4;
5865 | proto_tree_add_item_ret_string(blob_tree, hf_ssh_pk_blob_name, tvb, offset, slen, ENC_ASCII0x00000000, pinfo->pool, (const uint8_t**)&key_type);
5866 | proto_item_append_text(blob_item, " (type: %s)", key_type);
5867 | offset += slen;
5868 |
5869 | if (0 == strcmp(key_type, "ssh-rsa")) {
5870 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_e);
5871 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_n);
5872 | } else if (0 == strcmp(key_type, "ssh-dss")) {
5873 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_p);
5874 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_q);
5875 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_g);
5876 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_y);
5877 | } else if (g_str_has_prefix(key_type, "ecdsa-sha2-")(__builtin_constant_p ("ecdsa-sha2-")? __extension__ ({ const char * const __str = (key_type); const char * const __prefix = ("ecdsa-sha2-"); gboolean __result = (0); if (__str == ((void *)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix); else { const size_t __str_len = strlen (( (__str) + !(__str))); const size_t __prefix_len = strlen (((__prefix ) + !(__prefix))); if (__str_len >= __prefix_len) __result = memcmp (((__str) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len ) == 0; } __result; }) : (g_str_has_prefix) (key_type, "ecdsa-sha2-" ) )) {
5878 | offset += ssh_tree_add_string(tvb, offset, blob_tree,
5879 | hf_ssh_blob_ecdsa_curve_id, hf_ssh_blob_ecdsa_curve_id_length);
5880 | offset += ssh_tree_add_string(tvb, offset, blob_tree,
5881 | hf_ssh_blob_ecdsa_q, hf_ssh_blob_ecdsa_q_length);
5882 | } else if (g_str_has_prefix(key_type, "ssh-ed")(__builtin_constant_p ("ssh-ed")? __extension__ ({ const char * const __str = (key_type); const char * const __prefix = ("ssh-ed" ); gboolean __result = (0); if (__str == ((void*)0) || __prefix == ((void*)0)) __result = (g_str_has_prefix) (__str, __prefix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __prefix_len = strlen (((__prefix) + !(__prefix ))); if (__str_len >= __prefix_len) __result = memcmp (((__str ) + !(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0 ; } __result; }) : (g_str_has_prefix) (key_type, "ssh-ed") )) {
5883 | offset += ssh_tree_add_string(tvb, offset, blob_tree,
5884 | hf_ssh_blob_eddsa_key, hf_ssh_blob_eddsa_key_length);
5885 | } else {
5886 | proto_tree_add_item(blob_tree, hf_ssh_blob_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA0x00000000);
5887 | offset += tvb_reported_length_remaining(tvb, offset);
5888 | }
5889 |
5890 | return offset;
5891 | }
5892 |
5893 | static int
5894 | ssh_dissect_public_key_signature(tvbuff_t *packet_tvb, packet_info *pinfo,
5895 | int offset, proto_item *msg_type_tree)
5896 | {
5897 | (void)pinfo;
5898 | unsigned slen;
5899 | slen = tvb_get_ntohl(packet_tvb, offset) ;
5900 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_blob_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5901 | offset += 4;
5902 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_blob_name, packet_tvb, offset, slen, ENC_ASCII0x00000000);
5903 | offset += slen;
5904 | slen = tvb_get_ntohl(packet_tvb, offset) ;
5905 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_s_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000);
5906 | offset += 4;
5907 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_s, packet_tvb, offset, slen, ENC_NA0x00000000);
5908 | offset += slen;
5909 | return offset;
5910 | }
5911 |
5912 | #ifdef SSH_DECRYPT_DEBUG /* {{{ */
5913 |
5914 | static FILE* ssh_debug_file;
5915 |
5916 | static void
5917 | ssh_prefs_apply_cb(void)
5918 | {
5919 | ssh_set_debug(ssh_debug_file_name);
5920 | }
5921 |
5922 | static void
5923 | ssh_set_debug(const char* name)
5924 | {
5925 | static int debug_file_must_be_closed;
5926 | int use_stderr;
5927 |
5928 | use_stderr = name?(strcmp(name, SSH_DEBUG_USE_STDERR"-") == 0):0;
5929 |
5930 | if (debug_file_must_be_closed)
5931 | fclose(ssh_debug_file);
5932 |
5933 | if (use_stderr)
5934 | ssh_debug_file = stderrstderr;
5935 | else if (!name || (strcmp(name, "") ==0))
5936 | ssh_debug_file = NULL((void*)0);
5937 | else
5938 | ssh_debug_file = ws_fopenfopen(name, "w");
5939 |
5940 | if (!use_stderr && ssh_debug_file)
5941 | debug_file_must_be_closed = 1;
5942 | else
5943 | debug_file_must_be_closed = 0;
5944 |
5945 | ssh_debug_printf("Wireshark SSH debug log \n\n");
5946 | #ifdef HAVE_LIBGNUTLS1
5947 | ssh_debug_printf("GnuTLS version: %s\n", gnutls_check_version(NULL((void*)0)));
5948 | #endif
5949 | ssh_debug_printf("Libgcrypt version: %s\n", gcry_check_version(NULL((void*)0)));
5950 | ssh_debug_printf("\n");
5951 | }
5952 |
5953 | static void
5954 | ssh_debug_flush(void)
5955 | {
5956 | if (ssh_debug_file)
5957 | fflush(ssh_debug_file);
5958 | }
5959 |
5960 | static void
5961 | ssh_debug_printf(const char* fmt, ...)
5962 | {
5963 | va_list ap;
5964 |
5965 | if (!ssh_debug_file)
5966 | return;
5967 |
5968 | va_start(ap, fmt)__builtin_va_start(ap, fmt);
5969 | vfprintf(ssh_debug_file, fmt, ap);
5970 | va_end(ap)__builtin_va_end(ap);
5971 | }
5972 |
5973 | static void
5974 | ssh_print_data(const char* name, const unsigned char* data, size_t len)
5975 | {
5976 | size_t i, j, k;
5977 | if (!ssh_debug_file)
5978 | return;
5979 | #ifdef OPENSSH_STYLE
5980 | fprintf(ssh_debug_file,"%s[%d]\n",name, (int) len);
5981 | #else
5982 | fprintf(ssh_debug_file,"%s[%d]:\n",name, (int) len);
5983 | #endif
5984 | for (i=0; i<len; i+=16) {
5985 | #ifdef OPENSSH_STYLE
5986 | fprintf(ssh_debug_file,"%04u: ", (unsigned int)i);
5987 | #else
5988 | fprintf(ssh_debug_file,"| ");
5989 | #endif
5990 | for (j=i, k=0; k<16 && j<len; ++j, ++k)
5991 | fprintf(ssh_debug_file,"%.2x ",data[j]);
5992 | for (; k<16; ++k)
5993 | fprintf(ssh_debug_file," ");
5994 | #ifdef OPENSSH_STYLE
5995 | fputc(' ', ssh_debug_file);
5996 | #else
5997 | fputc('|', ssh_debug_file);
5998 | #endif
5999 | for (j=i, k=0; k<16 && j<len; ++j, ++k) {
6000 | unsigned char c = data[j];
6001 | if (!g_ascii_isprint(c)((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0) || (c=='\t')) c = '.';
6002 | fputc(c, ssh_debug_file);
6003 | }
6004 | #ifdef OPENSSH_STYLE
6005 | fprintf(ssh_debug_file,"\n");
6006 | #else
6007 | for (; k<16; ++k)
6008 | fputc(' ', ssh_debug_file);
6009 | fprintf(ssh_debug_file,"|\n");
6010 | #endif
6011 | }
6012 | }
6013 |
6014 | #endif /* SSH_DECRYPT_DEBUG }}} */
6015 |
6016 | static void
6017 | ssh_secrets_block_callback(const void *secrets, unsigned size)
6018 | {
6019 | ssh_keylog_process_lines((const uint8_t *)secrets, size);
6020 | }
6021 |
6022 | /* Functions for SSH random hashtables. {{{ */
6023 | static int
6024 | ssh_equal (const void *v, const void *v2)
6025 | {
6026 | if (v == NULL((void*)0) || v2 == NULL((void*)0)) {
6027 | return 0;
6028 | }
6029 |
6030 | const ssh_bignum *val1;
6031 | const ssh_bignum *val2;
6032 | val1 = (const ssh_bignum *)v;
6033 | val2 = (const ssh_bignum *)v2;
6034 |
6035 | if (val1->length == val2->length &&
6036 | !memcmp(val1->data, val2->data, val2->length)) {
6037 | return 1;
6038 | }
6039 | return 0;
6040 | }
6041 |
6042 | static unsigned
6043 | ssh_hash (const void *v)
6044 | {
6045 | unsigned l,hash;
6046 | const ssh_bignum* id;
6047 | const unsigned* cur;
6048 |
6049 | if (v == NULL((void*)0)) {
6050 | return 0;
6051 | }
6052 |
6053 | hash = 0;
6054 | id = (const ssh_bignum*) v;
6055 |
6056 | /* id and id->data are mallocated in ssh_save_master_key(). As such 'data'
6057 | * should be aligned for any kind of access (for example as a unsigned as
6058 | * is done below). The intermediate void* cast is to prevent "cast
6059 | * increases required alignment of target type" warnings on CPUs (such
6060 | * as SPARCs) that do not allow misaligned memory accesses.
6061 | */
6062 | cur = (const unsigned*)(void*) id->data;
6063 |
6064 | for (l=4; (l < id->length); l+=4, cur++)
6065 | hash = hash ^ (*cur);
6066 |
6067 | return hash;
6068 | }
6069 |
6070 | static void
6071 | ssh_free_glib_allocated_bignum(void *data)
6072 | {
6073 | ssh_bignum * bignum;
6074 | if (data == NULL((void*)0)) {
6075 | return;
6076 | }
6077 |
6078 | bignum = (ssh_bignum *) data;
6079 | g_free(bignum->data)(__builtin_object_size ((bignum->data), 0) != ((size_t) - 1 )) ? g_free_sized (bignum->data, __builtin_object_size ((bignum ->data), 0)) : (g_free) (bignum->data);
6080 | g_free(bignum)(__builtin_object_size ((bignum), 0) != ((size_t) - 1)) ? g_free_sized (bignum, __builtin_object_size ((bignum), 0)) : (g_free) (bignum );
6081 | }
6082 |
6083 | static void
6084 | ssh_free_glib_allocated_entry(void *data)
6085 | {
6086 | ssh_key_map_entry_t * entry;
6087 | if (data == NULL((void*)0)) {
6088 | return;
6089 | }
6090 |
6091 | entry = (ssh_key_map_entry_t *) data;
6092 | g_free(entry->type)(__builtin_object_size ((entry->type), 0) != ((size_t) - 1 )) ? g_free_sized (entry->type, __builtin_object_size ((entry ->type), 0)) : (g_free) (entry->type);
6093 | ssh_free_glib_allocated_bignum(entry->key_material);
6094 | g_free(entry)(__builtin_object_size ((entry), 0) != ((size_t) - 1)) ? g_free_sized (entry, __builtin_object_size ((entry), 0)) : (g_free) (entry );
6095 | }
6096 | /* Functions for SSH random hashtables. }}} */
6097 |
6098 | static void
6099 | ssh_shutdown(void) {
6100 | g_hash_table_destroy(ssh_master_key_map);
6101 | }
6102 |
6103 | void
6104 | proto_register_ssh(void)
6105 | {
6106 | static hf_register_info hf[] = {
6107 | { &hf_ssh_protocol,
6108 | { "Protocol", "ssh.protocol",
6109 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6110 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6111 |
6112 | { &hf_ssh_packet_length,
6113 | { "Packet Length", "ssh.packet_length",
6114 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6115 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6116 |
6117 | { &hf_ssh_packet_length_encrypted,
6118 | { "Packet Length (encrypted)", "ssh.packet_length_encrypted",
6119 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6120 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6121 |
6122 | { &hf_ssh_padding_length,
6123 | { "Padding Length", "ssh.padding_length",
6124 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
6125 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6126 |
6127 | { &hf_ssh_payload,
6128 | { "Payload", "ssh.payload",
6129 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6130 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6131 |
6132 | { &hf_ssh_encrypted_packet,
6133 | { "Encrypted Packet", "ssh.encrypted_packet",
6134 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6135 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6136 |
6137 | { &hf_ssh_padding_string,
6138 | { "Padding String", "ssh.padding_string",
6139 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6140 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6141 |
6142 | { &hf_ssh_seq_num,
6143 | { "Sequence number", "ssh.seq_num",
6144 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6145 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6146 |
6147 | { &hf_ssh_mac_string,
6148 | { "MAC", "ssh.mac",
6149 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6150 | "Message authentication code", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6151 |
6152 | { &hf_ssh_mac_status,
6153 | { "MAC Status", "ssh.mac.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals)((0 ? (const struct _value_string*)0 : ((proto_checksum_vals) ))), 0x0,
6154 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6155 |
6156 | { &hf_ssh_direction,
6157 | { "Direction", "ssh.direction",
6158 | FT_BOOLEAN, BASE_NONE, TFS(&tfs_s2c_c2s)((0 ? (const struct true_false_string*)0 : ((&tfs_s2c_c2s )))), 0x0,
6159 | "Message direction", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6160 |
6161 | { &hf_ssh_msg_code,
6162 | { "Message Code", "ssh.message_code",
6163 | FT_UINT8, BASE_DEC, VALS(ssh1_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh1_msg_vals)))), 0x0,
6164 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6165 |
6166 | { &hf_ssh2_msg_code,
6167 | { "Message Code", "ssh.message_code",
6168 | FT_UINT8, BASE_DEC, VALS(ssh2_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_msg_vals)))), 0x0,
6169 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6170 |
6171 | { &hf_ssh2_kex_dh_msg_code,
6172 | { "Message Code", "ssh.message_code",
6173 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_dh_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_dh_msg_vals )))), 0x0,
6174 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6175 |
6176 | { &hf_ssh2_kex_dh_gex_msg_code,
6177 | { "Message Code", "ssh.message_code",
6178 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_dh_gex_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_dh_gex_msg_vals )))), 0x0,
6179 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6180 |
6181 | { &hf_ssh2_kex_ecdh_msg_code,
6182 | { "Message Code", "ssh.message_code",
6183 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_ecdh_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_ecdh_msg_vals )))), 0x0,
6184 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6185 |
6186 | { &hf_ssh2_kex_hybrid_msg_code,
6187 | { "Message Code", "ssh.message_code",
6188 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_hybrid_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_hybrid_msg_vals )))), 0x0,
6189 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6190 |
6191 | { &hf_ssh2_ext_ping_msg_code,
6192 | { "Message Code", "ssh.message_code",
6193 | FT_UINT8, BASE_DEC, VALS(ssh2_ext_ping_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_ext_ping_msg_vals )))), 0x0,
6194 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6195 |
6196 | { &hf_ssh_cookie,
6197 | { "Cookie", "ssh.cookie",
6198 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6199 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6200 |
6201 | { &hf_ssh_kex_algorithms,
6202 | { "kex_algorithms string", "ssh.kex_algorithms",
6203 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6204 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6205 |
6206 | { &hf_ssh_server_host_key_algorithms,
6207 | { "server_host_key_algorithms string", "ssh.server_host_key_algorithms",
6208 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6209 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6210 |
6211 | { &hf_ssh_encryption_algorithms_client_to_server,
6212 | { "encryption_algorithms_client_to_server string", "ssh.encryption_algorithms_client_to_server",
6213 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6214 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6215 |
6216 | { &hf_ssh_encryption_algorithms_server_to_client,
6217 | { "encryption_algorithms_server_to_client string", "ssh.encryption_algorithms_server_to_client",
6218 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6219 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6220 |
6221 | { &hf_ssh_mac_algorithms_client_to_server,
6222 | { "mac_algorithms_client_to_server string", "ssh.mac_algorithms_client_to_server",
6223 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6224 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6225 |
6226 | { &hf_ssh_mac_algorithms_server_to_client,
6227 | { "mac_algorithms_server_to_client string", "ssh.mac_algorithms_server_to_client",
6228 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6229 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6230 |
6231 | { &hf_ssh_compression_algorithms_client_to_server,
6232 | { "compression_algorithms_client_to_server string", "ssh.compression_algorithms_client_to_server",
6233 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6234 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6235 |
6236 | { &hf_ssh_compression_algorithms_server_to_client,
6237 | { "compression_algorithms_server_to_client string", "ssh.compression_algorithms_server_to_client",
6238 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6239 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6240 |
6241 | { &hf_ssh_languages_client_to_server,
6242 | { "languages_client_to_server string", "ssh.languages_client_to_server",
6243 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6244 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6245 |
6246 | { &hf_ssh_languages_server_to_client,
6247 | { "languages_server_to_client string", "ssh.languages_server_to_client",
6248 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6249 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6250 |
6251 | { &hf_ssh_kex_algorithms_length,
6252 | { "kex_algorithms length", "ssh.kex_algorithms_length",
6253 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6254 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6255 |
6256 | { &hf_ssh_server_host_key_algorithms_length,
6257 | { "server_host_key_algorithms length", "ssh.server_host_key_algorithms_length",
6258 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6259 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6260 |
6261 | { &hf_ssh_encryption_algorithms_client_to_server_length,
6262 | { "encryption_algorithms_client_to_server length", "ssh.encryption_algorithms_client_to_server_length",
6263 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6264 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6265 |
6266 | { &hf_ssh_encryption_algorithms_server_to_client_length,
6267 | { "encryption_algorithms_server_to_client length", "ssh.encryption_algorithms_server_to_client_length",
6268 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6269 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6270 |
6271 | { &hf_ssh_mac_algorithms_client_to_server_length,
6272 | { "mac_algorithms_client_to_server length", "ssh.mac_algorithms_client_to_server_length",
6273 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6274 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6275 |
6276 | { &hf_ssh_mac_algorithms_server_to_client_length,
6277 | { "mac_algorithms_server_to_client length", "ssh.mac_algorithms_server_to_client_length",
6278 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6279 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6280 |
6281 | { &hf_ssh_compression_algorithms_client_to_server_length,
6282 | { "compression_algorithms_client_to_server length", "ssh.compression_algorithms_client_to_server_length",
6283 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6284 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6285 |
6286 | { &hf_ssh_compression_algorithms_server_to_client_length,
6287 | { "compression_algorithms_server_to_client length", "ssh.compression_algorithms_server_to_client_length",
6288 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6289 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6290 |
6291 | { &hf_ssh_languages_client_to_server_length,
6292 | { "languages_client_to_server length", "ssh.languages_client_to_server_length",
6293 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6294 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6295 |
6296 | { &hf_ssh_languages_server_to_client_length,
6297 | { "languages_server_to_client length", "ssh.languages_server_to_client_length",
6298 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6299 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6300 |
6301 | { &hf_ssh_first_kex_packet_follows,
6302 | { "First KEX Packet Follows", "ssh.first_kex_packet_follows",
6303 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
6304 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6305 |
6306 | { &hf_ssh_kex_reserved,
6307 | { "Reserved", "ssh.kex.reserved",
6308 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6309 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6310 |
6311 | { &hf_ssh_kex_hassh_algo,
6312 | { "hasshAlgorithms", "ssh.kex.hassh_algorithms",
6313 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6314 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6315 |
6316 | { &hf_ssh_kex_hassh,
6317 | { "hassh", "ssh.kex.hassh",
6318 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6319 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6320 |
6321 | { &hf_ssh_kex_hasshserver_algo,
6322 | { "hasshServerAlgorithms", "ssh.kex.hasshserver_algorithms",
6323 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6324 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6325 |
6326 | { &hf_ssh_kex_hasshserver,
6327 | { "hasshServer", "ssh.kex.hasshserver",
6328 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6329 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6330 |
6331 | { &hf_ssh_hostkey_length,
6332 | { "Host key length", "ssh.host_key.length",
6333 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6334 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6335 |
6336 | { &hf_ssh_hostkey_type_length,
6337 | { "Host key type length", "ssh.host_key.type_length",
6338 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6339 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6340 |
6341 | { &hf_ssh_hostkey_type,
6342 | { "Host key type", "ssh.host_key.type",
6343 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6344 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6345 |
6346 | { &hf_ssh_hostkey_data,
6347 | { "Host key data", "ssh.host_key.data",
6348 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6349 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6350 |
6351 | { &hf_ssh_hostkey_rsa_n,
6352 | { "RSA modulus (N)", "ssh.host_key.rsa.n",
6353 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6354 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6355 |
6356 | { &hf_ssh_hostkey_rsa_e,
6357 | { "RSA public exponent (e)", "ssh.host_key.rsa.e",
6358 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6359 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6360 |
6361 | { &hf_ssh_hostkey_dsa_p,
6362 | { "DSA prime modulus (p)", "ssh.host_key.dsa.p",
6363 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6364 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6365 |
6366 | { &hf_ssh_hostkey_dsa_q,
6367 | { "DSA prime divisor (q)", "ssh.host_key.dsa.q",
6368 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6369 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6370 |
6371 | { &hf_ssh_hostkey_dsa_g,
6372 | { "DSA subgroup generator (g)", "ssh.host_key.dsa.g",
6373 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6374 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6375 |
6376 | { &hf_ssh_hostkey_dsa_y,
6377 | { "DSA public key (y)", "ssh.host_key.dsa.y",
6378 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6379 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6380 |
6381 | { &hf_ssh_hostkey_ecdsa_curve_id,
6382 | { "ECDSA elliptic curve identifier", "ssh.host_key.ecdsa.id",
6383 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6384 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6385 |
6386 | { &hf_ssh_hostkey_ecdsa_curve_id_length,
6387 | { "ECDSA elliptic curve identifier length", "ssh.host_key.ecdsa.id_length",
6388 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6389 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6390 |
6391 | { &hf_ssh_hostkey_ecdsa_q,
6392 | { "ECDSA public key (Q)", "ssh.host_key.ecdsa.q",
6393 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6394 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6395 |
6396 | { &hf_ssh_hostkey_ecdsa_q_length,
6397 | { "ECDSA public key length", "ssh.host_key.ecdsa.q_length",
6398 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6399 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6400 |
6401 | { &hf_ssh_hostkey_eddsa_key,
6402 | { "EdDSA public key", "ssh.host_key.eddsa.key",
6403 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6404 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6405 |
6406 | { &hf_ssh_hostkey_eddsa_key_length,
6407 | { "EdDSA public key length", "ssh.host_key.eddsa.key_length",
6408 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6409 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6410 |
6411 | { &hf_ssh_hostsig_length,
6412 | { "Host signature length", "ssh.host_sig.length",
6413 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6414 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6415 |
6416 | { &hf_ssh_hostsig_type_length,
6417 | { "Host signature type length", "ssh.host_sig.type_length",
6418 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6419 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6420 |
6421 | { &hf_ssh_hostsig_type,
6422 | { "Host signature type", "ssh.host_sig.type",
6423 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6424 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6425 |
6426 | { &hf_ssh_hostsig_data_length,
6427 | { "Host signature data length", "ssh.host_sig.data_length",
6428 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6429 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6430 |
6431 | { &hf_ssh_hostsig_data,
6432 | { "Host signature data", "ssh.host_sig.data",
6433 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6434 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6435 |
6436 | { &hf_ssh_hostsig_rsa,
6437 | { "RSA signature", "ssh.host_sig.rsa",
6438 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6439 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6440 |
6441 | { &hf_ssh_hostsig_dsa,
6442 | { "DSA signature", "ssh.host_sig.dsa",
6443 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6444 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6445 |
6446 | { &hf_ssh_dh_e,
6447 | { "DH client e", "ssh.dh.e",
6448 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6449 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6450 |
6451 | { &hf_ssh_dh_f,
6452 | { "DH server f", "ssh.dh.f",
6453 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6454 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6455 |
6456 | { &hf_ssh_dh_gex_min,
6457 | { "DH GEX Min", "ssh.dh_gex.min",
6458 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6459 | "Minimal acceptable group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6460 |
6461 | { &hf_ssh_dh_gex_nbits,
6462 | { "DH GEX Number of Bits", "ssh.dh_gex.nbits",
6463 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6464 | "Preferred group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6465 |
6466 | { &hf_ssh_dh_gex_max,
6467 | { "DH GEX Max", "ssh.dh_gex.max",
6468 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6469 | "Maximal acceptable group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6470 |
6471 | { &hf_ssh_dh_gex_p,
6472 | { "DH GEX modulus (P)", "ssh.dh_gex.p",
6473 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6474 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6475 |
6476 | { &hf_ssh_dh_gex_g,
6477 | { "DH GEX base (G)", "ssh.dh_gex.g",
6478 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6479 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6480 |
6481 | { &hf_ssh_ecdh_q_c,
6482 | { "ECDH client's ephemeral public key (Q_C)", "ssh.ecdh.q_c",
6483 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6484 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6485 |
6486 | { &hf_ssh_ecdh_q_c_length,
6487 | { "ECDH client's ephemeral public key length", "ssh.ecdh.q_c_length",
6488 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6489 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6490 |
6491 | { &hf_ssh_ecdh_q_s,
6492 | { "ECDH server's ephemeral public key (Q_S)", "ssh.ecdh.q_s",
6493 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6494 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6495 |
6496 | { &hf_ssh_ecdh_q_s_length,
6497 | { "ECDH server's ephemeral public key length", "ssh.ecdh.q_s_length",
6498 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6499 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6500 |
6501 | { &hf_ssh_mpint_length,
6502 | { "Multi Precision Integer Length", "ssh.mpint_length",
6503 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6504 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6505 |
6506 | { &hf_ssh_ignore_data_length,
6507 | { "Debug message length", "ssh.ignore_data_length",
6508 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6509 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6510 |
6511 | { &hf_ssh_ignore_data,
6512 | { "Ignore data", "ssh.ignore_data",
6513 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6514 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6515 |
6516 | { &hf_ssh_debug_always_display,
6517 | { "Always Display", "ssh.debug_always_display",
6518 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
6519 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6520 |
6521 | { &hf_ssh_debug_message_length,
6522 | { "Debug message length", "ssh.debug_name_length",
6523 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6524 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6525 |
6526 | { &hf_ssh_debug_message,
6527 | { "Debug message", "ssh.debug_name",
6528 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6529 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6530 |
6531 | { &hf_ssh_service_name_length,
6532 | { "Service Name length", "ssh.service_name_length",
6533 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6534 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6535 |
6536 | { &hf_ssh_service_name,
6537 | { "Service Name", "ssh.service_name",
6538 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6539 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6540 |
6541 | { &hf_ssh_disconnect_reason,
6542 | { "Disconnect reason", "ssh.disconnect_reason",
6543 | FT_UINT32, BASE_HEX, NULL((void*)0), 0x0,
6544 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6545 |
6546 | { &hf_ssh_disconnect_description_length,
6547 | { "Disconnect description length", "ssh.disconnect_description_length",
6548 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6549 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6550 |
6551 | { &hf_ssh_disconnect_description,
6552 | { "Disconnect description", "ssh.disconnect_description",
6553 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6554 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6555 |
6556 | { &hf_ssh_ext_count,
6557 | { "Extension count", "ssh.extension.count",
6558 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6559 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6560 |
6561 | { &hf_ssh_ext_name_length,
6562 | { "Extension name length", "ssh.extension.name_length",
6563 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6564 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6565 |
6566 | { &hf_ssh_ext_name,
6567 | { "Extension name", "ssh.extension.name",
6568 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6569 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6570 |
6571 | { &hf_ssh_ext_value_length,
6572 | { "Extension value length", "ssh.extension.value_length",
6573 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6574 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6575 |
6576 | { &hf_ssh_ext_value,
6577 | { "Extension value", "ssh.extension.value",
6578 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6579 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6580 |
6581 | { &hf_ssh_ext_server_sig_algs_algorithms,
6582 | { "Accepted signature algorithms", "ssh.extension.server_sig_algs.algorithms",
6583 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6584 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6585 |
6586 | { &hf_ssh_ext_delay_compression_algorithms_client_to_server_length,
6587 | { "Compression algorithms (client to server) length", "ssh.extension.delay_compression.compression_algorithms_client_to_server_length",
6588 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6589 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6590 |
6591 | { &hf_ssh_ext_delay_compression_algorithms_client_to_server,
6592 | { "Compression algorithms (client to server)", "ssh.extension.delay_compression.compression_algorithms_client_to_server",
6593 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6594 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6595 |
6596 | { &hf_ssh_ext_delay_compression_algorithms_server_to_client_length,
6597 | { "Compression algorithms (server to client) length", "ssh.extension.delay_compression.compression_algorithms_server_to_client_length",
6598 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6599 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6600 |
6601 | { &hf_ssh_ext_delay_compression_algorithms_server_to_client,
6602 | { "Compression algorithms (server to client)", "ssh.extension.delay_compression.compression_algorithms_server_to_client",
6603 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6604 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6605 |
6606 | { &hf_ssh_ext_no_flow_control_value,
6607 | { "No flow control flag", "ssh.extension.no_flow_control.value",
6608 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6609 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6610 |
6611 | { &hf_ssh_ext_elevation_value,
6612 | { "Elevation flag", "ssh.extension.elevation.value",
6613 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6614 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6615 |
6616 | { &hf_ssh_ext_prop_publickey_algorithms_algorithms,
6617 | { "Public key algorithms", "ssh.extension.prop_publickey_algorithms.algorithms",
6618 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6619 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6620 |
6621 | { &hf_ssh_lang_tag_length,
6622 | { "Language tag length", "ssh.lang_tag_length",
6623 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6624 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6625 |
6626 | { &hf_ssh_lang_tag,
6627 | { "Language tag", "ssh.lang_tag",
6628 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6629 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6630 |
6631 | { &hf_ssh_ping_data_length,
6632 | { "Data length", "ssh.ping_data_length",
6633 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6634 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6635 |
6636 | { &hf_ssh_ping_data,
6637 | { "Data", "ssh.ping_data",
6638 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6639 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6640 |
6641 | { &hf_ssh_pong_data_length,
6642 | { "Data length", "ssh.pong_data_length",
6643 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6644 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6645 |
6646 | { &hf_ssh_pong_data,
6647 | { "Data", "ssh.pong_data",
6648 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6649 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6650 |
6651 |
6652 | { &hf_ssh_userauth_user_name_length,
6653 | { "User Name length", "ssh.userauth_user_name_length",
6654 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6655 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6656 |
6657 | { &hf_ssh_userauth_user_name,
6658 | { "User Name", "ssh.userauth_user_name",
6659 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6660 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6661 |
6662 | { &hf_ssh_userauth_change_password,
6663 | { "Change password", "ssh.userauth.change_password",
6664 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
6665 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6666 |
6667 | { &hf_ssh_userauth_service_name_length,
6668 | { "Service Name length", "ssh.userauth_service_name_length",
6669 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6670 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6671 |
6672 | { &hf_ssh_userauth_service_name,
6673 | { "Service Name", "ssh.userauth_service_name",
6674 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6675 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6676 |
6677 | { &hf_ssh_userauth_method_name_length,
6678 | { "Method Name length", "ssh.userauth_method_name_length",
6679 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6680 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6681 |
6682 | { &hf_ssh_userauth_method_name,
6683 | { "Method Name", "ssh.userauth_method_name",
6684 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6685 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6686 |
6687 | { &hf_ssh_userauth_have_signature,
6688 | { "Have signature", "ssh.userauth.have_signature",
6689 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
6690 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6691 |
6692 | { &hf_ssh_userauth_password_length,
6693 | { "Password length", "ssh.userauth_password_length",
6694 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6695 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6696 |
6697 | { &hf_ssh_userauth_password,
6698 | { "Password", "ssh.userauth_password",
6699 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6700 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6701 |
6702 | { &hf_ssh_userauth_new_password_length,
6703 | { "New password length", "ssh.userauth_new_password_length",
6704 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6705 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6706 |
6707 | { &hf_ssh_userauth_new_password,
6708 | { "New password", "ssh.userauth_new_password",
6709 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6710 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6711 |
6712 | { &hf_ssh_auth_failure_list_length,
6713 | { "Authentications that can continue list len", "ssh.auth_failure_cont_list_length",
6714 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6715 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6716 |
6717 | { &hf_ssh_auth_failure_list,
6718 | { "Authentications that can continue list", "ssh.auth_failure_cont_list",
6719 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6720 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6721 |
6722 | { &hf_ssh_userauth_partial_success,
6723 | { "Partial success", "ssh.userauth.partial_success",
6724 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
6725 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6726 |
6727 | { &hf_ssh_userauth_pka_name_len,
6728 | { "Public key algorithm name length", "ssh.userauth_pka_name_length",
6729 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6730 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6731 |
6732 | { &hf_ssh_userauth_pka_name,
6733 | { "Public key algorithm name", "ssh.userauth_pka_name",
6734 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6735 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6736 |
6737 | { &hf_ssh_pk_blob_name_length,
6738 | { "Public key blob algorithm name length", "ssh.pk_blob_name_length",
6739 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6740 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6741 |
6742 | { &hf_ssh_pk_blob_name,
6743 | { "Public key blob algorithm name", "ssh.pk_blob_name",
6744 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6745 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6746 |
6747 | { &hf_ssh_blob_length,
6748 | { "Public key blob length", "ssh.pk_blob_length",
6749 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6750 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6751 |
6752 | { &hf_ssh_blob,
6753 | { "Public key blob", "ssh.pk_blob",
6754 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
6755 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6756 |
6757 | { &hf_ssh_blob_e,
6758 | { "ssh-rsa public exponent (e)", "ssh.pk_blob.ssh-rsa.e",
6759 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6760 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6761 |
6762 | { &hf_ssh_blob_n,
6763 | { "ssh-rsa modulus (n)", "ssh.pk_blob.ssh-rsa.n",
6764 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6765 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6766 |
6767 | { &hf_ssh_blob_dsa_p,
6768 | { "DSA prime modulus (p)", "ssh.pk_blob.dsa.p",
6769 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6770 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6771 |
6772 | { &hf_ssh_blob_dsa_q,
6773 | { "DSA prime divisor (q)", "ssh.pk_blob.dsa.q",
6774 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6775 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6776 |
6777 | { &hf_ssh_blob_dsa_g,
6778 | { "DSA subgroup generator (g)", "ssh.pk_blob.dsa.g",
6779 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6780 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6781 |
6782 | { &hf_ssh_blob_dsa_y,
6783 | { "DSA public key (y)", "ssh.pk_blob.dsa.y",
6784 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6785 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6786 |
6787 | { &hf_ssh_blob_ecdsa_curve_id,
6788 | { "ECDSA elliptic curve identifier", "ssh.pk_blob.ecdsa.id",
6789 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6790 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6791 |
6792 | { &hf_ssh_blob_ecdsa_curve_id_length,
6793 | { "ECDSA elliptic curve identifier length", "ssh.pk_blob.ecdsa.id_length",
6794 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6795 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6796 |
6797 | { &hf_ssh_blob_ecdsa_q,
6798 | { "ECDSA public key (Q)", "ssh.pk_blob.ecdsa.q",
6799 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6800 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6801 |
6802 | { &hf_ssh_blob_ecdsa_q_length,
6803 | { "ECDSA public key length", "ssh.pk_blob.ecdsa.q_length",
6804 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6805 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6806 |
6807 | { &hf_ssh_blob_eddsa_key,
6808 | { "EdDSA public key", "ssh.pk_blob.eddsa.key",
6809 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6810 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6811 |
6812 | { &hf_ssh_blob_eddsa_key_length,
6813 | { "EdDSA public key length", "ssh.pk_blob.eddsa.key_length",
6814 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6815 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6816 |
6817 | { &hf_ssh_blob_data,
6818 | { "Public key blob data", "ssh.pk_blob.data",
6819 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6820 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6821 |
6822 | { &hf_ssh_signature_length,
6823 | { "Public key signature blob length", "ssh.pk_sig_blob_length",
6824 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6825 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6826 |
6827 | { &hf_ssh_pk_sig_blob_name_length,
6828 | { "Public key signature blob algorithm name length", "ssh.pk_sig_blob_name_length",
6829 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6830 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6831 |
6832 | { &hf_ssh_pk_sig_blob_name,
6833 | { "Public key signature blob algorithm name", "ssh.pk_sig_blob_name",
6834 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6835 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6836 |
6837 | { &hf_ssh_pk_sig_s_length,
6838 | { "ssh-rsa signature length", "ssh.sig.ssh-rsa.length",
6839 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6840 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6841 |
6842 | { &hf_ssh_pk_sig_s,
6843 | { "ssh-rsa signature (s)", "ssh.sig.ssh-rsa.s",
6844 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
6845 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6846 |
6847 | { &hf_ssh_connection_type_name_len,
6848 | { "Channel type name length", "ssh.connection_type_name_length",
6849 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6850 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6851 |
6852 | { &hf_ssh_connection_type_name,
6853 | { "Channel type name", "ssh.connection_type_name",
6854 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6855 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6856 |
6857 | { &hf_ssh_connection_sender_channel,
6858 | { "Sender channel", "ssh.connection_sender_channel",
6859 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6860 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6861 |
6862 | { &hf_ssh_connection_recipient_channel,
6863 | { "Recipient channel", "ssh.connection_recipient_channel",
6864 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6865 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6866 |
6867 | { &hf_ssh_connection_initial_window,
6868 | { "Initial window size", "ssh.connection_initial_window_size",
6869 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6870 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6871 |
6872 | { &hf_ssh_connection_maximum_packet_size,
6873 | { "Maximum packet size", "ssh.userauth_maximum_packet_size",
6874 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6875 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6876 |
6877 | { &hf_ssh_global_request_name_len,
6878 | { "Global request name length", "ssh.global_request_name_length",
6879 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6880 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6881 |
6882 | { &hf_ssh_global_request_name,
6883 | { "Global request name", "ssh.global_request_name",
6884 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6885 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6886 |
6887 | { &hf_ssh_global_request_want_reply,
6888 | { "Global request want reply", "ssh.global_request_want_reply",
6889 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
6890 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6891 |
6892 | { &hf_ssh_global_request_hostkeys_array_len,
6893 | { "Host keys array length", "ssh.global_request_hostkeys",
6894 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6895 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6896 |
6897 | { &hf_ssh_channel_request_name_len,
6898 | { "Channel request name length", "ssh.channel_request_name_length",
6899 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6900 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6901 |
6902 | { &hf_ssh_channel_request_name,
6903 | { "Channel request name", "ssh.channel_request_name",
6904 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6905 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6906 |
6907 | { &hf_ssh_channel_request_want_reply,
6908 | { "Channel request want reply", "ssh.channel_request_want_reply",
6909 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0,
6910 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6911 |
6912 | { &hf_ssh_subsystem_name_len,
6913 | { "Subsystem name length", "ssh.subsystem_name_length",
6914 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6915 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6916 |
6917 | { &hf_ssh_subsystem_name,
6918 | { "Subsystem name", "ssh.subsystem_name",
6919 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6920 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
6921 |
6922 | { &hf_ssh_exec_cmd,
6923 | { "Command", "ssh.exec_command",
6924 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6925 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6926 |
6927 | { &hf_ssh_env_name,
6928 | { "Variable name", "ssh.env_name",
6929 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6930 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6931 |
6932 | { &hf_ssh_env_value,
6933 | { "Variable value", "ssh.env_value",
6934 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6935 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6936 |
6937 | { &hf_ssh_pty_term,
6938 | { "TERM environment variable", "ssh.pty_term",
6939 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0,
6940 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6941 |
6942 | { &hf_ssh_pty_term_width_char,
6943 | { "Terminal width, characters", "ssh.pty_term_width_char",
6944 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6945 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6946 |
6947 | { &hf_ssh_pty_term_height_row,
6948 | { "Terminal height, rows", "ssh.pty_term_height_row",
6949 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6950 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6951 |
6952 | { &hf_ssh_pty_term_width_pixel,
6953 | { "Terminal width, pixels", "ssh.pty_term_width_pixel",
6954 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6955 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6956 |
6957 | { &hf_ssh_pty_term_height_pixel,
6958 | { "Terminal height, pixels", "ssh.pty_term_height_pixel",
6959 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6960 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6961 |
6962 | { &hf_ssh_pty_term_modes_len,
6963 | { "Encoded Terminal Modes Length", "ssh.pty_term_modes_length",
6964 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
6965 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6966 |
6967 | { &hf_ssh_pty_term_modes,
6968 | { "Encoded Terminal Modes", "ssh.pty_term_modes",
6969 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
6970 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6971 |
6972 | { &hf_ssh_pty_term_mode,
6973 | { "Mode", "ssh.pty_term_mode",
6974 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
6975 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6976 |
6977 | { &hf_ssh_pty_term_mode_opcode,
6978 | { "Opcode", "ssh.pty_term_mode.opcode",
6979 | FT_UINT8, BASE_DEC, VALS(ssh_tty_op_vals)((0 ? (const struct _value_string*)0 : ((ssh_tty_op_vals)))), 0x0,
6980 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6981 |
6982 | { &hf_ssh_pty_term_mode_vintr,
6983 | { "Interrupt character", "ssh.pty_term_mode.vintr",
6984 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
6985 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
6986 |
6987 | { &hf_ssh_pty_term_mode_vquit,
6988 | { "Quit character", "ssh.pty_term_mode.vquit",
6989 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
6990 | "Sends SIGQUIT on POSIX systems", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
6991 |
6992 | { &hf_ssh_pty_term_mode_verase,
6993 | { "Erase the character to the left of the cursor", "ssh.pty_term_mode.verase",
6994 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
6995 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
6996 |
6997 | { &hf_ssh_pty_term_mode_vkill,
6998 | { "Kill the current input line", "ssh.pty_term_mode.vkill",
6999 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7000 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7001 |
7002 | { &hf_ssh_pty_term_mode_veof,
7003 | { "End-of-file character", "ssh.pty_term_mode.veof",
7004 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7005 | "Sends EOF from the terminal", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
7006 |
7007 | { &hf_ssh_pty_term_mode_veol,
7008 | { "End-of-line character", "ssh.pty_term_mode.veol",
7009 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7010 | "In additional to carriage return and/or line feed", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7011 |
7012 | { &hf_ssh_pty_term_mode_veol2,
7013 | { "Additional end-of-line character", "ssh.pty_term_mode.veol2",
7014 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7015 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7016 |
7017 | { &hf_ssh_pty_term_mode_vstart,
7018 | { "Continues paused output", "ssh.pty_term_mode.vstart",
7019 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7020 | "Normally Control-Q", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
7021 |
7022 | { &hf_ssh_pty_term_mode_vstop,
7023 | { "Pauses output", "ssh.pty_term_mode.vstop",
7024 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7025 | "Normally Control-S", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7026 |
7027 | { &hf_ssh_pty_term_mode_vsusp,
7028 | { "Suspends the current program", "ssh.pty_term_mode.vsusp",
7029 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7030 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7031 |
7032 | { &hf_ssh_pty_term_mode_vdsusp,
7033 | { "Another suspend character", "ssh.pty_term_mode.vdsusp",
7034 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7035 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7036 |
7037 | { &hf_ssh_pty_term_mode_vreprint,
7038 | { "Reprints the current input line", "ssh.pty_term_mode.vreprint",
7039 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7040 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7041 |
7042 | { &hf_ssh_pty_term_mode_vwerase,
7043 | { "Erase a word to the left of the cursor", "ssh.pty_term_mode.vwerase",
7044 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7045 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7046 |
7047 | { &hf_ssh_pty_term_mode_vlnext,
7048 | { "Enter the next character typed literally", "ssh.pty_term_mode.vlnext",
7049 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7050 | "Even if a special character", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7051 |
7052 | { &hf_ssh_pty_term_mode_vflush,
7053 | { "Character to flush output", "ssh.pty_term_mode.vflush",
7054 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7055 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7056 |
7057 | { &hf_ssh_pty_term_mode_vswtch,
7058 | { "Switch to a different shell layer", "ssh.pty_term_mode.vswtch",
7059 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7060 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7061 |
7062 | { &hf_ssh_pty_term_mode_vstatus,
7063 | { "Print system status line", "ssh.pty_term_mode.vstatus",
7064 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7065 | "Load, command, pid, etc.", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}},
7066 |
7067 | { &hf_ssh_pty_term_mode_vdiscard,
7068 | { "Toggles the flushing of terminal output", "ssh.pty_term_mode.vdiscard",
7069 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0,
7070 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} },
7071 |
7072 | { &hf_ssh_pty_term_mode_ignpar,
7073 | { "Ignore parity flag", "ssh.pty_term_mode.ignpar",
7074 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7075 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7076 |
7077 | { &hf_ssh_pty_term_mode_parmrk,
7078 | { "Mark parity and framing errors", "ssh.pty_term_mode.parmrk",
7079 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7080 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7081 |
7082 | { &hf_ssh_pty_term_mode_inpck,
7083 | { "Enable checking of parity errors", "ssh.pty_term_mode.inpck",
7084 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7085 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7086 |
7087 | { &hf_ssh_pty_term_mode_istrip,
7088 | { "Strip 8th bit off characters", "ssh.pty_term_mode.istrip",
7089 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7090 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7091 |
7092 | { &hf_ssh_pty_term_mode_inlcr,
7093 | { "Map NL into CR on input", "ssh.pty_term_mode.inlcr",
7094 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7095 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7096 |
7097 | { &hf_ssh_pty_term_mode_igncr,
7098 | { "Ignore CR on input", "ssh.pty_term_mode.igncr",
7099 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7100 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7101 |
7102 | { &hf_ssh_pty_term_mode_icrnl,
7103 | { "Map CR to NL on input", "ssh.pty_term_mode.icrnl",
7104 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7105 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7106 |
7107 | { &hf_ssh_pty_term_mode_iuclc,
7108 | { "Translate uppercase characters to lowercase", "ssh.pty_term_mode.iuclc",
7109 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7110 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7111 |
7112 | { &hf_ssh_pty_term_mode_ixon,
7113 | { "Enable output flow control", "ssh.pty_term_mode.ixon",
7114 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7115 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7116 |
7117 | { &hf_ssh_pty_term_mode_ixany,
7118 | { "Any char will restart after stop", "ssh.pty_term_mode.ixany",
7119 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7120 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7121 |
7122 | { &hf_ssh_pty_term_mode_ixoff,
7123 | { "Enable input flow control", "ssh.pty_term_mode.ixoff",
7124 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7125 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7126 |
7127 | { &hf_ssh_pty_term_mode_imaxbel,
7128 | { "Ring bell on input queue full", "ssh.pty_term_mode.imaxbel",
7129 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7130 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7131 |
7132 | { &hf_ssh_pty_term_mode_iutf8,
7133 | { "Terminal input and output is assumed to be encoded in UTF-8", "ssh.pty_term_mode.iutf8",
7134 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7135 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7136 |
7137 | { &hf_ssh_pty_term_mode_isig,
7138 | { "Enable signals INTR, QUIT, [D]SUSP", "ssh.pty_term_mode.isig",
7139 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7140 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7141 |
7142 | { &hf_ssh_pty_term_mode_icanon,
7143 | { "Canonicalize input lines", "ssh.pty_term_mode.icanon",
7144 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7145 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7146 |
7147 | { &hf_ssh_pty_term_mode_xcase,
7148 | { "Enable input and output of uppercase characters by preceding their lowercase equivalents with '\'", "ssh.pty_term_mode.xcase",
7149 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7150 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7151 |
7152 | { &hf_ssh_pty_term_mode_echo,
7153 | { "Enable echoing", "ssh.pty_term_mode.echo",
7154 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7155 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7156 |
7157 | { &hf_ssh_pty_term_mode_echoe,
7158 | { "Visually erase chars", "ssh.pty_term_mode.echoe",
7159 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7160 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7161 |
7162 | { &hf_ssh_pty_term_mode_echok,
7163 | { "Kill character discards current line", "ssh.pty_term_mode.echok",
7164 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7165 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7166 |
7167 | { &hf_ssh_pty_term_mode_echonl,
7168 | { "Echo NL even if ECHO is off", "ssh.pty_term_mode.echonl",
7169 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7170 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7171 |
7172 | { &hf_ssh_pty_term_mode_noflsh,
7173 | { "No flush after interrupt", "ssh.pty_term_mode.noflsh",
7174 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7175 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7176 |
7177 | { &hf_ssh_pty_term_mode_tostop,
7178 | { "Stop background jobs from output", "ssh.pty_term_mode.tostop",
7179 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7180 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7181 |
7182 | { &hf_ssh_pty_term_mode_iexten,
7183 | { "Enable extensions", "ssh.pty_term_mode.iexten",
7184 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7185 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7186 |
7187 | { &hf_ssh_pty_term_mode_echoctl,
7188 | { "Echo control characters as ^(Char)", "ssh.pty_term_mode.echoctl",
7189 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7190 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7191 |
7192 | { &hf_ssh_pty_term_mode_echoke,
7193 | { "Visual erase for line kill", "ssh.pty_term_mode.echoke",
7194 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7195 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7196 |
7197 | { &hf_ssh_pty_term_mode_pendin,
7198 | { "Retype pending input", "ssh.pty_term_mode.pendin",
7199 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7200 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7201 |
7202 | { &hf_ssh_pty_term_mode_opost,
7203 | { "Enable output processing", "ssh.pty_term_mode.opost",
7204 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7205 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7206 |
7207 | { &hf_ssh_pty_term_mode_olcuc,
7208 | { "Convert lowercase to uppercase", "ssh.pty_term_mode.olcuc",
7209 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7210 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7211 |
7212 | { &hf_ssh_pty_term_mode_onlcr,
7213 | { "Map NL to CR-NL", "ssh.pty_term_mode.onlcr",
7214 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7215 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7216 |
7217 | { &hf_ssh_pty_term_mode_ocrnl,
7218 | { "Translate carriage return to newline (output)", "ssh.pty_term_mode.ocrnl",
7219 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7220 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7221 |
7222 | { &hf_ssh_pty_term_mode_onocr,
7223 | { "Translate newline to carriage-return newline (output)", "ssh.pty_term_mode.onocr",
7224 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7225 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7226 |
7227 | { &hf_ssh_pty_term_mode_onlret,
7228 | { "Newline performs a carriage return (output)", "ssh.pty_term_mode.onlret",
7229 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7230 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7231 |
7232 | { &hf_ssh_pty_term_mode_cs7,
7233 | { "7 bit mode", "ssh.pty_term_mode.cs7",
7234 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7235 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7236 |
7237 | { &hf_ssh_pty_term_mode_cs8,
7238 | { "8 bit mode", "ssh.pty_term_mode.cs8",
7239 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7240 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7241 |
7242 | { &hf_ssh_pty_term_mode_parenb,
7243 | { "Parity enable", "ssh.pty_term_mode.parenb",
7244 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7245 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7246 |
7247 | { &hf_ssh_pty_term_mode_parodd,
7248 | { "Odd parity", "ssh.pty_term_mode.parodd",
7249 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7250 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7251 |
7252 | { &hf_ssh_pty_term_mode_ispeed,
7253 | { "Input baud rate", "ssh.pty_term_mode.ispeed",
7254 | FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_bit_sec)((0 ? (const struct unit_name_string*)0 : ((&units_bit_sec )))), 0x0,
7255 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7256 |
7257 | { &hf_ssh_pty_term_mode_ospeed,
7258 | { "Output baud rate", "ssh.pty_term_mode.ospeed",
7259 | FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_bit_sec)((0 ? (const struct unit_name_string*)0 : ((&units_bit_sec )))), 0x0,
7260 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7261 |
7262 | { &hf_ssh_pty_term_mode_value,
7263 | { "Value", "ssh.pty_term_mode.value",
7264 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
7265 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7266 |
7267 | { &hf_ssh_exit_status,
7268 | { "Exit status", "ssh.exit_status",
7269 | FT_UINT32, BASE_HEX, NULL((void*)0), 0x0,
7270 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7271 |
7272 | { &hf_ssh_channel_window_adjust,
7273 | { "Bytes to add", "ssh.channel_window_adjust",
7274 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
7275 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7276 |
7277 | { &hf_ssh_channel_data_len,
7278 | { "Data length", "ssh.channel_data_length",
7279 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
7280 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7281 |
7282 | { &hf_ssh_channel_data_type_code,
7283 | { "Data Type Code", "ssh.channel_data_type_code",
7284 | FT_UINT32, BASE_DEC, VALS(ssh_channel_data_type_code_vals)((0 ? (const struct _value_string*)0 : ((ssh_channel_data_type_code_vals )))), 0x0,
7285 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } },
7286 |
7287 | { &hf_ssh_reassembled_in,
7288 | { "Reassembled PDU in frame", "ssh.reassembled_in",
7289 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
7290 | "The PDU that doesn't end in this segment is reassembled in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7291 |
7292 | { &hf_ssh_reassembled_length,
7293 | { "Reassembled PDU length", "ssh.reassembled.length",
7294 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
7295 | "The total length of the reassembled payload", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7296 |
7297 | { &hf_ssh_reassembled_data,
7298 | { "Reassembled PDU data", "ssh.reassembled.data",
7299 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x00,
7300 | "The payload of multiple reassembled SSH segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7301 |
7302 | { &hf_ssh_segments,
7303 | { "Reassembled SSH segments", "ssh.segments",
7304 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0,
7305 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7306 |
7307 | { &hf_ssh_segment,
7308 | { "SSH segment", "ssh.segment",
7309 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
7310 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7311 |
7312 | { &hf_ssh_segment_overlap,
7313 | { "Segment overlap", "ssh.segment.overlap",
7314 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7315 | "Segment overlaps with other segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7316 |
7317 | { &hf_ssh_segment_overlap_conflict,
7318 | { "Conflicting data in segment overlap", "ssh.segment.overlap.conflict",
7319 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7320 | "Overlapping segments contained conflicting data", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7321 |
7322 | { &hf_ssh_segment_multiple_tails,
7323 | { "Multiple tail segments found", "ssh.segment.multipletails",
7324 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7325 | "Several tails were found when reassembling the pdu", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7326 |
7327 | { &hf_ssh_segment_too_long_fragment,
7328 | { "Segment too long", "ssh.segment.toolongfragment",
7329 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0,
7330 | "Segment contained data past end of the pdu", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7331 |
7332 | { &hf_ssh_segment_error,
7333 | { "Reassembling error", "ssh.segment.error",
7334 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0,
7335 | "Reassembling error due to illegal segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7336 |
7337 | { &hf_ssh_segment_count,
7338 | { "Segment count", "ssh.segment.count",
7339 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0,
7340 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7341 |
7342 | { &hf_ssh_segment_data,
7343 | { "SSH segment data", "ssh.segment.data",
7344 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x00,
7345 | "The payload of a single SSH segment", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }},
7346 |
7347 | { &hf_ssh_hybrid_blob_client,
7348 | { "Hybrid Key Exchange Blob Client", "ssh.kex_hybrid_blob_client",
7349 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "Client post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7350 | },
7351 |
7352 | { &hf_ssh_hybrid_blob_client_len,
7353 | { "Hybrid Key Exchange Blob Client Length", "ssh.kex_hybrid_blob_client_len",
7354 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "Length of client post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7355 | },
7356 |
7357 | { &hf_ssh_hybrid_blob_server,
7358 | { "Hybrid Key Exchange Blob Server", "ssh.kex_hybrid_blob_server",
7359 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "Server post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7360 | },
7361 |
7362 | { &hf_ssh_hybrid_blob_server_len,
7363 | { "Hybrid Key Exchange Blob Server Length", "ssh.kex_hybrid_blob_server_len",
7364 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, "Length of server post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7365 | },
7366 |
7367 | { &hf_ssh_pq_kem_client,
7368 | { "Client PQ KEM Public Key", "ssh.kex.pq_kem_client",
7369 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
7370 | "Post-quantum key (client)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7371 | },
7372 |
7373 | { &hf_ssh_pq_kem_server,
7374 | { "Server PQ KEM Response", "ssh.kex.pq_kem_server",
7375 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0,
7376 | "Post-quantum ciphertext (server response)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }
7377 | },
7378 |
7379 | };
7380 |
7381 | static int *ett[] = {
7382 | &ett_ssh,
7383 | &ett_key_exchange,
7384 | &ett_key_exchange_host_key,
7385 | &ett_key_exchange_host_sig,
7386 | &ett_extension,
7387 | &ett_userauth_pk_blob,
7388 | &ett_userauth_pk_signature,
7389 | &ett_term_modes,
7390 | &ett_term_mode,
7391 | &ett_ssh1,
7392 | &ett_ssh2,
7393 | &ett_key_init,
7394 | &ett_ssh_segments,
7395 | &ett_ssh_pqhybrid_client, // added for PQ hybrid CLIENT dissection
7396 | &ett_ssh_pqhybrid_server, // added for PQ hybrid SERVER dissection
7397 | &ett_ssh_segment
7398 | };
7399 |
7400 | static ei_register_info ei[] = {
7401 | { &ei_ssh_packet_length, { "ssh.packet_length.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid packet length", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7402 | { &ei_ssh_padding_length, { "ssh.padding_length.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid padding length", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7403 | { &ei_ssh_packet_decode, { "ssh.packet_decode.error", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Packet decoded length not equal to packet length", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7404 | { &ei_ssh_channel_number, { "ssh.channel_number.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Could not find channel", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7405 | { &ei_ssh_invalid_keylen, { "ssh.key_length.error", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Invalid key length", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7406 | { &ei_ssh_mac_bad, { "ssh.mac_bad.expert", PI_CHECKSUM0x01000000, PI_ERROR0x00800000, "Bad MAC", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7407 | { &ei_ssh2_kex_hybrid_msg_code, { "ssh.kex_hybrid_msg_code", PI_SECURITY0x0a000000, PI_NOTE0x00400000, "Hybrid KEX encountered", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7408 | { &ei_ssh2_kex_hybrid_msg_code_unknown, { "ssh.kex_hybrid_msg_code.unknown", PI_UNDECODED0x05000000, PI_NOTE0x00400000, "Unknown KEX_HYBRID message code", EXPFILL0, ((void*)0), 0, ((void*)0), {0, {((void*)0), ((void*)0), FT_NONE , BASE_NONE, ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE , -1, ((void*)0)}} }},
7409 |
7410 | };
7411 | module_t *ssh_module;
7412 | expert_module_t *expert_ssh;
7413 |
7414 | proto_ssh = proto_register_protocol("SSH Protocol", "SSH", "ssh");
7415 | proto_register_field_array(proto_ssh, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0]));
7416 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0]));
7417 | expert_ssh = expert_register_protocol(proto_ssh);
7418 | expert_register_field_array(expert_ssh, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
7419 |
7420 | #ifdef SSH_DECRYPT_DEBUG
7421 | ssh_module = prefs_register_protocol(proto_ssh, ssh_prefs_apply_cb);
7422 | #else
7423 | ssh_module = prefs_register_protocol(proto_ssh, NULL((void*)0));
7424 | #endif
7425 | prefs_register_bool_preference(ssh_module, "desegment_buffers",
7426 | "Reassemble SSH buffers spanning multiple TCP segments",
7427 | "Whether the SSH dissector should reassemble SSH buffers spanning multiple TCP segments. "
7428 | "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
7429 | &ssh_desegment);
7430 | prefs_register_bool_preference(ssh_module, "ignore_ssh_mac_failed",
7431 | "Ignore Message Authentication Code (MAC) failure",
7432 | "For troubleshooting purposes, decrypt even if the "
7433 | "Message Authentication Code (MAC) check fails.",
7434 | &ssh_ignore_mac_failed);
7435 |
7436 | ssh_master_key_map = g_hash_table_new_full(ssh_hash, ssh_equal, ssh_free_glib_allocated_bignum, ssh_free_glib_allocated_entry);
7437 | prefs_register_filename_preference(ssh_module, "keylog_file", "Key log filename",
7438 | "The path to the file which contains a list of key exchange secrets in the following format:\n"
7439 | "\"<hex-encoded-cookie> <PRIVATE_KEY|SHARED_SECRET> <hex-encoded-key>\" (without quotes or leading spaces).\n",
7440 | &pref_keylog_file, false0);
7441 |
7442 | prefs_register_filename_preference(ssh_module, "debug_file", "SSH debug file",
7443 | "Redirect SSH debug to the file specified. Leave empty to disable debugging "
7444 | "or use \"" SSH_DEBUG_USE_STDERR"-" "\" to redirect output to stderr.",
7445 | &ssh_debug_file_name, true1);
7446 |
7447 | secrets_register_type(SECRETS_TYPE_SSH0x5353484b, ssh_secrets_block_callback);
7448 |
7449 | ssh_handle = register_dissector("ssh", dissect_ssh, proto_ssh);
7450 | reassembly_table_register(&ssh_reassembly_table, &tcp_reassembly_table_functions);
7451 | register_shutdown_routine(ssh_shutdown);
7452 | }
7453 |
7454 | void
7455 | proto_reg_handoff_ssh(void)
7456 | {
7457 | #ifdef SSH_DECRYPT_DEBUG
7458 | ssh_set_debug(ssh_debug_file_name);
7459 | #endif
7460 | dissector_add_uint_range_with_preference("tcp.port", TCP_RANGE_SSH"22", ssh_handle);
7461 | dissector_add_uint("sctp.port", SCTP_PORT_SSH22, ssh_handle);
7462 | dissector_add_uint("sctp.ppi", SSH_PAYLOAD_PROTOCOL_ID45, ssh_handle);
7463 | sftp_handle = find_dissector_add_dependency("sftp", proto_ssh);
7464 | data_text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_ssh);
7465 |
7466 | heur_dissector_add("tcp", dissect_ssh_heur, "SSH over TCP", "ssh_tcp", proto_ssh, HEURISTIC_ENABLE);
7467 | }
7468 |
7469 | /*
7470 | * Editor modelines - https://www.wireshark.org/tools/modelines.html
7471 | *
7472 | * Local variables:
7473 | * c-basic-offset: 4
7474 | * tab-width: 8
7475 | * indent-tabs-mode: nil
7476 | * End:
7477 | *
7478 | * vi: set shiftwidth=4 tabstop=8 expandtab:
7479 | * :indentSize=4:tabSize=8:noTabs=true:
7480 | */