| File: | epan/dissectors/packet-ssh.c |
| Warning: | line 2656, column 17 Value of 'errno' was not checked and may be overwritten by function 'ferror' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | /* Start with WIRESHARK_LOG_DOMAINS=packet-ssh and WIRESHARK_LOG_LEVEL=debug to see messages. */ | |||
| 40 | #define WS_LOG_DOMAIN"packet-ssh" "packet-ssh" | |||
| 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 <jtckdint.h> | |||
| 46 | #include <errno(*__errno_location ()).h> | |||
| 47 | ||||
| 48 | #include <epan/packet.h> | |||
| 49 | #include <epan/exceptions.h> | |||
| 50 | #include <epan/sctpppids.h> | |||
| 51 | #include <epan/prefs.h> | |||
| 52 | #include <epan/expert.h> | |||
| 53 | #include <epan/proto_data.h> | |||
| 54 | #include <epan/tfs.h> | |||
| 55 | #include <epan/unit_strings.h> | |||
| 56 | #include <wsutil/strtoi.h> | |||
| 57 | #include <wsutil/to_str.h> | |||
| 58 | #include <wsutil/file_util.h> | |||
| 59 | #include <wsutil/filesystem.h> | |||
| 60 | #include <wsutil/wsgcrypt.h> | |||
| 61 | #include <wsutil/curve25519.h> | |||
| 62 | #include <wsutil/pint.h> | |||
| 63 | #include <wsutil/str_util.h> | |||
| 64 | #include <wsutil/wslog.h> | |||
| 65 | #include <epan/secrets.h> | |||
| 66 | #include <wiretap/secrets-types.h> | |||
| 67 | ||||
| 68 | #if defined(HAVE_LIBGNUTLS1) | |||
| 69 | #include <gnutls/abstract.h> | |||
| 70 | #endif | |||
| 71 | ||||
| 72 | #include "packet-tcp.h" | |||
| 73 | ||||
| 74 | void proto_register_ssh(void); | |||
| 75 | void proto_reg_handoff_ssh(void); | |||
| 76 | ||||
| 77 | /* SSH Version 1 definition , from openssh ssh1.h */ | |||
| 78 | #define SSH1_MSG_NONE0 0 /* no message */ | |||
| 79 | #define SSH1_MSG_DISCONNECT1 1 /* cause (string) */ | |||
| 80 | #define SSH1_SMSG_PUBLIC_KEY2 2 /* ck,msk,srvk,hostk */ | |||
| 81 | #define SSH1_CMSG_SESSION_KEY3 3 /* key (BIGNUM) */ | |||
| 82 | #define SSH1_CMSG_USER4 4 /* user (string) */ | |||
| 83 | ||||
| 84 | ||||
| 85 | #define SSH_VERSION_UNKNOWN0 0 | |||
| 86 | #define SSH_VERSION_11 1 | |||
| 87 | #define SSH_VERSION_22 2 | |||
| 88 | ||||
| 89 | /* proto data */ | |||
| 90 | ||||
| 91 | typedef struct { | |||
| 92 | uint8_t *data; | |||
| 93 | unsigned length; | |||
| 94 | } ssh_bignum; | |||
| 95 | ||||
| 96 | #define SSH_KEX_CURVE255190x00010000 0x00010000 | |||
| 97 | #define SSH_KEX_DH_GEX0x00020000 0x00020000 | |||
| 98 | #define SSH_KEX_DH_GROUP10x00030001 0x00030001 | |||
| 99 | #define SSH_KEX_DH_GROUP140x00030014 0x00030014 | |||
| 100 | #define SSH_KEX_DH_GROUP160x00030016 0x00030016 | |||
| 101 | #define SSH_KEX_DH_GROUP180x00030018 0x00030018 | |||
| 102 | #define SSH_KEX_SNTRUP761X255190x00040000 0x00040000 | |||
| 103 | #define SSH_KEX_MLKEM768X255190x00050000 0x00050000 | |||
| 104 | ||||
| 105 | #define SSH_KEX_HASH_SHA11 1 | |||
| 106 | #define SSH_KEX_HASH_SHA2562 2 | |||
| 107 | #define SSH_KEX_HASH_SHA5124 4 | |||
| 108 | ||||
| 109 | #define DIGEST_MAX_SIZE48 48 | |||
| 110 | ||||
| 111 | /* The maximum SSH packet_length accepted. If the packet_length field after | |||
| 112 | * attempted decryption is larger than this, the packet will be assumed to | |||
| 113 | * have failed decryption (possibly due to being continuation data). | |||
| 114 | * (This could be made a preference.) | |||
| 115 | */ | |||
| 116 | #define SSH_MAX_PACKET_LEN32768 32768 | |||
| 117 | ||||
| 118 | typedef struct _ssh_message_info_t { | |||
| 119 | uint32_t sequence_number; | |||
| 120 | unsigned char *plain_data; /**< Decrypted data. */ | |||
| 121 | unsigned data_len; /**< Length of decrypted data. */ | |||
| 122 | int id; /**< Identifies the exact message within a frame | |||
| 123 | (there can be multiple records in a frame). */ | |||
| 124 | uint32_t byte_seq; | |||
| 125 | uint32_t next_byte_seq; | |||
| 126 | struct _ssh_message_info_t* next; | |||
| 127 | uint8_t calc_mac[DIGEST_MAX_SIZE48]; | |||
| 128 | } ssh_message_info_t; | |||
| 129 | ||||
| 130 | typedef struct { | |||
| 131 | bool_Bool from_server; | |||
| 132 | ssh_message_info_t * messages; | |||
| 133 | } ssh_packet_info_t; | |||
| 134 | ||||
| 135 | typedef struct _ssh_channel_info_t { | |||
| 136 | uint32_t byte_seq; | |||
| 137 | uint16_t flags; | |||
| 138 | wmem_tree_t *multisegment_pdus; | |||
| 139 | dissector_handle_t handle; | |||
| 140 | } ssh_channel_info_t; | |||
| 141 | ||||
| 142 | struct ssh_peer_data { | |||
| 143 | unsigned counter; | |||
| 144 | ||||
| 145 | uint32_t frame_version_start; | |||
| 146 | uint32_t frame_version_end; | |||
| 147 | ||||
| 148 | uint32_t frame_key_start; | |||
| 149 | uint32_t frame_key_end; | |||
| 150 | int frame_key_end_offset; | |||
| 151 | ||||
| 152 | char* kex_proposal; | |||
| 153 | ||||
| 154 | /* For all subsequent proposals, | |||
| 155 | [0] is client-to-server and [1] is server-to-client. */ | |||
| 156 | #define CLIENT_TO_SERVER_PROPOSAL0 0 | |||
| 157 | #define SERVER_TO_CLIENT_PROPOSAL1 1 | |||
| 158 | ||||
| 159 | char* mac_proposals[2]; | |||
| 160 | char* mac; | |||
| 161 | int mac_length; | |||
| 162 | ||||
| 163 | char* enc_proposals[2]; | |||
| 164 | char* enc; | |||
| 165 | ||||
| 166 | char* comp_proposals[2]; | |||
| 167 | char* comp; | |||
| 168 | ||||
| 169 | int length_is_plaintext; | |||
| 170 | ||||
| 171 | // see libgcrypt source, gcrypt.h:gcry_cipher_algos | |||
| 172 | unsigned cipher_id; | |||
| 173 | unsigned mac_id; | |||
| 174 | // chacha20 needs two cipher handles | |||
| 175 | gcry_cipher_hd_t cipher, cipher_2; | |||
| 176 | unsigned sequence_number; | |||
| 177 | ssh_bignum *bn_cookie; | |||
| 178 | uint8_t iv[12]; | |||
| 179 | uint8_t hmac_iv[DIGEST_MAX_SIZE48]; | |||
| 180 | unsigned hmac_iv_len; | |||
| 181 | ||||
| 182 | unsigned int rekey_trigger_frame; // for storing new KEXINIT frame value when REKEY | |||
| 183 | bool_Bool rekey_pending; // trace REKEY | |||
| 184 | uint8_t plain0[16]; | |||
| 185 | bool_Bool plain0_valid; | |||
| 186 | ||||
| 187 | wmem_map_t *channel_info; /**< Map of sender channel numbers to recipient numbers. */ | |||
| 188 | wmem_map_t *channel_handles; /**< Map of recipient channel numbers to subdissector handles. */ | |||
| 189 | struct ssh_flow_data * global_data; | |||
| 190 | }; | |||
| 191 | ||||
| 192 | struct ssh_flow_data { | |||
| 193 | unsigned version; | |||
| 194 | ||||
| 195 | /* The address/port of the server */ | |||
| 196 | address srv_addr; | |||
| 197 | unsigned srv_port; | |||
| 198 | ||||
| 199 | char* kex; | |||
| 200 | int (*kex_specific_dissector)(uint8_t msg_code, tvbuff_t *tvb, | |||
| 201 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 202 | struct ssh_flow_data *global_data); | |||
| 203 | ||||
| 204 | /* [0] is client's, [1] is server's */ | |||
| 205 | #define CLIENT_PEER_DATA0 0 | |||
| 206 | #define SERVER_PEER_DATA1 1 | |||
| 207 | struct ssh_peer_data peer_data[2]; | |||
| 208 | ||||
| 209 | char *session_id; | |||
| 210 | unsigned session_id_length; | |||
| 211 | ssh_bignum *kex_e; | |||
| 212 | ssh_bignum *kex_f; | |||
| 213 | ssh_bignum *kex_gex_p; // Group modulo | |||
| 214 | ssh_bignum *kex_gex_g; // Group generator | |||
| 215 | ssh_bignum *secret; | |||
| 216 | wmem_array_t *kex_client_version; | |||
| 217 | wmem_array_t *kex_server_version; | |||
| 218 | wmem_array_t *kex_client_key_exchange_init; | |||
| 219 | wmem_array_t *kex_server_key_exchange_init; | |||
| 220 | wmem_array_t *kex_server_host_key_blob; | |||
| 221 | wmem_array_t *kex_gex_bits_min; | |||
| 222 | wmem_array_t *kex_gex_bits_req; | |||
| 223 | wmem_array_t *kex_gex_bits_max; | |||
| 224 | wmem_array_t *kex_shared_secret; | |||
| 225 | bool_Bool do_decrypt; | |||
| 226 | bool_Bool ext_ping_openssh_offered; | |||
| 227 | bool_Bool ext_kex_strict; | |||
| 228 | ssh_bignum new_keys[6]; | |||
| 229 | uint8_t *pqkem_ciphertext; | |||
| 230 | uint32_t pqkem_ciphertext_len; | |||
| 231 | uint8_t *curve25519_pub; | |||
| 232 | uint32_t curve25519_pub_len; | |||
| 233 | // storing PQ dissected keys | |||
| 234 | uint8_t *kex_e_pq; // binary material => no bignum (not traditional DH integer / not math ready) | |||
| 235 | uint8_t *kex_f_pq; // binary material => no bignum (not traditional DH integer / not math ready) | |||
| 236 | uint32_t kex_e_pq_len; | |||
| 237 | uint32_t kex_f_pq_len; | |||
| 238 | }; | |||
| 239 | ||||
| 240 | typedef struct { | |||
| 241 | char *type; // "PRIVATE_KEY" or "SHARED_SECRET" | |||
| 242 | ssh_bignum *key_material; // Either private key or shared secret | |||
| 243 | } ssh_key_map_entry_t; | |||
| 244 | ||||
| 245 | static GHashTable * ssh_master_key_map; | |||
| 246 | ||||
| 247 | static int proto_ssh; | |||
| 248 | ||||
| 249 | /* Version exchange */ | |||
| 250 | static int hf_ssh_protocol; | |||
| 251 | ||||
| 252 | /* Framing */ | |||
| 253 | static int hf_ssh_packet_length; | |||
| 254 | static int hf_ssh_packet_length_encrypted; | |||
| 255 | static int hf_ssh_padding_length; | |||
| 256 | static int hf_ssh_payload; | |||
| 257 | static int hf_ssh_encrypted_packet; | |||
| 258 | static int hf_ssh_padding_string; | |||
| 259 | static int hf_ssh_mac_string; | |||
| 260 | static int hf_ssh_mac_status; | |||
| 261 | static int hf_ssh_seq_num; | |||
| 262 | static int hf_ssh_direction; | |||
| 263 | ||||
| 264 | /* Message codes */ | |||
| 265 | static int hf_ssh_msg_code; | |||
| 266 | static int hf_ssh2_msg_code; | |||
| 267 | static int hf_ssh2_kex_dh_msg_code; | |||
| 268 | static int hf_ssh2_kex_dh_gex_msg_code; | |||
| 269 | static int hf_ssh2_kex_ecdh_msg_code; | |||
| 270 | static int hf_ssh2_kex_hybrid_msg_code; | |||
| 271 | static int hf_ssh2_ext_ping_msg_code; | |||
| 272 | ||||
| 273 | /* Algorithm negotiation */ | |||
| 274 | static int hf_ssh_cookie; | |||
| 275 | static int hf_ssh_kex_algorithms; | |||
| 276 | static int hf_ssh_server_host_key_algorithms; | |||
| 277 | static int hf_ssh_encryption_algorithms_client_to_server; | |||
| 278 | static int hf_ssh_encryption_algorithms_server_to_client; | |||
| 279 | static int hf_ssh_mac_algorithms_client_to_server; | |||
| 280 | static int hf_ssh_mac_algorithms_server_to_client; | |||
| 281 | static int hf_ssh_compression_algorithms_client_to_server; | |||
| 282 | static int hf_ssh_compression_algorithms_server_to_client; | |||
| 283 | static int hf_ssh_languages_client_to_server; | |||
| 284 | static int hf_ssh_languages_server_to_client; | |||
| 285 | static int hf_ssh_kex_algorithms_length; | |||
| 286 | static int hf_ssh_server_host_key_algorithms_length; | |||
| 287 | static int hf_ssh_encryption_algorithms_client_to_server_length; | |||
| 288 | static int hf_ssh_encryption_algorithms_server_to_client_length; | |||
| 289 | static int hf_ssh_mac_algorithms_client_to_server_length; | |||
| 290 | static int hf_ssh_mac_algorithms_server_to_client_length; | |||
| 291 | static int hf_ssh_compression_algorithms_client_to_server_length; | |||
| 292 | static int hf_ssh_compression_algorithms_server_to_client_length; | |||
| 293 | static int hf_ssh_languages_client_to_server_length; | |||
| 294 | static int hf_ssh_languages_server_to_client_length; | |||
| 295 | static int hf_ssh_first_kex_packet_follows; | |||
| 296 | static int hf_ssh_kex_reserved; | |||
| 297 | static int hf_ssh_kex_hassh_algo; | |||
| 298 | static int hf_ssh_kex_hassh; | |||
| 299 | static int hf_ssh_kex_hasshserver_algo; | |||
| 300 | static int hf_ssh_kex_hasshserver; | |||
| 301 | ||||
| 302 | /* Key exchange common elements */ | |||
| 303 | static int hf_ssh_hostkey_length; | |||
| 304 | static int hf_ssh_hostkey_type_length; | |||
| 305 | static int hf_ssh_hostkey_type; | |||
| 306 | static int hf_ssh_hostkey_data; | |||
| 307 | static int hf_ssh_hostkey_rsa_n; | |||
| 308 | static int hf_ssh_hostkey_rsa_e; | |||
| 309 | static int hf_ssh_hostkey_dsa_p; | |||
| 310 | static int hf_ssh_hostkey_dsa_q; | |||
| 311 | static int hf_ssh_hostkey_dsa_g; | |||
| 312 | static int hf_ssh_hostkey_dsa_y; | |||
| 313 | static int hf_ssh_hostkey_ecdsa_curve_id; | |||
| 314 | static int hf_ssh_hostkey_ecdsa_curve_id_length; | |||
| 315 | static int hf_ssh_hostkey_ecdsa_q; | |||
| 316 | static int hf_ssh_hostkey_ecdsa_q_length; | |||
| 317 | static int hf_ssh_hostkey_eddsa_key; | |||
| 318 | static int hf_ssh_hostkey_eddsa_key_length; | |||
| 319 | static int hf_ssh_hostsig_length; | |||
| 320 | static int hf_ssh_hostsig_type_length; | |||
| 321 | static int hf_ssh_hostsig_type; | |||
| 322 | static int hf_ssh_hostsig_rsa; | |||
| 323 | static int hf_ssh_hostsig_dsa; | |||
| 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_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 ssh_dissect_kex_pq_hybrid(uint8_t msg_code, tvbuff_t *tvb, | |||
| 901 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 902 | struct ssh_flow_data *global_data); | |||
| 903 | static int // add support of client PQ hybrid key (e) | |||
| 904 | ssh_read_e_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data); | |||
| 905 | static int // add support of server PQ hybrid key (f) | |||
| 906 | ssh_read_f_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data); | |||
| 907 | static int ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo, | |||
| 908 | struct ssh_flow_data *global_data, | |||
| 909 | int offset, proto_tree *tree, int is_response, unsigned *version, | |||
| 910 | bool_Bool *need_desegmentation); | |||
| 911 | static int ssh_try_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 912 | struct ssh_peer_data *peer_data, int offset, proto_tree *tree); | |||
| 913 | static int ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 914 | struct ssh_peer_data *peer_data, | |||
| 915 | int offset, proto_tree *tree); | |||
| 916 | static bool_Bool ssh_choose_algo(char *client, char *server, char **result); | |||
| 917 | static void ssh_set_mac_length(struct ssh_peer_data *peer_data); | |||
| 918 | static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data); | |||
| 919 | ||||
| 920 | static void ssh_keylog_read_file(void); | |||
| 921 | static void ssh_keylog_process_line(const char *line); | |||
| 922 | static void ssh_keylog_process_lines(const uint8_t *data, unsigned datalen); | |||
| 923 | static void ssh_keylog_reset(void); | |||
| 924 | static ssh_bignum *ssh_kex_make_bignum(const uint8_t *data, unsigned length); | |||
| 925 | static bool_Bool ssh_read_e(tvbuff_t *tvb, int offset, | |||
| 926 | struct ssh_flow_data *global_data); | |||
| 927 | static bool_Bool ssh_read_f(tvbuff_t *tvb, int offset, | |||
| 928 | struct ssh_flow_data *global_data); | |||
| 929 | static ssh_bignum * ssh_read_mpint(tvbuff_t *tvb, int offset); | |||
| 930 | static void ssh_keylog_hash_write_secret(struct ssh_flow_data *global_data); | |||
| 931 | static ssh_bignum *ssh_kex_shared_secret(int kex_type, ssh_bignum *pub, ssh_bignum *priv, ssh_bignum *modulo); | |||
| 932 | static void ssh_hash_buffer_put_string(wmem_array_t *buffer, const char *string, | |||
| 933 | unsigned len); | |||
| 934 | static void ssh_hash_buffer_put_uint32(wmem_array_t *buffer, unsigned val); | |||
| 935 | static char *ssh_string(const char *string, unsigned len); | |||
| 936 | static void ssh_derive_symmetric_keys(ssh_bignum *shared_secret, | |||
| 937 | char *exchange_hash, unsigned hash_length, | |||
| 938 | struct ssh_flow_data *global_data); | |||
| 939 | static void ssh_derive_symmetric_key(ssh_bignum *shared_secret, | |||
| 940 | char *exchange_hash, unsigned hash_length, char id, | |||
| 941 | ssh_bignum *result_key, struct ssh_flow_data *global_data, unsigned we_need); | |||
| 942 | ||||
| 943 | static void ssh_choose_enc_mac(struct ssh_flow_data *global_data); | |||
| 944 | static void ssh_decryption_set_cipher_id(struct ssh_peer_data *peer); | |||
| 945 | static void ssh_decryption_setup_cipher(struct ssh_peer_data *peer, | |||
| 946 | ssh_bignum *iv, ssh_bignum *key); | |||
| 947 | static void ssh_decryption_set_mac_id(struct ssh_peer_data *peer); | |||
| 948 | static void ssh_decryption_setup_mac(struct ssh_peer_data *peer, | |||
| 949 | ssh_bignum *iv); | |||
| 950 | static ssh_packet_info_t* ssh_get_packet_info(packet_info *pinfo, bool_Bool is_response); | |||
| 951 | static ssh_message_info_t* ssh_get_message(packet_info *pinfo, int record_id); | |||
| 952 | static unsigned ssh_decrypt_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 953 | struct ssh_peer_data *peer_data, int offset); | |||
| 954 | static bool_Bool ssh_decrypt_chacha20(gcry_cipher_hd_t hd, uint32_t seqnr, | |||
| 955 | uint32_t counter, const unsigned char *ctext, unsigned ctext_len, | |||
| 956 | unsigned char *plain, unsigned plain_len); | |||
| 957 | static int ssh_dissect_decrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 958 | struct ssh_peer_data *peer_data, proto_tree *tree, | |||
| 959 | ssh_message_info_t *message); | |||
| 960 | static int ssh_dissect_transport_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 961 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code); | |||
| 962 | static int ssh_dissect_rfc8308_extension(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 963 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree); | |||
| 964 | static int ssh_dissect_userauth_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 965 | int offset, proto_item *msg_type_tree, unsigned msg_code); | |||
| 966 | static int ssh_dissect_userauth_specific(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 967 | int offset, proto_item *msg_type_tree, unsigned msg_code); | |||
| 968 | static int ssh_dissect_connection_specific(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 969 | struct ssh_peer_data *peer_data, int offset, proto_item *msg_type_tree, | |||
| 970 | unsigned msg_code, ssh_message_info_t *message); | |||
| 971 | static int ssh_dissect_connection_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 972 | int offset, proto_item *msg_type_tree, unsigned msg_code); | |||
| 973 | static int ssh_dissect_local_extension(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 974 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code); | |||
| 975 | static int ssh_dissect_public_key_blob(tvbuff_t *tvb, packet_info *pinfo, | |||
| 976 | proto_item *msg_type_tree); | |||
| 977 | static int ssh_dissect_public_key_signature(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 978 | int offset, proto_item *msg_type_tree); | |||
| 979 | ||||
| 980 | static void create_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, uint32_t sender_channel); | |||
| 981 | static ssh_channel_info_t* get_channel_info_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel); | |||
| 982 | static void set_subdissector_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, const uint8_t* subsystem_name); | |||
| 983 | ||||
| 984 | #define SSH_DEBUG_USE_STDERR"-" "-" | |||
| 985 | ||||
| 986 | #ifdef SSH_DECRYPT_DEBUG | |||
| 987 | static void | |||
| 988 | ssh_debug_printf(const char* fmt,...) G_GNUC_PRINTF(1,2)__attribute__((__format__ (__printf__, 1, 2))); | |||
| 989 | static void | |||
| 990 | ssh_print_data(const char* name, const unsigned char* data, size_t len); | |||
| 991 | static void | |||
| 992 | ssh_set_debug(const char* name); | |||
| 993 | static void | |||
| 994 | ssh_debug_flush(void); | |||
| 995 | #else | |||
| 996 | ||||
| 997 | /* No debug: nullify debug operation*/ | |||
| 998 | static inline void G_GNUC_PRINTF(1,2)__attribute__((__format__ (__printf__, 1, 2))) | |||
| 999 | ssh_debug_printf(const char* fmt _U___attribute__((unused)),...) | |||
| 1000 | { | |||
| 1001 | } | |||
| 1002 | #define ssh_print_data(a, b, c) | |||
| 1003 | #define ssh_print_string(a, b) | |||
| 1004 | #define ssh_set_debug(name) | |||
| 1005 | #define ssh_debug_flush() | |||
| 1006 | ||||
| 1007 | #endif /* SSH_DECRYPT_DEBUG */ | |||
| 1008 | ||||
| 1009 | static void | |||
| 1010 | ssh_set_server(struct ssh_flow_data *global_data, address *addr, uint32_t port) | |||
| 1011 | { | |||
| 1012 | copy_address_wmem(wmem_file_scope(), &global_data->srv_addr, addr); | |||
| 1013 | global_data->srv_port = port; | |||
| 1014 | } | |||
| 1015 | ||||
| 1016 | static bool_Bool | |||
| 1017 | ssh_packet_from_server(struct ssh_flow_data *session, const packet_info *pinfo) | |||
| 1018 | { | |||
| 1019 | bool_Bool ret; | |||
| 1020 | if (session && session->srv_addr.type != AT_NONE) { | |||
| 1021 | ret = (session->srv_port == pinfo->srcport) && | |||
| 1022 | addresses_equal(&session->srv_addr, &pinfo->src); | |||
| 1023 | } else { | |||
| 1024 | ret = (pinfo->match_uint == pinfo->srcport); | |||
| 1025 | } | |||
| 1026 | ||||
| 1027 | ssh_debug_printf("packet_from_server: is from server - %s\n", (ret)?"TRUE":"FALSE"); | |||
| 1028 | return ret; | |||
| 1029 | } | |||
| 1030 | ||||
| 1031 | static bool_Bool | |||
| 1032 | ssh_peer_data_from_server(struct ssh_peer_data* peer_data) { | |||
| 1033 | return &peer_data->global_data->peer_data[SERVER_PEER_DATA1] == peer_data; | |||
| 1034 | } | |||
| 1035 | ||||
| 1036 | static int | |||
| 1037 | dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused))) | |||
| 1038 | { | |||
| 1039 | proto_tree *ssh_tree; | |||
| 1040 | proto_item *ti; | |||
| 1041 | conversation_t *conversation; | |||
| 1042 | int last_offset, offset = 0; | |||
| 1043 | ||||
| 1044 | bool_Bool is_response, | |||
| 1045 | need_desegmentation; | |||
| 1046 | unsigned version; | |||
| 1047 | ||||
| 1048 | struct ssh_flow_data *global_data = NULL((void*)0); | |||
| 1049 | struct ssh_peer_data *peer_data; | |||
| 1050 | ||||
| 1051 | ssh_debug_printf("\ndissect_ssh enter frame #%u (%s)\n", pinfo->num, (pinfo->fd->visited)?"already visited":"first time"); | |||
| 1052 | ||||
| 1053 | conversation = find_or_create_conversation(pinfo); | |||
| 1054 | ||||
| 1055 | global_data = (struct ssh_flow_data *)conversation_get_proto_data(conversation, proto_ssh); | |||
| 1056 | if (!global_data) { | |||
| 1057 | 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))); | |||
| 1058 | global_data->version = SSH_VERSION_UNKNOWN0; | |||
| 1059 | global_data->kex_specific_dissector = ssh_dissect_kex_dh; | |||
| 1060 | global_data->peer_data[CLIENT_PEER_DATA0].mac_length = -1; | |||
| 1061 | global_data->peer_data[SERVER_PEER_DATA1].mac_length = -1; | |||
| 1062 | global_data->peer_data[CLIENT_PEER_DATA0].sequence_number = 0; | |||
| 1063 | global_data->peer_data[SERVER_PEER_DATA1].sequence_number = 0; | |||
| 1064 | global_data->peer_data[CLIENT_PEER_DATA0].bn_cookie = NULL((void*)0); | |||
| 1065 | global_data->peer_data[SERVER_PEER_DATA1].bn_cookie = NULL((void*)0); | |||
| 1066 | global_data->peer_data[CLIENT_PEER_DATA0].global_data = global_data; | |||
| 1067 | global_data->peer_data[SERVER_PEER_DATA1].global_data = global_data; | |||
| 1068 | global_data->kex_client_version = wmem_array_new(wmem_file_scope(), 1); | |||
| 1069 | global_data->kex_server_version = wmem_array_new(wmem_file_scope(), 1); | |||
| 1070 | global_data->kex_client_key_exchange_init = wmem_array_new(wmem_file_scope(), 1); | |||
| 1071 | global_data->kex_server_key_exchange_init = wmem_array_new(wmem_file_scope(), 1); | |||
| 1072 | global_data->kex_server_host_key_blob = wmem_array_new(wmem_file_scope(), 1); | |||
| 1073 | global_data->kex_gex_bits_min = wmem_array_new(wmem_file_scope(), 1); | |||
| 1074 | global_data->kex_gex_bits_req = wmem_array_new(wmem_file_scope(), 1); | |||
| 1075 | global_data->kex_gex_bits_max = wmem_array_new(wmem_file_scope(), 1); | |||
| 1076 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1); | |||
| 1077 | global_data->do_decrypt = true1; | |||
| 1078 | global_data->ext_ping_openssh_offered = false0; | |||
| 1079 | ||||
| 1080 | /* We expect to get the client message first. If this is from an | |||
| 1081 | * an assigned server port, call it the server, otherwise call it | |||
| 1082 | * the client. | |||
| 1083 | * XXX - We don't unambigously know which side is the server and | |||
| 1084 | * which the client until the KEX specific _INIT and _REPLY messages; | |||
| 1085 | * we ought to be able to handle the cases where the version string or | |||
| 1086 | * KEXINIT messages are out of order or where the client version string | |||
| 1087 | * is missing. */ | |||
| 1088 | if (pinfo->match_uint == pinfo->srcport) { | |||
| 1089 | ssh_set_server(global_data, &pinfo->src, pinfo->srcport); | |||
| 1090 | } else { | |||
| 1091 | ssh_set_server(global_data, &pinfo->dst, pinfo->destport); | |||
| 1092 | } | |||
| 1093 | ||||
| 1094 | conversation_add_proto_data(conversation, proto_ssh, global_data); | |||
| 1095 | } | |||
| 1096 | ||||
| 1097 | is_response = ssh_packet_from_server(global_data, pinfo); | |||
| 1098 | peer_data = &global_data->peer_data[is_response]; | |||
| 1099 | ||||
| 1100 | ti = proto_tree_add_item(tree, proto_ssh, tvb, offset, -1, ENC_NA0x00000000); | |||
| 1101 | ssh_tree = proto_item_add_subtree(ti, ett_ssh); | |||
| 1102 | ||||
| 1103 | version = global_data->version; | |||
| 1104 | ||||
| 1105 | switch(version) { | |||
| 1106 | case SSH_VERSION_UNKNOWN0: | |||
| 1107 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSH"); | |||
| 1108 | break; | |||
| 1109 | case SSH_VERSION_11: | |||
| 1110 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv1"); | |||
| 1111 | break; | |||
| 1112 | case SSH_VERSION_22: | |||
| 1113 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv2"); | |||
| 1114 | break; | |||
| 1115 | ||||
| 1116 | } | |||
| 1117 | ||||
| 1118 | col_clear(pinfo->cinfo, COL_INFO); | |||
| 1119 | ||||
| 1120 | while(tvb_reported_length_remaining(tvb, offset)> 0) { | |||
| 1121 | bool_Bool after_version_start = (peer_data->frame_version_start == 0 || | |||
| 1122 | pinfo->num >= peer_data->frame_version_start); | |||
| 1123 | bool_Bool before_version_end = (peer_data->frame_version_end == 0 || | |||
| 1124 | pinfo->num <= peer_data->frame_version_end); | |||
| 1125 | ||||
| 1126 | need_desegmentation = false0; | |||
| 1127 | last_offset = offset; | |||
| 1128 | ||||
| 1129 | peer_data->counter++; | |||
| 1130 | ||||
| 1131 | if (after_version_start && before_version_end && | |||
| 1132 | (tvb_strncaseeql(tvb, offset, "SSH-", 4) == 0)) { | |||
| 1133 | if (peer_data->frame_version_start == 0) | |||
| 1134 | peer_data->frame_version_start = pinfo->num; | |||
| 1135 | ||||
| 1136 | offset = ssh_dissect_protocol(tvb, pinfo, | |||
| 1137 | global_data, | |||
| 1138 | offset, ssh_tree, is_response, | |||
| 1139 | &version, &need_desegmentation); | |||
| 1140 | ||||
| 1141 | if (!need_desegmentation) { | |||
| 1142 | peer_data->frame_version_end = pinfo->num; | |||
| 1143 | global_data->version = version; | |||
| 1144 | } | |||
| 1145 | } else { | |||
| 1146 | switch(version) { | |||
| 1147 | ||||
| 1148 | case SSH_VERSION_UNKNOWN0: | |||
| 1149 | offset = ssh_try_dissect_encrypted_packet(tvb, pinfo, | |||
| 1150 | &global_data->peer_data[is_response], offset, ssh_tree); | |||
| 1151 | break; | |||
| 1152 | ||||
| 1153 | case SSH_VERSION_11: | |||
| 1154 | offset = ssh_dissect_ssh1(tvb, pinfo, global_data, | |||
| 1155 | offset, ssh_tree, is_response, | |||
| 1156 | &need_desegmentation); | |||
| 1157 | break; | |||
| 1158 | ||||
| 1159 | case SSH_VERSION_22: | |||
| 1160 | offset = ssh_dissect_ssh2(tvb, pinfo, global_data, | |||
| 1161 | offset, ssh_tree, is_response, | |||
| 1162 | &need_desegmentation); | |||
| 1163 | break; | |||
| 1164 | } | |||
| 1165 | } | |||
| 1166 | ||||
| 1167 | if (need_desegmentation) | |||
| 1168 | return tvb_captured_length(tvb); | |||
| 1169 | if (offset <= last_offset) { | |||
| 1170 | /* XXX - add an expert info in the function | |||
| 1171 | that decrements offset */ | |||
| 1172 | break; | |||
| 1173 | } | |||
| 1174 | } | |||
| 1175 | ||||
| 1176 | col_prepend_fstr(pinfo->cinfo, COL_INFO, "%s: ", is_response ? "Server" : "Client"); | |||
| 1177 | ti = proto_tree_add_boolean(ssh_tree, hf_ssh_direction, tvb, 0, 0, is_response); | |||
| 1178 | proto_item_set_generated(ti); | |||
| 1179 | ||||
| 1180 | ssh_debug_flush(); | |||
| 1181 | ||||
| 1182 | return tvb_captured_length(tvb); | |||
| 1183 | } | |||
| 1184 | ||||
| 1185 | static bool_Bool | |||
| 1186 | dissect_ssh_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) | |||
| 1187 | { | |||
| 1188 | conversation_t *conversation; | |||
| 1189 | ||||
| 1190 | if (tvb_strneql(tvb, 0, "SSH-", 4) != 0) { | |||
| 1191 | return false0; | |||
| 1192 | } | |||
| 1193 | ||||
| 1194 | conversation = find_or_create_conversation(pinfo); | |||
| 1195 | conversation_set_dissector(conversation, ssh_handle); | |||
| 1196 | ||||
| 1197 | dissect_ssh(tvb, pinfo, tree, data); | |||
| 1198 | ||||
| 1199 | return true1; | |||
| 1200 | } | |||
| 1201 | ||||
| 1202 | static int | |||
| 1203 | ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo, | |||
| 1204 | struct ssh_flow_data *global_data, | |||
| 1205 | int offset, proto_tree *tree, int is_response, | |||
| 1206 | bool_Bool *need_desegmentation) | |||
| 1207 | { | |||
| 1208 | proto_item *ssh2_tree = NULL((void*)0); | |||
| 1209 | int remain_length; | |||
| 1210 | ||||
| 1211 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response]; | |||
| 1212 | ||||
| 1213 | remain_length = tvb_captured_length_remaining(tvb, offset); | |||
| 1214 | ||||
| 1215 | if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1216 | 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" , 1216, __func__, "SSH: SECOND PASS frame %u", pinfo->num) ; } } while (0); | |||
| 1217 | }else{ | |||
| 1218 | 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" , 1218, __func__, "SSH: FIRST PASS frame %u", pinfo->num); } } while (0); | |||
| 1219 | } | |||
| 1220 | ||||
| 1221 | while(remain_length>0){ | |||
| 1222 | int last_offset = offset; | |||
| 1223 | if (tree) { | |||
| 1224 | wmem_strbuf_t *title = wmem_strbuf_new(pinfo->pool, "SSH Version 2"); | |||
| 1225 | ||||
| 1226 | if (peer_data->enc || peer_data->mac || peer_data->comp) { | |||
| 1227 | wmem_strbuf_append_printf(title, " ("); | |||
| 1228 | if (peer_data->enc) | |||
| 1229 | wmem_strbuf_append_printf(title, "encryption:%s%s", | |||
| 1230 | peer_data->enc, | |||
| 1231 | peer_data->mac || peer_data->comp | |||
| 1232 | ? " " : ""); | |||
| 1233 | if (peer_data->mac) | |||
| 1234 | wmem_strbuf_append_printf(title, "mac:%s%s", | |||
| 1235 | peer_data->mac, | |||
| 1236 | peer_data->comp ? " " : ""); | |||
| 1237 | if (peer_data->comp) | |||
| 1238 | wmem_strbuf_append_printf(title, "compression:%s", | |||
| 1239 | peer_data->comp); | |||
| 1240 | wmem_strbuf_append_printf(title, ")"); | |||
| 1241 | } | |||
| 1242 | ||||
| 1243 | ssh2_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_ssh2, NULL((void*)0), wmem_strbuf_get_str(title)); | |||
| 1244 | } | |||
| 1245 | 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" , 1245, __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); | |||
| 1246 | if ((peer_data->frame_key_start == 0) || | |||
| 1247 | ((peer_data->frame_key_start <= pinfo->num) && | |||
| 1248 | ((peer_data->frame_key_end == 0) || (pinfo->num < peer_data->frame_key_end) || | |||
| 1249 | ((pinfo->num == peer_data->frame_key_end) && (offset < peer_data->frame_key_end_offset))))) { | |||
| 1250 | offset = ssh_dissect_key_exchange(tvb, pinfo, global_data, | |||
| 1251 | offset, ssh2_tree, is_response, | |||
| 1252 | need_desegmentation); | |||
| 1253 | ||||
| 1254 | if (!*need_desegmentation) { | |||
| 1255 | ssh_get_packet_info(pinfo, is_response); | |||
| 1256 | }else{ | |||
| 1257 | break; | |||
| 1258 | } | |||
| 1259 | } else { | |||
| 1260 | if(!*need_desegmentation){ | |||
| 1261 | offset = ssh_try_dissect_encrypted_packet(tvb, pinfo, | |||
| 1262 | &global_data->peer_data[is_response], offset, ssh2_tree); | |||
| 1263 | if (pinfo->desegment_len) { | |||
| 1264 | break; | |||
| 1265 | } | |||
| 1266 | }else{ | |||
| 1267 | break; | |||
| 1268 | } | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | if (ssh2_tree) { | |||
| 1272 | proto_item_set_len(ssh2_tree, offset - last_offset); | |||
| 1273 | } | |||
| 1274 | ||||
| 1275 | remain_length = tvb_captured_length_remaining(tvb, offset); | |||
| 1276 | } | |||
| 1277 | ||||
| 1278 | return offset; | |||
| 1279 | } | |||
| 1280 | static int | |||
| 1281 | ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo, | |||
| 1282 | struct ssh_flow_data *global_data, | |||
| 1283 | int offset, proto_tree *tree, int is_response, | |||
| 1284 | bool_Bool *need_desegmentation) | |||
| 1285 | { | |||
| 1286 | unsigned plen, padding_length, len; | |||
| 1287 | uint8_t msg_code; | |||
| 1288 | unsigned remain_length; | |||
| 1289 | ||||
| 1290 | proto_item *ssh1_tree; | |||
| 1291 | ||||
| 1292 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response]; | |||
| 1293 | ||||
| 1294 | ssh1_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_ssh1, NULL((void*)0), "SSH Version 1"); | |||
| 1295 | ||||
| 1296 | /* | |||
| 1297 | * We use "tvb_ensure_captured_length_remaining()" to make sure there | |||
| 1298 | * actually *is* data remaining. | |||
| 1299 | * | |||
| 1300 | * This means we're guaranteed that "remain_length" is positive. | |||
| 1301 | */ | |||
| 1302 | remain_length = tvb_ensure_captured_length_remaining(tvb, offset); | |||
| 1303 | /* | |||
| 1304 | * Can we do reassembly? | |||
| 1305 | */ | |||
| 1306 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 1307 | /* | |||
| 1308 | * Yes - would an SSH header starting at this offset be split | |||
| 1309 | * across segment boundaries? | |||
| 1310 | */ | |||
| 1311 | if (remain_length < 4) { | |||
| 1312 | /* | |||
| 1313 | * Yes. Tell the TCP dissector where the data for | |||
| 1314 | * this message starts in the data it handed us and | |||
| 1315 | * that we need "some more data." Don't tell it | |||
| 1316 | * exactly how many bytes we need because if/when we | |||
| 1317 | * ask for even more (after the header) that will | |||
| 1318 | * break reassembly. | |||
| 1319 | */ | |||
| 1320 | pinfo->desegment_offset = offset; | |||
| 1321 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 1322 | *need_desegmentation = true1; | |||
| 1323 | return offset; | |||
| 1324 | } | |||
| 1325 | } | |||
| 1326 | plen = tvb_get_ntohl(tvb, offset) ; | |||
| 1327 | ||||
| 1328 | /* | |||
| 1329 | * Amount of random padding. | |||
| 1330 | * | |||
| 1331 | * This is between 1 and 8; if the length is a multiple of 8, | |||
| 1332 | * there are 8 bytes of padding, not 1 byte. | |||
| 1333 | * | |||
| 1334 | * That means this calculation is correct; do not use either | |||
| 1335 | * WS_ROUNDUP_8() or WS_PADDING_TO_8() here. | |||
| 1336 | */ | |||
| 1337 | padding_length = 8 - plen%8; | |||
| 1338 | ||||
| 1339 | ||||
| 1340 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 1341 | if (plen+4+padding_length > remain_length) { | |||
| 1342 | pinfo->desegment_offset = offset; | |||
| 1343 | pinfo->desegment_len = plen+padding_length - remain_length; | |||
| 1344 | *need_desegmentation = true1; | |||
| 1345 | return offset; | |||
| 1346 | } | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | if (plen >= SSH_MAX_PACKET_LEN32768) { | |||
| 1350 | if (ssh1_tree && plen > 0) { | |||
| 1351 | proto_tree_add_uint_format(ssh1_tree, hf_ssh_packet_length, tvb, | |||
| 1352 | offset, 4, plen, "Overly large length %x", plen); | |||
| 1353 | } | |||
| 1354 | plen = remain_length-4-padding_length; | |||
| 1355 | } else { | |||
| 1356 | if (ssh1_tree && plen > 0) { | |||
| 1357 | proto_tree_add_uint(ssh1_tree, hf_ssh_packet_length, tvb, | |||
| 1358 | offset, 4, plen); | |||
| 1359 | } | |||
| 1360 | } | |||
| 1361 | offset+=4; | |||
| 1362 | /* padding length */ | |||
| 1363 | ||||
| 1364 | proto_tree_add_uint(ssh1_tree, hf_ssh_padding_length, tvb, | |||
| 1365 | offset, padding_length, padding_length); | |||
| 1366 | offset += padding_length; | |||
| 1367 | ||||
| 1368 | /* msg_code */ | |||
| 1369 | if ((peer_data->frame_key_start == 0) || | |||
| 1370 | ((peer_data->frame_key_start >= pinfo->num) && (pinfo->num <= peer_data->frame_key_end))) { | |||
| 1371 | msg_code = tvb_get_uint8(tvb, offset); | |||
| 1372 | ||||
| 1373 | proto_tree_add_item(ssh1_tree, hf_ssh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1374 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1375 | val_to_str(msg_code, ssh1_msg_vals, "Unknown (%u)")); | |||
| 1376 | offset += 1; | |||
| 1377 | len = plen -1; | |||
| 1378 | if (!pinfo->fd->visited) { | |||
| 1379 | if (peer_data->frame_key_start == 0) | |||
| 1380 | peer_data->frame_key_start = pinfo->num; | |||
| 1381 | peer_data->frame_key_end = pinfo->num; | |||
| 1382 | } | |||
| 1383 | } else { | |||
| 1384 | len = plen; | |||
| 1385 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (len=%d)", len); | |||
| 1386 | } | |||
| 1387 | /* payload */ | |||
| 1388 | if (ssh1_tree) { | |||
| 1389 | proto_tree_add_item(ssh1_tree, hf_ssh_payload, | |||
| 1390 | tvb, offset, len, ENC_NA0x00000000); | |||
| 1391 | } | |||
| 1392 | offset += len; | |||
| 1393 | ||||
| 1394 | return offset; | |||
| 1395 | } | |||
| 1396 | ||||
| 1397 | static int | |||
| 1398 | ssh_tree_add_mpint(tvbuff_t *tvb, int offset, proto_tree *tree, | |||
| 1399 | int hf_ssh_mpint_selection) | |||
| 1400 | { | |||
| 1401 | unsigned len = tvb_get_ntohl(tvb, offset); | |||
| 1402 | proto_tree_add_uint(tree, hf_ssh_mpint_length, tvb, | |||
| 1403 | offset, 4, len); | |||
| 1404 | offset+=4; | |||
| 1405 | proto_tree_add_item(tree, hf_ssh_mpint_selection, | |||
| 1406 | tvb, offset, len, ENC_NA0x00000000); | |||
| 1407 | return 4+len; | |||
| 1408 | } | |||
| 1409 | ||||
| 1410 | static int | |||
| 1411 | ssh_tree_add_string(tvbuff_t *tvb, int offset, proto_tree *tree, | |||
| 1412 | int hf_ssh_string, int hf_ssh_string_length) | |||
| 1413 | { | |||
| 1414 | unsigned len = tvb_get_ntohl(tvb, offset); | |||
| 1415 | proto_tree_add_uint(tree, hf_ssh_string_length, tvb, | |||
| 1416 | offset, 4, len); | |||
| 1417 | offset+=4; | |||
| 1418 | proto_tree_add_item(tree, hf_ssh_string, | |||
| 1419 | tvb, offset, len, ENC_NA0x00000000); | |||
| 1420 | return 4+len; | |||
| 1421 | } | |||
| 1422 | ||||
| 1423 | static unsigned | |||
| 1424 | ssh_tree_add_hostkey(tvbuff_t *tvb, int offset, proto_tree *parent_tree, | |||
| 1425 | const char *tree_name, int ett_idx, | |||
| 1426 | struct ssh_flow_data *global_data) | |||
| 1427 | { | |||
| 1428 | proto_tree *tree = NULL((void*)0); | |||
| 1429 | proto_item *ti; | |||
| 1430 | int last_offset; | |||
| 1431 | int remaining_len; | |||
| 1432 | unsigned key_len, type_len; | |||
| 1433 | char* key_type; | |||
| 1434 | char *tree_title; | |||
| 1435 | ||||
| 1436 | last_offset = offset; | |||
| 1437 | ||||
| 1438 | key_len = tvb_get_ntohl(tvb, offset); | |||
| 1439 | offset += 4; | |||
| 1440 | ||||
| 1441 | /* Read the key type before creating the tree so we can append it as info. */ | |||
| 1442 | type_len = tvb_get_ntohl(tvb, offset); | |||
| 1443 | offset += 4; | |||
| 1444 | key_type = (char *) tvb_get_string_enc(wmem_packet_scope(), tvb, offset, type_len, ENC_ASCII0x00000000|ENC_NA0x00000000); | |||
| 1445 | ||||
| 1446 | tree_title = wmem_strdup_printf(wmem_packet_scope(), "%s (type: %s)", tree_name, key_type); | |||
| 1447 | tree = proto_tree_add_subtree(parent_tree, tvb, last_offset, key_len + 4, ett_idx, NULL((void*)0), | |||
| 1448 | tree_title); | |||
| 1449 | ||||
| 1450 | ti = proto_tree_add_uint(tree, hf_ssh_hostkey_length, tvb, last_offset, 4, key_len); | |||
| 1451 | ||||
| 1452 | // server host key (K_S / Q) | |||
| 1453 | char *data = (char *)tvb_memdup(wmem_packet_scope(), tvb, last_offset + 4, key_len); | |||
| 1454 | if (global_data) { | |||
| 1455 | // Reset array while REKEY: sanitize server host key blob | |||
| 1456 | global_data->kex_server_host_key_blob = wmem_array_new(wmem_file_scope(), 1); | |||
| 1457 | ssh_hash_buffer_put_string(global_data->kex_server_host_key_blob, data, key_len); | |||
| 1458 | } | |||
| 1459 | ||||
| 1460 | last_offset += 4; | |||
| 1461 | proto_tree_add_uint(tree, hf_ssh_hostkey_type_length, tvb, last_offset, 4, type_len); | |||
| 1462 | proto_tree_add_string(tree, hf_ssh_hostkey_type, tvb, offset, type_len, key_type); | |||
| 1463 | offset += type_len; | |||
| 1464 | ||||
| 1465 | if (0 == strcmp(key_type, "ssh-rsa")) { | |||
| 1466 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_rsa_e); | |||
| 1467 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_rsa_n); | |||
| 1468 | } else if (0 == strcmp(key_type, "ssh-dss")) { | |||
| 1469 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_p); | |||
| 1470 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_q); | |||
| 1471 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_g); | |||
| 1472 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostkey_dsa_y); | |||
| 1473 | } 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-" ) )) { | |||
| 1474 | offset += ssh_tree_add_string(tvb, offset, tree, | |||
| 1475 | hf_ssh_hostkey_ecdsa_curve_id, hf_ssh_hostkey_ecdsa_curve_id_length); | |||
| 1476 | offset += ssh_tree_add_string(tvb, offset, tree, | |||
| 1477 | hf_ssh_hostkey_ecdsa_q, hf_ssh_hostkey_ecdsa_q_length); | |||
| 1478 | } 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") )) { | |||
| 1479 | offset += ssh_tree_add_string(tvb, offset, tree, | |||
| 1480 | hf_ssh_hostkey_eddsa_key, hf_ssh_hostkey_eddsa_key_length); | |||
| 1481 | } else { | |||
| 1482 | remaining_len = key_len - (type_len + 4); | |||
| 1483 | proto_tree_add_item(tree, hf_ssh_hostkey_data, tvb, offset, remaining_len, ENC_NA0x00000000); | |||
| 1484 | offset += remaining_len; | |||
| 1485 | } | |||
| 1486 | ||||
| 1487 | if (last_offset + (int)key_len != offset) { | |||
| 1488 | expert_add_info_format(/*pinfo*/NULL((void*)0), ti, &ei_ssh_packet_decode, "Decoded %d bytes, but hostkey length is %d bytes", offset - last_offset, key_len); | |||
| 1489 | } | |||
| 1490 | return 4+key_len; | |||
| 1491 | } | |||
| 1492 | ||||
| 1493 | static unsigned | |||
| 1494 | ssh_tree_add_hostsignature(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_tree *parent_tree, | |||
| 1495 | const char *tree_name, int ett_idx, | |||
| 1496 | struct ssh_flow_data *global_data) | |||
| 1497 | { | |||
| 1498 | (void)global_data; | |||
| 1499 | proto_tree *tree = NULL((void*)0); | |||
| 1500 | proto_item* ti = NULL((void*)0); | |||
| 1501 | int last_offset; | |||
| 1502 | int offset0 = offset; | |||
| 1503 | int remaining_len; | |||
| 1504 | unsigned sig_len, type_len; | |||
| 1505 | uint8_t* sig_type; | |||
| 1506 | char *tree_title; | |||
| 1507 | ||||
| 1508 | last_offset = offset; | |||
| 1509 | ||||
| 1510 | sig_len = tvb_get_ntohl(tvb, offset); | |||
| 1511 | offset += 4; | |||
| 1512 | ||||
| 1513 | /* Read the signature type before creating the tree so we can append it as info. */ | |||
| 1514 | type_len = tvb_get_ntohl(tvb, offset); | |||
| 1515 | offset += 4; | |||
| 1516 | sig_type = tvb_get_string_enc(pinfo->pool, tvb, offset, type_len, ENC_ASCII0x00000000|ENC_NA0x00000000); | |||
| 1517 | ||||
| 1518 | tree_title = wmem_strdup_printf(pinfo->pool, "%s (type: %s)", tree_name, sig_type); | |||
| 1519 | tree = proto_tree_add_subtree(parent_tree, tvb, last_offset, sig_len + 4, ett_idx, NULL((void*)0), | |||
| 1520 | tree_title); | |||
| 1521 | ||||
| 1522 | ti = proto_tree_add_uint(tree, hf_ssh_hostsig_length, tvb, last_offset, 4, sig_len); | |||
| 1523 | ||||
| 1524 | last_offset += 4; | |||
| 1525 | proto_tree_add_uint(tree, hf_ssh_hostsig_type_length, tvb, last_offset, 4, type_len); | |||
| 1526 | proto_tree_add_string(tree, hf_ssh_hostsig_type, tvb, offset, type_len, sig_type); | |||
| 1527 | offset += type_len; | |||
| 1528 | ||||
| 1529 | if (0 == strcmp(sig_type, "ssh-rsa")) { | |||
| 1530 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostsig_rsa); | |||
| 1531 | } else if (0 == strcmp(sig_type, "ssh-dss")) { | |||
| 1532 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_hostsig_dsa); | |||
| 1533 | // } else if (g_str_has_prefix(sig_type, "ecdsa-sha2-")) { | |||
| 1534 | // offset += ssh_tree_add_string(tvb, offset, tree, | |||
| 1535 | // hf_ssh_hostkey_ecdsa_curve_id, hf_ssh_hostkey_ecdsa_curve_id_length); | |||
| 1536 | // ssh_tree_add_string(tvb, offset, tree, | |||
| 1537 | // hf_ssh_hostkey_ecdsa_q, hf_ssh_hostkey_ecdsa_q_length); | |||
| 1538 | // } else if (g_str_has_prefix(sig_type, "ssh-ed")) { | |||
| 1539 | // ssh_tree_add_string(tvb, offset, tree, | |||
| 1540 | // hf_ssh_hostkey_eddsa_key, hf_ssh_hostkey_eddsa_key_length); | |||
| 1541 | } else { | |||
| 1542 | remaining_len = sig_len - (type_len + 4); | |||
| 1543 | proto_tree_add_item(tree, hf_ssh_hostsig_data, tvb, offset, remaining_len, ENC_NA0x00000000); | |||
| 1544 | offset += remaining_len; | |||
| 1545 | } | |||
| 1546 | ||||
| 1547 | if(offset-offset0!=(int)(4+sig_len)){ | |||
| 1548 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", offset-offset0, sig_len); | |||
| 1549 | } | |||
| 1550 | ||||
| 1551 | return 4+sig_len; | |||
| 1552 | } | |||
| 1553 | ||||
| 1554 | static int | |||
| 1555 | ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo, | |||
| 1556 | struct ssh_flow_data *global_data, | |||
| 1557 | int offset, proto_tree *tree, int is_response, | |||
| 1558 | bool_Bool *need_desegmentation) | |||
| 1559 | { | |||
| 1560 | unsigned plen, len; | |||
| 1561 | uint8_t padding_length; | |||
| 1562 | unsigned remain_length; | |||
| 1563 | int last_offset = offset; | |||
| 1564 | unsigned msg_code; | |||
| 1565 | ||||
| 1566 | proto_item *ti; | |||
| 1567 | proto_item *key_ex_tree = NULL((void*)0); | |||
| 1568 | const char *key_ex_title = "Key Exchange"; | |||
| 1569 | ||||
| 1570 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response]; | |||
| 1571 | ||||
| 1572 | if (PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1573 | 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" , 1573, __func__, "SSH: SECOND PASS dissecting keys -for Wireshark UI- frame %u" , pinfo->num); } } while (0); | |||
| 1574 | } | |||
| 1575 | /* This is after the identification string (Protocol Version Exchange) | |||
| 1576 | * but before the first key exchange has completed, so we expect the SSH | |||
| 1577 | * packets to be unencrypted, and to contain KEX related messages. | |||
| 1578 | * | |||
| 1579 | * XXX - Without the "strict kex" extension, other messages are allowed; | |||
| 1580 | * most don't make sense (SSH_MSG_IGNORE and SSH_MSG_DEBUG might), but we | |||
| 1581 | * could dissect them and add them to the tree. | |||
| 1582 | * | |||
| 1583 | * XXX - Could we combine this with ssh_dissect_decrypted_packet, with a | |||
| 1584 | * flag to indicate whether we're before the initial key exchange? | |||
| 1585 | */ | |||
| 1586 | ||||
| 1587 | /* | |||
| 1588 | * We use "tvb_ensure_captured_length_remaining()" to make sure there | |||
| 1589 | * actually *is* data remaining. | |||
| 1590 | * | |||
| 1591 | * This means we're guaranteed that "remain_length" is positive. | |||
| 1592 | */ | |||
| 1593 | remain_length = tvb_ensure_captured_length_remaining(tvb, offset); | |||
| 1594 | /* | |||
| 1595 | * Can we do reassembly? | |||
| 1596 | */ | |||
| 1597 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 1598 | /* | |||
| 1599 | * Yes - would an SSH header starting at this offset | |||
| 1600 | * be split across segment boundaries? | |||
| 1601 | */ | |||
| 1602 | if (remain_length < 4) { | |||
| 1603 | /* | |||
| 1604 | * Yes. Tell the TCP dissector where the data for | |||
| 1605 | * this message starts in the data it handed us and | |||
| 1606 | * that we need "some more data." Don't tell it | |||
| 1607 | * exactly how many bytes we need because if/when we | |||
| 1608 | * ask for even more (after the header) that will | |||
| 1609 | * break reassembly. | |||
| 1610 | */ | |||
| 1611 | pinfo->desegment_offset = offset; | |||
| 1612 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 1613 | *need_desegmentation = true1; | |||
| 1614 | return offset; | |||
| 1615 | } | |||
| 1616 | } | |||
| 1617 | plen = tvb_get_ntohl(tvb, offset) ; | |||
| 1618 | ||||
| 1619 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 1620 | if (plen +4 > remain_length) { | |||
| 1621 | pinfo->desegment_offset = offset; | |||
| 1622 | pinfo->desegment_len = plen+4 - remain_length; | |||
| 1623 | *need_desegmentation = true1; | |||
| 1624 | return offset; | |||
| 1625 | } | |||
| 1626 | } | |||
| 1627 | /* | |||
| 1628 | * Need to check plen > 0x80000000 here | |||
| 1629 | */ | |||
| 1630 | ||||
| 1631 | ti = proto_tree_add_uint(tree, hf_ssh_packet_length, tvb, | |||
| 1632 | offset, 4, plen); | |||
| 1633 | if (plen >= SSH_MAX_PACKET_LEN32768) { | |||
| 1634 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Overly large number %d", plen); | |||
| 1635 | plen = remain_length-4; | |||
| 1636 | ||||
| 1637 | /* XXX - Mark as Continuation Data and return without incrementing? | |||
| 1638 | * Or do so *before* using this length to desegment? */ | |||
| 1639 | } | |||
| 1640 | offset+=4; | |||
| 1641 | ||||
| 1642 | ssh_packet_info_t *packet = ssh_get_packet_info(pinfo, is_response); | |||
| 1643 | ||||
| 1644 | int record_id = tvb_raw_offset(tvb)+offset; | |||
| 1645 | ssh_message_info_t *message; | |||
| 1646 | message = ssh_get_message(pinfo, record_id); | |||
| 1647 | if (!message) { | |||
| 1648 | message = wmem_new0(wmem_file_scope(), ssh_message_info_t)((ssh_message_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_message_info_t))); | |||
| 1649 | message->sequence_number = peer_data->sequence_number++; | |||
| 1650 | message->id = record_id; | |||
| 1651 | /* No data, and no MAC, as is this is before encryption starts. */ | |||
| 1652 | message->next = NULL((void*)0); | |||
| 1653 | ssh_debug_printf("%s->sequence_number++ > %d\n", is_response?"server":"client", peer_data->sequence_number); | |||
| 1654 | ||||
| 1655 | ssh_message_info_t **pmessage = &packet->messages; | |||
| 1656 | while(*pmessage){ | |||
| 1657 | pmessage = &(*pmessage)->next; | |||
| 1658 | } | |||
| 1659 | *pmessage = message; | |||
| 1660 | } | |||
| 1661 | ||||
| 1662 | /* padding length */ | |||
| 1663 | padding_length = tvb_get_uint8(tvb, offset); | |||
| 1664 | proto_tree_add_uint(tree, hf_ssh_padding_length, tvb, offset, 1, padding_length); | |||
| 1665 | offset += 1; | |||
| 1666 | ||||
| 1667 | if (global_data->kex) | |||
| 1668 | key_ex_title = wmem_strdup_printf(pinfo->pool, "%s (method:%s)", key_ex_title, global_data->kex); | |||
| 1669 | key_ex_tree = proto_tree_add_subtree(tree, tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), key_ex_title); | |||
| 1670 | ||||
| 1671 | /* msg_code */ | |||
| 1672 | msg_code = tvb_get_uint8(tvb, offset); | |||
| 1673 | ||||
| 1674 | if (msg_code >= 30 && msg_code < 40) { | |||
| 1675 | offset = global_data->kex_specific_dissector(msg_code, tvb, pinfo, | |||
| 1676 | offset, key_ex_tree, global_data); | |||
| 1677 | } else { | |||
| 1678 | proto_tree_add_item(key_ex_tree, hf_ssh2_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1679 | offset += 1; | |||
| 1680 | ||||
| 1681 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1682 | val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 1683 | ||||
| 1684 | /* 16 bytes cookie */ | |||
| 1685 | switch(msg_code) | |||
| 1686 | { | |||
| 1687 | case SSH_MSG_KEXINIT20: | |||
| 1688 | offset = ssh_dissect_key_init(tvb, pinfo, offset, key_ex_tree, is_response, global_data); | |||
| 1689 | if ((peer_data->frame_key_start == 0) && (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))) { | |||
| 1690 | peer_data->frame_key_start = pinfo->num; | |||
| 1691 | } | |||
| 1692 | break; | |||
| 1693 | case SSH_MSG_NEWKEYS21: | |||
| 1694 | if (peer_data->frame_key_end == 0) { | |||
| 1695 | peer_data->frame_key_end = pinfo->num; | |||
| 1696 | peer_data->frame_key_end_offset = offset; | |||
| 1697 | ||||
| 1698 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1699 | /* "After sending or receiving a SSH2_MSG_NEWKEYS message, | |||
| 1700 | * reset the packet sequence number to zero. This behaviour | |||
| 1701 | * persists for the duration of the connection (i.e. not | |||
| 1702 | * just the first SSH2_MSG_NEWKEYS) */ | |||
| 1703 | if (global_data->ext_kex_strict) { | |||
| 1704 | peer_data->sequence_number = 0; | |||
| 1705 | ssh_debug_printf("%s->sequence_number reset to 0 (Strict KEX)\n", is_response?"server":"client"); | |||
| 1706 | } | |||
| 1707 | } | |||
| 1708 | ||||
| 1709 | // the client sent SSH_MSG_NEWKEYS | |||
| 1710 | if (!is_response) { | |||
| 1711 | ssh_debug_printf("Activating new keys for CLIENT => SERVER\n"); | |||
| 1712 | ssh_decryption_setup_cipher(&global_data->peer_data[CLIENT_PEER_DATA0], &global_data->new_keys[0], &global_data->new_keys[2]); | |||
| 1713 | ssh_decryption_setup_mac(&global_data->peer_data[CLIENT_PEER_DATA0], &global_data->new_keys[4]); | |||
| 1714 | }else{ | |||
| 1715 | ssh_debug_printf("Activating new keys for SERVER => CLIENT\n"); | |||
| 1716 | ssh_decryption_setup_cipher(&global_data->peer_data[SERVER_PEER_DATA1], &global_data->new_keys[1], &global_data->new_keys[3]); | |||
| 1717 | ssh_decryption_setup_mac(&global_data->peer_data[SERVER_PEER_DATA1], &global_data->new_keys[5]); | |||
| 1718 | } | |||
| 1719 | } | |||
| 1720 | break; | |||
| 1721 | } | |||
| 1722 | } | |||
| 1723 | ||||
| 1724 | len = plen+4-padding_length-(offset-last_offset); | |||
| 1725 | if (len > 0) { | |||
| 1726 | proto_tree_add_item(key_ex_tree, hf_ssh_payload, tvb, offset, len, ENC_NA0x00000000); | |||
| 1727 | } | |||
| 1728 | offset += len; | |||
| 1729 | ||||
| 1730 | /* padding */ | |||
| 1731 | proto_tree_add_item(tree, hf_ssh_padding_string, tvb, offset, padding_length, ENC_NA0x00000000); | |||
| 1732 | offset+= padding_length; | |||
| 1733 | ti = proto_tree_add_uint(tree, hf_ssh_seq_num, tvb, offset, 0, message->sequence_number); | |||
| 1734 | proto_item_set_generated(ti); | |||
| 1735 | ||||
| 1736 | return offset; | |||
| 1737 | } | |||
| 1738 | ||||
| 1739 | static int ssh_dissect_kex_dh(uint8_t msg_code, tvbuff_t *tvb, | |||
| 1740 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 1741 | struct ssh_flow_data *global_data) | |||
| 1742 | { | |||
| 1743 | proto_tree_add_item(tree, hf_ssh2_kex_dh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1744 | offset += 1; | |||
| 1745 | ||||
| 1746 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1747 | val_to_str(msg_code, ssh2_kex_dh_msg_vals, "Unknown (%u)")); | |||
| 1748 | ||||
| 1749 | switch (msg_code) { | |||
| 1750 | case SSH_MSG_KEXDH_INIT30: | |||
| 1751 | // e (client ephemeral key public part) | |||
| 1752 | if (!ssh_read_e(tvb, offset, global_data)) { | |||
| 1753 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2, | |||
| 1754 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset)); | |||
| 1755 | } | |||
| 1756 | ||||
| 1757 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_e); | |||
| 1758 | break; | |||
| 1759 | ||||
| 1760 | case SSH_MSG_KEXDH_REPLY31: | |||
| 1761 | offset += ssh_tree_add_hostkey(tvb, offset, tree, "KEX host key", | |||
| 1762 | ett_key_exchange_host_key, global_data); | |||
| 1763 | ||||
| 1764 | // f (server ephemeral key public part), K_S (host key) | |||
| 1765 | if (!ssh_read_f(tvb, offset, global_data)) { | |||
| 1766 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2, | |||
| 1767 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset)); | |||
| 1768 | } | |||
| 1769 | ssh_choose_enc_mac(global_data); | |||
| 1770 | ssh_keylog_hash_write_secret(global_data); | |||
| 1771 | ||||
| 1772 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_f); | |||
| 1773 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature", | |||
| 1774 | ett_key_exchange_host_sig, global_data); | |||
| 1775 | break; | |||
| 1776 | } | |||
| 1777 | ||||
| 1778 | return offset; | |||
| 1779 | } | |||
| 1780 | ||||
| 1781 | static int ssh_dissect_kex_dh_gex(uint8_t msg_code, tvbuff_t *tvb, | |||
| 1782 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 1783 | struct ssh_flow_data *global_data) | |||
| 1784 | { | |||
| 1785 | proto_tree_add_item(tree, hf_ssh2_kex_dh_gex_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1786 | offset += 1; | |||
| 1787 | ||||
| 1788 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1789 | val_to_str(msg_code, ssh2_kex_dh_gex_msg_vals, "Unknown (%u)")); | |||
| 1790 | ||||
| 1791 | switch (msg_code) { | |||
| 1792 | case SSH_MSG_KEX_DH_GEX_REQUEST_OLD30: | |||
| 1793 | proto_tree_add_item(tree, hf_ssh_dh_gex_nbits, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 1794 | offset += 4; | |||
| 1795 | break; | |||
| 1796 | ||||
| 1797 | case SSH_MSG_KEX_DH_GEX_GROUP31: | |||
| 1798 | // p (Group modulo) | |||
| 1799 | global_data->kex_gex_p = ssh_read_mpint(tvb, offset); | |||
| 1800 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_gex_p); | |||
| 1801 | // g (Group generator) | |||
| 1802 | global_data->kex_gex_g = ssh_read_mpint(tvb, offset); | |||
| 1803 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_gex_g); | |||
| 1804 | break; | |||
| 1805 | ||||
| 1806 | case SSH_MSG_KEX_DH_GEX_INIT32: | |||
| 1807 | // e (Client public key) | |||
| 1808 | if (!ssh_read_e(tvb, offset, global_data)) { | |||
| 1809 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2, | |||
| 1810 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset)); | |||
| 1811 | } | |||
| 1812 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_e); | |||
| 1813 | break; | |||
| 1814 | ||||
| 1815 | case SSH_MSG_KEX_DH_GEX_REPLY33: | |||
| 1816 | offset += ssh_tree_add_hostkey(tvb, offset, tree, "KEX host key", | |||
| 1817 | ett_key_exchange_host_key, global_data); | |||
| 1818 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1819 | ssh_read_f(tvb, offset, global_data); | |||
| 1820 | // f (server ephemeral key public part), K_S (host key) | |||
| 1821 | ssh_choose_enc_mac(global_data); | |||
| 1822 | ssh_keylog_hash_write_secret(global_data); | |||
| 1823 | } | |||
| 1824 | offset += ssh_tree_add_mpint(tvb, offset, tree, hf_ssh_dh_f); | |||
| 1825 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature", | |||
| 1826 | ett_key_exchange_host_sig, global_data); | |||
| 1827 | break; | |||
| 1828 | ||||
| 1829 | case SSH_MSG_KEX_DH_GEX_REQUEST34:{ | |||
| 1830 | ||||
| 1831 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1832 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_min, tvb_get_ntohl(tvb, offset)); | |||
| 1833 | } | |||
| 1834 | proto_tree_add_item(tree, hf_ssh_dh_gex_min, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 1835 | offset += 4; | |||
| 1836 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1837 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_req, tvb_get_ntohl(tvb, offset)); | |||
| 1838 | } | |||
| 1839 | proto_tree_add_item(tree, hf_ssh_dh_gex_nbits, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 1840 | offset += 4; | |||
| 1841 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1842 | ssh_hash_buffer_put_uint32(global_data->kex_gex_bits_max, tvb_get_ntohl(tvb, offset)); | |||
| 1843 | } | |||
| 1844 | proto_tree_add_item(tree, hf_ssh_dh_gex_max, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 1845 | offset += 4; | |||
| 1846 | break; | |||
| 1847 | } | |||
| 1848 | } | |||
| 1849 | ||||
| 1850 | return offset; | |||
| 1851 | } | |||
| 1852 | ||||
| 1853 | static int | |||
| 1854 | ssh_dissect_kex_ecdh(uint8_t msg_code, tvbuff_t *tvb, | |||
| 1855 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 1856 | struct ssh_flow_data *global_data) | |||
| 1857 | { | |||
| 1858 | proto_tree_add_item(tree, hf_ssh2_kex_ecdh_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1859 | offset += 1; | |||
| 1860 | ||||
| 1861 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1862 | val_to_str(msg_code, ssh2_kex_ecdh_msg_vals, "Unknown (%u)")); | |||
| 1863 | ||||
| 1864 | switch (msg_code) { | |||
| 1865 | case SSH_MSG_KEX_ECDH_INIT30: | |||
| 1866 | if (!ssh_read_e(tvb, offset, global_data)) { | |||
| 1867 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2, | |||
| 1868 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset)); | |||
| 1869 | } | |||
| 1870 | ||||
| 1871 | offset += ssh_tree_add_string(tvb, offset, tree, hf_ssh_ecdh_q_c, hf_ssh_ecdh_q_c_length); | |||
| 1872 | break; | |||
| 1873 | ||||
| 1874 | case SSH_MSG_KEX_ECDH_REPLY31: | |||
| 1875 | offset += ssh_tree_add_hostkey(tvb, offset, tree, "KEX host key", | |||
| 1876 | ett_key_exchange_host_key, global_data); | |||
| 1877 | ||||
| 1878 | if (!ssh_read_f(tvb, offset, global_data)){ | |||
| 1879 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 2, | |||
| 1880 | "Invalid key length: %u", tvb_get_ntohl(tvb, offset)); | |||
| 1881 | } | |||
| 1882 | ||||
| 1883 | ssh_choose_enc_mac(global_data); | |||
| 1884 | ssh_keylog_hash_write_secret(global_data); | |||
| 1885 | ||||
| 1886 | offset += ssh_tree_add_string(tvb, offset, tree, hf_ssh_ecdh_q_s, hf_ssh_ecdh_q_s_length); | |||
| 1887 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature", | |||
| 1888 | ett_key_exchange_host_sig, global_data); | |||
| 1889 | break; | |||
| 1890 | } | |||
| 1891 | ||||
| 1892 | return offset; | |||
| 1893 | } | |||
| 1894 | ||||
| 1895 | static int ssh_dissect_kex_hybrid(uint8_t msg_code, tvbuff_t *tvb, | |||
| 1896 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 1897 | struct ssh_flow_data *global_data _U___attribute__((unused))) | |||
| 1898 | { | |||
| 1899 | proto_tree_add_item(tree, hf_ssh2_kex_hybrid_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1900 | offset += 1; | |||
| 1901 | ||||
| 1902 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1903 | val_to_str(msg_code, ssh2_kex_hybrid_msg_vals, "Unknown (%u)")); | |||
| 1904 | ||||
| 1905 | const char *kex_name = global_data->kex; | |||
| 1906 | switch (msg_code) { | |||
| 1907 | case SSH_MSG_KEX_HYBRID_INIT30: | |||
| 1908 | expert_add_info(pinfo, NULL((void*)0), &ei_ssh2_kex_hybrid_msg_code_unknown); | |||
| 1909 | expert_add_info(pinfo, NULL((void*)0), &ei_ssh2_kex_hybrid_msg_code); | |||
| 1910 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1911 | ws_warning("KEX_HYBRID detected: KEX ALGORITHM = %s", kex_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_WARNING, "epan/dissectors/packet-ssh.c" , 1911, __func__, "KEX_HYBRID detected: KEX ALGORITHM = %s", kex_name ); } } while (0); | |||
| 1912 | ws_warning("KEX_HYBRID KEM support in Wireshark / TShark SSH dissector may be missing, partial or experimental")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_WARNING, "epan/dissectors/packet-ssh.c" , 1912, __func__, "KEX_HYBRID KEM support in Wireshark / TShark SSH dissector may be missing, partial or experimental" ); } } while (0); | |||
| 1913 | } | |||
| 1914 | ws_noisy(">>> KEX_HYBRID KEM detected: 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" , 1914, __func__, ">>> KEX_HYBRID KEM detected: msg_code = %u, offset = %d, kex = %s" , msg_code, offset, kex_name); } } while (0); | |||
| 1915 | break; | |||
| 1916 | case SSH_MSG_KEX_HYBRID_REPLY31: | |||
| 1917 | ws_noisy(">>> KEX_HYBRID KEM detected: 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" , 1917, __func__, ">>> KEX_HYBRID KEM detected: msg_code = %u, offset = %d, kex = %s" , msg_code, offset, kex_name); } } while (0); | |||
| 1918 | break; | |||
| 1919 | } | |||
| 1920 | ||||
| 1921 | return offset; | |||
| 1922 | } | |||
| 1923 | ||||
| 1924 | /* | |||
| 1925 | * === Hybrid KEX Dissection Strategy for Post-Quantum algorithms === | |||
| 1926 | * | |||
| 1927 | * This 3 functions: | |||
| 1928 | * | |||
| 1929 | * - ssh_dissect_kex_pq_hybrid() | |||
| 1930 | * - ssh_read_e_pq() | |||
| 1931 | * - ssh_read_f_pq() | |||
| 1932 | * | |||
| 1933 | * handles the dissection of server key exchange payloads for the | |||
| 1934 | * post-quantum hybrid key exchange method: | |||
| 1935 | * - sntrup761x25519-sha512 | |||
| 1936 | * - mlkem768x25519-sha256 | |||
| 1937 | * | |||
| 1938 | * /!\ Rationale for implementation approach: | |||
| 1939 | * | |||
| 1940 | * OpenSSH encodes the server's ephemeral key (`Q_S`) as a single SSH `string` | |||
| 1941 | * which contains both the post-quantum KEM ciphertext (from sntrup761 / mlkem768) | |||
| 1942 | * and the traditional Curve25519 public key. Therefore, we parse one string | |||
| 1943 | * | |||
| 1944 | * sntrup761x25519: | |||
| 1945 | * - PQ ciphertext: 1039 bytes (sntrup761) | |||
| 1946 | * - Curve25519 pubkey: 32 bytes | |||
| 1947 | * | |||
| 1948 | * mlkem768x25519: | |||
| 1949 | * - PQ ciphertext: 1152 bytes (mlkem768) | |||
| 1950 | * - Curve25519 pubkey: 32 bytes | |||
| 1951 | * | |||
| 1952 | * This matches how OpenSSH serializes the hybrid key material, and allows Wireshark | |||
| 1953 | * to compute the correct key exchange hash and derive session keys accurately. | |||
| 1954 | * | |||
| 1955 | * /!\ This design is necessary for live decryption support in Wireshark and TShark. | |||
| 1956 | * | |||
| 1957 | * References: | |||
| 1958 | * - RFC 4253: The SSH Transport Layer Protocol | |||
| 1959 | * - Section 6: string encoding format | |||
| 1960 | * - Section 7.2: Key derivation | |||
| 1961 | * - RFC 8731: Secure Shell (SSH) Key Exchange Method using Curve25519 | |||
| 1962 | * - Internet-Draft on sntrup761x25519-sha512 | |||
| 1963 | * - https://www.ietf.org/archive/id/draft-josefsson-ntruprime-ssh-02.html | |||
| 1964 | * - Internet-Draft on mlkem768x25519-sha256 | |||
| 1965 | * - https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-kem | |||
| 1966 | * - OpenSSH Hybrid KEM Implementation (sntrup761x25519-sha512 / mlkem768x25519-sha256) | |||
| 1967 | * - https://github.com/openssh/openssh-portable/blob/master/kexc25519.c | |||
| 1968 | * - https://github.com/openssh/openssh-portable/blob/master/kexsntrup761x25519.c | |||
| 1969 | * - https://github.com/openssh/openssh-portable/blob/master/kexmlkem768x25519.c | |||
| 1970 | * | |||
| 1971 | * These hybrid KEX format are experimental and not yet standardized via the IETF. | |||
| 1972 | * The parsing logic here is tailored to match OpenSSH's real-world behavior to | |||
| 1973 | * ensure accurate decryption support in Wireshark. | |||
| 1974 | */ | |||
| 1975 | ||||
| 1976 | static int | |||
| 1977 | ssh_dissect_kex_pq_hybrid(uint8_t msg_code, tvbuff_t *tvb, | |||
| 1978 | packet_info *pinfo, int offset, proto_tree *tree, | |||
| 1979 | struct ssh_flow_data *global_data) | |||
| 1980 | { | |||
| 1981 | // SSH PACKET STRUCTURE RFC4253 (e.g. packet of 1228 bytes payload) | |||
| 1982 | // [00 00 04 cc] → ssh payload blob length field in tcp packet (e.g. 1228=0x04cc): 4 bytes | |||
| 1983 | // [1228 bytes of SSH PAYLOAD BLOB] → ssh payload blob field: 1228 bytes | |||
| 1984 | ||||
| 1985 | // Add the message code byte (first field in packet) to the GUI tree. | |||
| 1986 | proto_tree_add_item(tree, hf_ssh2_kex_hybrid_msg_code, tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 1987 | offset += 1; // Move offset past the msg_code byte. | |||
| 1988 | ||||
| 1989 | // Add a descriptive string to Wireshark's "Info" column. | |||
| 1990 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), | |||
| 1991 | val_to_str(msg_code, ssh2_kex_hybrid_msg_vals, "Unknown (%u)")); | |||
| 1992 | ||||
| 1993 | if (msg_code == SSH_MSG_KEX_HYBRID_INIT30) { | |||
| ||||
| 1994 | // Print warning when sntrup761x25519-sha512 or mlkem768x25519-sha256 is detected in KEX | |||
| 1995 | // This implementation currently rely on SHARED_SECRET only and do not work with PRIVATE_KEY | |||
| 1996 | const char *kex_name = global_data->kex; | |||
| 1997 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 1998 | 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" , 1998, __func__, "POST-QUANTUM KEX_HYBRID detected: KEX = %s" , kex_name); } } while (0); | |||
| 1999 | 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" , 1999, __func__, "SHARED_SECRET decryption is supported - PRIVATE_KEY decryption is not supported" ); } } while (0); | |||
| 2000 | } | |||
| 2001 | // Print noisy debug info | |||
| 2002 | 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" , 2002, __func__, ">>> HYBRID KEM: msg_code = %u, offset = %d, kex = %s" , msg_code, offset, kex_name); } } while (0); | |||
| 2003 | } | |||
| 2004 | ||||
| 2005 | switch (msg_code) { | |||
| 2006 | ||||
| 2007 | // Client Key Exchange INIT | |||
| 2008 | case SSH_MSG_KEX_HYBRID_INIT30: { | |||
| 2009 | ||||
| 2010 | // SNTRUP761X25519: RFC4253 SSH "string" (binary-encoded structure) | |||
| 2011 | // [00 00 04 a6] → length = 1190 (0x04a6) | |||
| 2012 | // [32 bytes of X25519 pubkey] → ephemeral X25519 public key | |||
| 2013 | // [1158 bytes PQ blob] → sntrup761 encapsulated client key | |||
| 2014 | ||||
| 2015 | // MLKEM768X25519: RFC4253 SSH "string" (binary-encoded structure) | |||
| 2016 | // [00 00 04 c0] → length = 1216 (0x04c0) | |||
| 2017 | // [32 bytes of X25519 pubkey] → ephemeral X25519 public key | |||
| 2018 | // [1184 bytes PQ blob] → mlkem768 encapsulated client key | |||
| 2019 | ||||
| 2020 | 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" , 2020, __func__, "CLIENT INIT follow offset pointer - absolute offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2021 | int new_offset_client = ssh_read_e_pq(tvb, offset, global_data); | |||
| 2022 | if (new_offset_client < 0) { | |||
| 2023 | uint32_t bad_len = tvb_get_ntohl(tvb, offset); | |||
| 2024 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4, | |||
| 2025 | "Invalid PQ client key length: %u", bad_len); | |||
| 2026 | 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" , 2026, __func__, "ExpertInfo: Invalid PQ client key length at offset %d: %u" , offset, bad_len); } } while (0); | |||
| 2027 | ||||
| 2028 | return offset + 4; | |||
| 2029 | ws_debug("CLIENT INIT validate PQ client key length - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2029, __func__, "CLIENT INIT validate PQ client key length - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2030 | } | |||
| 2031 | ||||
| 2032 | // PQ-hybrid KEMs cannot use ssh_add_tree_string => manual dissection | |||
| 2033 | // Get PQ blob size | |||
| 2034 | proto_tree *pq_tree = NULL((void*)0); | |||
| 2035 | uint32_t pq_len = tvb_get_ntohl(tvb, offset); | |||
| 2036 | ws_debug("CLIENT INIT PQ blob length - pq_len: %d", pq_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2036, __func__, "CLIENT INIT PQ blob length - pq_len: %d", pq_len ); } } while (0); // debug trace pq_len | |||
| 2037 | ||||
| 2038 | // Add a subtree for dissecting PQ blob | |||
| 2039 | proto_tree_add_item(tree, hf_ssh_hybrid_blob_client_len, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); // add blob length | |||
| 2040 | offset += 4; // shift length field | |||
| 2041 | pq_tree = proto_tree_add_subtree(tree, tvb, offset, pq_len, ett_ssh_pqhybrid_client, NULL((void*)0), "Hybrid Key Exchange Blob Client"); | |||
| 2042 | 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" , 2042, __func__, "CLIENT INIT add PQ Hybrid subtree - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2043 | ||||
| 2044 | // Make a new tvb for just the PQ blob string contents | |||
| 2045 | tvbuff_t *string_tvb = tvb_new_subset_length(tvb, offset, pq_len); | |||
| 2046 | ||||
| 2047 | // Now dissect string inside the blob and add PQ server response and ECDH Q_S to GUI subtree | |||
| 2048 | proto_tree_add_item(pq_tree, hf_ssh_ecdh_q_c, string_tvb, 0, 32, ENC_NA0x00000000); | |||
| 2049 | proto_tree_add_item(pq_tree, hf_ssh_pq_kem_client, string_tvb, 32, pq_len - 32, ENC_NA0x00000000); | |||
| 2050 | ||||
| 2051 | // retrieve offset from read_f_pq() to shift blob length and consume packet | |||
| 2052 | offset = new_offset_client; | |||
| 2053 | 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" , 2053, __func__, "CLIENT INIT shift PQ blob - offset: %d", offset ); } } while (0); // debug trace offset | |||
| 2054 | break; | |||
| 2055 | } | |||
| 2056 | ||||
| 2057 | // Server Reply Message | |||
| 2058 | case SSH_MSG_KEX_HYBRID_REPLY31: { | |||
| 2059 | ||||
| 2060 | // SNTRUP761X25519: RFC4253 SSH "string" (binary-encoded structure) | |||
| 2061 | // [00 00 00 0b] → length = 11 // blob offset:0 absolute offset:6 | |||
| 2062 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519" | |||
| 2063 | // [00 00 00 20] → length = 32 | |||
| 2064 | // [32 bytes of public key] → public key | |||
| 2065 | // [00 00 04 2f] → length = 1071 | |||
| 2066 | // [1071 bytes PQ blob] → PQ blob (32 x25519 + 1039 sntrup761) | |||
| 2067 | ||||
| 2068 | // MLKEM768X25519: RFC4253 SSH "string" (binary-encoded structure) | |||
| 2069 | // [00 00 00 0b] → length = 11 // blob offset:0 absolute offset:6 | |||
| 2070 | // [73 73 68 2d 65 64 32 35 35 31 39] → "ssh-ed25519" | |||
| 2071 | // [00 00 00 20] → length = 32 | |||
| 2072 | // [32 bytes of X25519 pubkey] → ephemeral server X25519 public key | |||
| 2073 | // [00 00 04 a0] → length = 1184 (0x04a0) | |||
| 2074 | // [1184 bytes PQ blob] → PQ blob (32 x25519 + 1152 kyber768) | |||
| 2075 | ||||
| 2076 | 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" , 2076, __func__, "SERVER REPLY follow offset pointer - absolute offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2077 | ||||
| 2078 | // Add the host key used to sign the key exchange to the GUI tree. | |||
| 2079 | offset += ssh_tree_add_hostkey(tvb, offset, tree, "KEX host key", ett_key_exchange_host_key, global_data); | |||
| 2080 | ||||
| 2081 | 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" , 2081, __func__, "SERVER REPLY add hostkey tree - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2082 | ||||
| 2083 | int new_offset_server = ssh_read_f_pq(tvb, offset, global_data); | |||
| 2084 | if (new_offset_server < 0) { | |||
| 2085 | uint32_t bad_len = tvb_get_ntohl(tvb, offset); | |||
| 2086 | proto_tree_add_expert_format(tree, pinfo, &ei_ssh_invalid_keylen, tvb, offset, 4, | |||
| 2087 | "Invalid PQ server key length: %u", bad_len); | |||
| 2088 | 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" , 2088, __func__, "ExpertInfo: Invalid PQ server key length at offset %d: %u" , offset, bad_len); } } while (0); | |||
| 2089 | ||||
| 2090 | return offset + 4; | |||
| 2091 | ws_debug("SERVER REPLY validate PQ server key length - offset: %d", offset)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2091, __func__, "SERVER REPLY validate PQ server key length - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2092 | } | |||
| 2093 | ||||
| 2094 | // Select encryption and MAC based on negotiated algorithms. | |||
| 2095 | ssh_choose_enc_mac(global_data); | |||
| 2096 | ||||
| 2097 | // Write session secrets to keylog file (if enabled). | |||
| 2098 | ssh_keylog_hash_write_secret(global_data); | |||
| 2099 | ||||
| 2100 | // PQ-hybrid KEMs cannot use ssh_add_tree_string => manual dissection | |||
| 2101 | // Get PQ blob size | |||
| 2102 | proto_tree *pq_tree = NULL((void*)0); | |||
| 2103 | uint32_t pq_len = tvb_get_ntohl(tvb, offset); | |||
| 2104 | ws_debug("SERVER REPLY PQ blob length - pq_len: %d", pq_len)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2104, __func__, "SERVER REPLY PQ blob length - pq_len: %d", pq_len); } } while (0); // debug trace pq_len | |||
| 2105 | ||||
| 2106 | // Add a subtree for dissecting PQ blob | |||
| 2107 | proto_tree_add_item(tree, hf_ssh_hybrid_blob_server_len, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); // add blob length | |||
| 2108 | offset += 4; // shift length field | |||
| 2109 | pq_tree = proto_tree_add_subtree(tree, tvb, offset, pq_len, ett_ssh_pqhybrid_server, NULL((void*)0), "Hybrid Key Exchange Blob Server"); | |||
| 2110 | 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" , 2110, __func__, "SERVER REPLY add PQ Hybrid subtree - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2111 | ||||
| 2112 | // Make a new tvb for just the PQ blob string contents | |||
| 2113 | tvbuff_t *string_tvb = tvb_new_subset_length(tvb, offset, pq_len); | |||
| 2114 | ||||
| 2115 | // Now dissect string inside the blob and add PQ server response and ECDH Q_S to GUI subtree | |||
| 2116 | proto_tree_add_item(pq_tree, hf_ssh_ecdh_q_s, string_tvb, 0, 32, ENC_NA0x00000000); | |||
| 2117 | proto_tree_add_item(pq_tree, hf_ssh_pq_kem_server, string_tvb, 32, pq_len - 32, ENC_NA0x00000000); | |||
| 2118 | ||||
| 2119 | // retrieve offset from read_f_pq() to shift blob length | |||
| 2120 | offset = new_offset_server; | |||
| 2121 | 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" , 2121, __func__, "SERVER REPLY shift PQ blob - offset: %d", offset ); } } while (0); // debug trace offset | |||
| 2122 | ||||
| 2123 | // Add the host's digital signature to the GUI tree | |||
| 2124 | offset += ssh_tree_add_hostsignature(tvb, pinfo, offset, tree, "KEX host signature", | |||
| 2125 | ett_key_exchange_host_sig, global_data); | |||
| 2126 | 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" , 2126, __func__, "SERVER REPLY add signature tree - offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2127 | break; | |||
| 2128 | } | |||
| 2129 | } | |||
| 2130 | ||||
| 2131 | if (msg_code == SSH_MSG_KEX_HYBRID_INIT30) { | |||
| 2132 | 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" , 2132, __func__, "OUT PQ HYBRID KEX - CLIENT INIT track offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2133 | } else if (msg_code == SSH_MSG_KEX_HYBRID_REPLY31) { | |||
| 2134 | 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" , 2134, __func__, "OUT PQ HYBRID KEX - SERVER REPLY track offset: %d" , offset); } } while (0); // debug trace offset | |||
| 2135 | } else { | |||
| 2136 | 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" , 2136, __func__, "OUT PQ HYBRID KEX - track offset: %d", offset ); } } while (0); // debug trace offset | |||
| 2137 | } | |||
| 2138 | ||||
| 2139 | return offset; // Final offset after packet is processed by ssh_dissect_kex_pq_hybrid() | |||
| 2140 | } | |||
| 2141 | ||||
| 2142 | static ssh_message_info_t* | |||
| 2143 | ssh_get_message(packet_info *pinfo, int record_id) | |||
| 2144 | { | |||
| 2145 | ssh_packet_info_t *packet = (ssh_packet_info_t *)p_get_proto_data( | |||
| 2146 | wmem_file_scope(), pinfo, proto_ssh, 0); | |||
| 2147 | ||||
| 2148 | if (!packet) { | |||
| 2149 | return NULL((void*)0); | |||
| 2150 | } | |||
| 2151 | ||||
| 2152 | ssh_message_info_t *message = NULL((void*)0); | |||
| 2153 | for (message = packet->messages; message; message = message->next) { | |||
| 2154 | 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" , 2154, __func__, "%u:looking for message %d now %d", pinfo-> num, record_id, message->id); } } while (0); | |||
| 2155 | if (message->id == record_id) { | |||
| 2156 | return message; | |||
| 2157 | } | |||
| 2158 | } | |||
| 2159 | ||||
| 2160 | return NULL((void*)0); | |||
| 2161 | } | |||
| 2162 | ||||
| 2163 | static int | |||
| 2164 | ssh_try_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 2165 | struct ssh_peer_data *peer_data, int offset, proto_tree *tree) | |||
| 2166 | { | |||
| 2167 | bool_Bool can_decrypt = peer_data->cipher != NULL((void*)0) || peer_data->cipher_id == CIPHER_NULL0x00080000; | |||
| 2168 | ssh_message_info_t *message = NULL((void*)0); | |||
| 2169 | ||||
| 2170 | if (can_decrypt) { | |||
| 2171 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 2172 | ssh_decrypt_packet(tvb, pinfo, peer_data, offset); | |||
| 2173 | if (pinfo->desegment_len) { | |||
| 2174 | return offset; | |||
| 2175 | } | |||
| 2176 | } | |||
| 2177 | ||||
| 2178 | int record_id = tvb_raw_offset(tvb) + offset; | |||
| 2179 | message = ssh_get_message(pinfo, record_id); | |||
| 2180 | ||||
| 2181 | if (message) { | |||
| 2182 | offset += ssh_dissect_decrypted_packet(tvb_new_subset_remaining(tvb, offset), pinfo, peer_data, tree, message); | |||
| 2183 | return offset; | |||
| 2184 | } | |||
| 2185 | } | |||
| 2186 | ||||
| 2187 | return ssh_dissect_encrypted_packet(tvb, pinfo, peer_data, offset, tree); | |||
| 2188 | } | |||
| 2189 | ||||
| 2190 | static int | |||
| 2191 | ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 2192 | struct ssh_peer_data *peer_data, | |||
| 2193 | int offset, proto_tree *tree) | |||
| 2194 | { | |||
| 2195 | int len; | |||
| 2196 | unsigned plen; | |||
| 2197 | ||||
| 2198 | len = tvb_reported_length_remaining(tvb, offset); | |||
| 2199 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (len=%d)", len); | |||
| 2200 | ||||
| 2201 | if (tree) { | |||
| 2202 | int encrypted_len = len; | |||
| 2203 | ||||
| 2204 | if (len > 4 && peer_data->length_is_plaintext) { | |||
| 2205 | plen = tvb_get_ntohl(tvb, offset) ; | |||
| 2206 | proto_tree_add_uint(tree, hf_ssh_packet_length, tvb, offset, 4, plen); | |||
| 2207 | encrypted_len -= 4; | |||
| 2208 | } | |||
| 2209 | else if (len > 4) { | |||
| 2210 | proto_tree_add_item(tree, hf_ssh_packet_length_encrypted, tvb, offset, 4, ENC_NA0x00000000); | |||
| 2211 | encrypted_len -= 4; | |||
| 2212 | } | |||
| 2213 | ||||
| 2214 | if (peer_data->mac_length>0) | |||
| 2215 | encrypted_len -= peer_data->mac_length; | |||
| 2216 | ||||
| 2217 | proto_tree_add_item(tree, hf_ssh_encrypted_packet, | |||
| 2218 | tvb, offset+4, encrypted_len, ENC_NA0x00000000); | |||
| 2219 | ||||
| 2220 | if (peer_data->mac_length>0) | |||
| 2221 | proto_tree_add_item(tree, hf_ssh_mac_string, | |||
| 2222 | tvb, offset+4+encrypted_len, | |||
| 2223 | peer_data->mac_length, ENC_NA0x00000000); | |||
| 2224 | } | |||
| 2225 | offset += len; | |||
| 2226 | return offset; | |||
| 2227 | } | |||
| 2228 | ||||
| 2229 | static int | |||
| 2230 | ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo, | |||
| 2231 | struct ssh_flow_data *global_data, | |||
| 2232 | int offset, proto_tree *tree, int is_response, unsigned * version, | |||
| 2233 | bool_Bool *need_desegmentation) | |||
| 2234 | { | |||
| 2235 | unsigned remain_length; | |||
| 2236 | int linelen, protolen; | |||
| 2237 | ||||
| 2238 | /* | |||
| 2239 | * If the first packet do not contain the banner, | |||
| 2240 | * it is dump in the middle of a flow or not a ssh at all | |||
| 2241 | */ | |||
| 2242 | if (tvb_strncaseeql(tvb, offset, "SSH-", 4) != 0) { | |||
| 2243 | offset = ssh_dissect_encrypted_packet(tvb, pinfo, | |||
| 2244 | &global_data->peer_data[is_response], offset, tree); | |||
| 2245 | return offset; | |||
| 2246 | } | |||
| 2247 | ||||
| 2248 | if (!is_response) { | |||
| 2249 | if (tvb_strncaseeql(tvb, offset, "SSH-2.", 6) == 0) { | |||
| 2250 | *(version) = SSH_VERSION_22; | |||
| 2251 | } else if (tvb_strncaseeql(tvb, offset, "SSH-1.99-", 9) == 0) { | |||
| 2252 | *(version) = SSH_VERSION_22; | |||
| 2253 | } else if (tvb_strncaseeql(tvb, offset, "SSH-1.", 6) == 0) { | |||
| 2254 | *(version) = SSH_VERSION_11; | |||
| 2255 | } | |||
| 2256 | } | |||
| 2257 | ||||
| 2258 | /* | |||
| 2259 | * We use "tvb_ensure_captured_length_remaining()" to make sure there | |||
| 2260 | * actually *is* data remaining. | |||
| 2261 | * | |||
| 2262 | * This means we're guaranteed that "remain_length" is positive. | |||
| 2263 | */ | |||
| 2264 | remain_length = tvb_ensure_captured_length_remaining(tvb, offset); | |||
| 2265 | /*linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, false); | |||
| 2266 | */ | |||
| 2267 | linelen = tvb_find_uint8(tvb, offset, -1, '\n'); | |||
| 2268 | ||||
| 2269 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 2270 | if (linelen == -1 || remain_length < (unsigned)linelen-offset) { | |||
| 2271 | pinfo->desegment_offset = offset; | |||
| 2272 | pinfo->desegment_len = linelen-remain_length; | |||
| 2273 | *need_desegmentation = true1; | |||
| 2274 | return offset; | |||
| 2275 | } | |||
| 2276 | } | |||
| 2277 | if (linelen == -1) { | |||
| 2278 | /* XXX - reassemble across segment boundaries? */ | |||
| 2279 | linelen = remain_length; | |||
| 2280 | protolen = linelen; | |||
| 2281 | } else { | |||
| 2282 | linelen = linelen - offset + 1; | |||
| 2283 | ||||
| 2284 | if (linelen > 1 && tvb_get_uint8(tvb, offset + linelen - 2) == '\r') | |||
| 2285 | protolen = linelen - 2; | |||
| 2286 | else | |||
| 2287 | protolen = linelen - 1; | |||
| 2288 | } | |||
| 2289 | ||||
| 2290 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Protocol (%s)", | |||
| 2291 | tvb_format_text(pinfo->pool, tvb, offset, protolen)); | |||
| 2292 | ||||
| 2293 | // V_C / V_S (client and server identification strings) RFC4253 4.2 | |||
| 2294 | // format: SSH-protoversion-softwareversion SP comments [CR LF not incl.] | |||
| 2295 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 2296 | char *data = (char *)tvb_memdup(pinfo->pool, tvb, offset, protolen); | |||
| 2297 | if(!is_response){ | |||
| 2298 | ssh_hash_buffer_put_string(global_data->kex_client_version, data, protolen); | |||
| 2299 | }else{ | |||
| 2300 | ssh_hash_buffer_put_string(global_data->kex_server_version, data, protolen); | |||
| 2301 | } | |||
| 2302 | } | |||
| 2303 | ||||
| 2304 | proto_tree_add_item(tree, hf_ssh_protocol, | |||
| 2305 | tvb, offset, protolen, ENC_ASCII0x00000000); | |||
| 2306 | offset += linelen; | |||
| 2307 | return offset; | |||
| 2308 | } | |||
| 2309 | ||||
| 2310 | static void | |||
| 2311 | ssh_set_mac_length(struct ssh_peer_data *peer_data) | |||
| 2312 | { | |||
| 2313 | char *size_str; | |||
| 2314 | uint32_t size = 0; | |||
| 2315 | char *mac_name = peer_data->mac; | |||
| 2316 | char *strip; | |||
| 2317 | ||||
| 2318 | if (!mac_name) | |||
| 2319 | return; | |||
| 2320 | ||||
| 2321 | /* wmem_strdup() never returns NULL */ | |||
| 2322 | mac_name = wmem_strdup(NULL((void*)0), (const char *)mac_name); | |||
| 2323 | ||||
| 2324 | /* strip trailing "-etm@openssh.com" or "@openssh.com" */ | |||
| 2325 | strip = strstr(mac_name, "-etm@openssh.com"); | |||
| 2326 | if (strip) { | |||
| 2327 | peer_data->length_is_plaintext = 1; | |||
| 2328 | *strip = '\0'; | |||
| 2329 | } | |||
| 2330 | else { | |||
| 2331 | strip = strstr(mac_name, "@openssh.com"); | |||
| 2332 | if (strip) *strip = '\0'; | |||
| 2333 | } | |||
| 2334 | ||||
| 2335 | size_str = g_strrstr(mac_name, "-"); | |||
| 2336 | if (size_str && ws_strtou32(size_str + 1, NULL((void*)0), &size) && size > 0 && size % 8 == 0) { | |||
| 2337 | peer_data->mac_length = size / 8; | |||
| 2338 | } | |||
| 2339 | else if (strcmp(mac_name, "hmac-sha1") == 0) { | |||
| 2340 | peer_data->mac_length = 20; | |||
| 2341 | } | |||
| 2342 | else if (strcmp(mac_name, "hmac-md5") == 0) { | |||
| 2343 | peer_data->mac_length = 16; | |||
| 2344 | } | |||
| 2345 | else if (strcmp(mac_name, "hmac-ripemd160") == 0) { | |||
| 2346 | peer_data->mac_length = 20; | |||
| 2347 | } | |||
| 2348 | else if (strcmp(mac_name, "none") == 0) { | |||
| 2349 | peer_data->mac_length = 0; | |||
| 2350 | } | |||
| 2351 | ||||
| 2352 | wmem_free(NULL((void*)0), mac_name); | |||
| 2353 | } | |||
| 2354 | ||||
| 2355 | static void ssh_set_kex_specific_dissector(struct ssh_flow_data *global_data) | |||
| 2356 | { | |||
| 2357 | const char *kex_name = global_data->kex; | |||
| 2358 | ||||
| 2359 | if (!kex_name) return; | |||
| 2360 | ||||
| 2361 | if (strcmp(kex_name, "diffie-hellman-group-exchange-sha1") == 0 || | |||
| 2362 | strcmp(kex_name, "diffie-hellman-group-exchange-sha256") == 0) | |||
| 2363 | { | |||
| 2364 | global_data->kex_specific_dissector = ssh_dissect_kex_dh_gex; | |||
| 2365 | } | |||
| 2366 | 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-" ) ) || | |||
| 2367 | strcmp(kex_name, "curve25519-sha256@libssh.org") == 0 || | |||
| 2368 | strcmp(kex_name, "curve25519-sha256") == 0 || | |||
| 2369 | strcmp(kex_name, "curve448-sha512") == 0) | |||
| 2370 | { | |||
| 2371 | global_data->kex_specific_dissector = ssh_dissect_kex_ecdh; | |||
| 2372 | } | |||
| 2373 | else if (strcmp(kex_name, "diffie-hellman-group14-sha256") == 0 || | |||
| 2374 | strcmp(kex_name, "diffie-hellman-group16-sha512") == 0 || | |||
| 2375 | strcmp(kex_name, "diffie-hellman-group18-sha512") == 0 || | |||
| 2376 | strcmp(kex_name, "diffie-hellman-group1-sha1") == 0 || | |||
| 2377 | strcmp(kex_name, "diffie-hellman-group14-sha1") == 0) | |||
| 2378 | { | |||
| 2379 | global_data->kex_specific_dissector = ssh_dissect_kex_dh; | |||
| 2380 | } | |||
| 2381 | else if (strcmp(kex_name, "mlkem768nistp256-sha256") == 0 || | |||
| 2382 | strcmp(kex_name, "mlkem1024nistp384-sha384") == 0) | |||
| 2383 | { | |||
| 2384 | global_data->kex_specific_dissector = ssh_dissect_kex_hybrid; | |||
| 2385 | } | |||
| 2386 | else if (strcmp(kex_name, "sntrup761x25519-sha512") == 0 || | |||
| 2387 | strcmp(kex_name, "mlkem768x25519-sha256") == 0) | |||
| 2388 | /* ___add support for post-quantum hybrid KEM */ | |||
| 2389 | { | |||
| 2390 | global_data->kex_specific_dissector = ssh_dissect_kex_pq_hybrid; | |||
| 2391 | } | |||
| 2392 | else | |||
| 2393 | { | |||
| 2394 | 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" , 2394, __func__, "NOT SUPPORTED OR UNKNOWN KEX DETECTED: ALGORITHM = %s" , kex_name); } } while (0); | |||
| 2395 | } | |||
| 2396 | } | |||
| 2397 | ||||
| 2398 | static int | |||
| 2399 | ssh_gslist_compare_strings(const void *a, const void *b) | |||
| 2400 | { | |||
| 2401 | if (a == NULL((void*)0) && b == NULL((void*)0)) | |||
| 2402 | return 0; | |||
| 2403 | if (a == NULL((void*)0)) | |||
| 2404 | return -1; | |||
| 2405 | if (b == NULL((void*)0)) | |||
| 2406 | return 1; | |||
| 2407 | return strcmp((const char*)a, (const char*)b); | |||
| 2408 | } | |||
| 2409 | ||||
| 2410 | /* expects that *result is NULL */ | |||
| 2411 | static bool_Bool | |||
| 2412 | ssh_choose_algo(char *client, char *server, char **result) | |||
| 2413 | { | |||
| 2414 | char **server_strings = NULL((void*)0); | |||
| 2415 | char **client_strings = NULL((void*)0); | |||
| 2416 | char **step; | |||
| 2417 | GSList *server_list = NULL((void*)0); | |||
| 2418 | ||||
| 2419 | static const char* client_strict = "kex-strict-c-v00@openssh.com"; | |||
| 2420 | static const char* server_strict = "kex-strict-s-v00@openssh.com"; | |||
| 2421 | bool_Bool kex_strict = false0; | |||
| 2422 | ||||
| 2423 | if (!client || !server || !result || *result) | |||
| 2424 | return false0; | |||
| 2425 | ||||
| 2426 | server_strings = g_strsplit(server, ",", 0); | |||
| 2427 | for (step = server_strings; *step; step++) { | |||
| 2428 | server_list = g_slist_append(server_list, *step); | |||
| 2429 | } | |||
| 2430 | ||||
| 2431 | client_strings = g_strsplit(client, ",", 0); | |||
| 2432 | for (step = client_strings; *step; step++) { | |||
| 2433 | GSList *agreed; | |||
| 2434 | if ((agreed = g_slist_find_custom(server_list, *step, ssh_gslist_compare_strings))) { | |||
| 2435 | *result = wmem_strdup(wmem_file_scope(), (const char *)agreed->data); | |||
| 2436 | break; | |||
| 2437 | } | |||
| 2438 | } | |||
| 2439 | ||||
| 2440 | /* Check for the OpenSSH strict key exchange extension designed to | |||
| 2441 | * mitigate the Terrapin attack by resetting the packet sequence | |||
| 2442 | * number to zero after a SSH2_MSG_NEWKEYS message. | |||
| 2443 | * https://www.openssh.com/txt/release-9.6 | |||
| 2444 | * Also see PROTOCOL in the OpenSSH source distribution. | |||
| 2445 | * | |||
| 2446 | * OpenSSH says this is activated "when an endpoint that supports this | |||
| 2447 | * extension observes this algorithm name in a peer's KEXINIT packet". | |||
| 2448 | * We'll have to assume that any endpoint that supports this also | |||
| 2449 | * indicates support for it in its own first SSH2_MSG_KEXINIT. | |||
| 2450 | */ | |||
| 2451 | if (g_strv_contains((const char* const*)client_strings, client_strict) && | |||
| 2452 | g_strv_contains((const char* const*)server_strings, server_strict)) { | |||
| 2453 | ||||
| 2454 | kex_strict = true1; | |||
| 2455 | } | |||
| 2456 | ||||
| 2457 | g_strfreev(client_strings); | |||
| 2458 | g_slist_free(server_list); | |||
| 2459 | g_strfreev(server_strings); | |||
| 2460 | ||||
| 2461 | return kex_strict; | |||
| 2462 | } | |||
| 2463 | ||||
| 2464 | static int | |||
| 2465 | ssh_dissect_key_init(tvbuff_t *tvb, packet_info *pinfo, int offset, | |||
| 2466 | proto_tree *tree, int is_response, struct ssh_flow_data *global_data) | |||
| 2467 | { | |||
| 2468 | int start_offset = offset; | |||
| 2469 | int payload_length; | |||
| 2470 | wmem_strbuf_t *hassh_algo; | |||
| 2471 | char *hassh; | |||
| 2472 | ||||
| 2473 | proto_item *tf, *ti; | |||
| 2474 | proto_tree *key_init_tree; | |||
| 2475 | ||||
| 2476 | struct ssh_peer_data *peer_data = &global_data->peer_data[is_response]; | |||
| 2477 | ||||
| 2478 | key_init_tree = proto_tree_add_subtree(tree, tvb, offset, -1, ett_key_init, &tf, "Algorithms"); | |||
| 2479 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 2480 | peer_data->bn_cookie = ssh_kex_make_bignum(tvb_get_ptr(tvb, offset, 16), 16); | |||
| 2481 | } | |||
| 2482 | proto_tree_add_item(key_init_tree, hf_ssh_cookie, | |||
| 2483 | tvb, offset, 16, ENC_NA0x00000000); | |||
| 2484 | offset += 16; | |||
| 2485 | ||||
| 2486 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2487 | hf_ssh_kex_algorithms_length, hf_ssh_kex_algorithms, | |||
| 2488 | &peer_data->kex_proposal); | |||
| 2489 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2490 | hf_ssh_server_host_key_algorithms_length, | |||
| 2491 | hf_ssh_server_host_key_algorithms, NULL((void*)0)); | |||
| 2492 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2493 | hf_ssh_encryption_algorithms_client_to_server_length, | |||
| 2494 | hf_ssh_encryption_algorithms_client_to_server, | |||
| 2495 | &peer_data->enc_proposals[CLIENT_TO_SERVER_PROPOSAL0]); | |||
| 2496 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2497 | hf_ssh_encryption_algorithms_server_to_client_length, | |||
| 2498 | hf_ssh_encryption_algorithms_server_to_client, | |||
| 2499 | &peer_data->enc_proposals[SERVER_TO_CLIENT_PROPOSAL1]); | |||
| 2500 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2501 | hf_ssh_mac_algorithms_client_to_server_length, | |||
| 2502 | hf_ssh_mac_algorithms_client_to_server, | |||
| 2503 | &peer_data->mac_proposals[CLIENT_TO_SERVER_PROPOSAL0]); | |||
| 2504 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2505 | hf_ssh_mac_algorithms_server_to_client_length, | |||
| 2506 | hf_ssh_mac_algorithms_server_to_client, | |||
| 2507 | &peer_data->mac_proposals[SERVER_TO_CLIENT_PROPOSAL1]); | |||
| 2508 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2509 | hf_ssh_compression_algorithms_client_to_server_length, | |||
| 2510 | hf_ssh_compression_algorithms_client_to_server, | |||
| 2511 | &peer_data->comp_proposals[CLIENT_TO_SERVER_PROPOSAL0]); | |||
| 2512 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2513 | hf_ssh_compression_algorithms_server_to_client_length, | |||
| 2514 | hf_ssh_compression_algorithms_server_to_client, | |||
| 2515 | &peer_data->comp_proposals[SERVER_TO_CLIENT_PROPOSAL1]); | |||
| 2516 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2517 | hf_ssh_languages_client_to_server_length, | |||
| 2518 | hf_ssh_languages_client_to_server, NULL((void*)0)); | |||
| 2519 | offset = ssh_dissect_proposal(tvb, offset, key_init_tree, | |||
| 2520 | hf_ssh_languages_server_to_client_length, | |||
| 2521 | hf_ssh_languages_server_to_client, NULL((void*)0)); | |||
| 2522 | ||||
| 2523 | proto_tree_add_item(key_init_tree, hf_ssh_first_kex_packet_follows, | |||
| 2524 | tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 2525 | offset+=1; | |||
| 2526 | ||||
| 2527 | proto_tree_add_item(key_init_tree, hf_ssh_kex_reserved, | |||
| 2528 | tvb, offset, 4, ENC_NA0x00000000); | |||
| 2529 | offset+=4; | |||
| 2530 | ||||
| 2531 | hassh_algo = wmem_strbuf_new(pinfo->pool, ""); | |||
| 2532 | if(!is_response) { | |||
| 2533 | wmem_strbuf_append_printf(hassh_algo, "%s;%s;%s;%s", peer_data->kex_proposal, peer_data->enc_proposals[CLIENT_TO_SERVER_PROPOSAL0], | |||
| 2534 | peer_data->mac_proposals[CLIENT_TO_SERVER_PROPOSAL0], peer_data->comp_proposals[CLIENT_TO_SERVER_PROPOSAL0]); | |||
| 2535 | hassh = g_compute_checksum_for_string(G_CHECKSUM_MD5, wmem_strbuf_get_str(hassh_algo), wmem_strbuf_get_len(hassh_algo)); | |||
| 2536 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hassh_algo, tvb, offset, 0, wmem_strbuf_get_str(hassh_algo)); | |||
| 2537 | proto_item_set_generated(ti); | |||
| 2538 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hassh, tvb, offset, 0, hassh); | |||
| 2539 | proto_item_set_generated(ti); | |||
| 2540 | g_free(hassh); | |||
| 2541 | } else { | |||
| 2542 | wmem_strbuf_append_printf(hassh_algo, "%s;%s;%s;%s", peer_data->kex_proposal, peer_data->enc_proposals[SERVER_TO_CLIENT_PROPOSAL1], | |||
| 2543 | peer_data->mac_proposals[SERVER_TO_CLIENT_PROPOSAL1], peer_data->comp_proposals[SERVER_TO_CLIENT_PROPOSAL1]); | |||
| 2544 | hassh = g_compute_checksum_for_string(G_CHECKSUM_MD5, wmem_strbuf_get_str(hassh_algo), wmem_strbuf_get_len(hassh_algo)); | |||
| 2545 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hasshserver_algo, tvb, offset, 0, wmem_strbuf_get_str(hassh_algo)); | |||
| 2546 | proto_item_set_generated(ti); | |||
| 2547 | ti = proto_tree_add_string(key_init_tree, hf_ssh_kex_hasshserver, tvb, offset, 0, hassh); | |||
| 2548 | proto_item_set_generated(ti); | |||
| 2549 | g_free(hassh); | |||
| 2550 | } | |||
| 2551 | ||||
| 2552 | if (global_data->peer_data[CLIENT_PEER_DATA0].kex_proposal && | |||
| 2553 | global_data->peer_data[SERVER_PEER_DATA1].kex_proposal && | |||
| 2554 | !global_data->kex) | |||
| 2555 | { | |||
| 2556 | /* Note: we're ignoring first_kex_packet_follows. */ | |||
| 2557 | global_data->ext_kex_strict = ssh_choose_algo( | |||
| 2558 | global_data->peer_data[CLIENT_PEER_DATA0].kex_proposal, | |||
| 2559 | global_data->peer_data[SERVER_PEER_DATA1].kex_proposal, | |||
| 2560 | &global_data->kex); | |||
| 2561 | ssh_set_kex_specific_dissector(global_data); | |||
| 2562 | } | |||
| 2563 | ||||
| 2564 | payload_length = offset - start_offset; | |||
| 2565 | ||||
| 2566 | if (tf != NULL((void*)0)) { | |||
| 2567 | proto_item_set_len(tf, payload_length); | |||
| 2568 | } | |||
| 2569 | ||||
| 2570 | // I_C / I_S (client and server SSH_MSG_KEXINIT payload) RFC4253 4.2 | |||
| 2571 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 2572 | char *data = (char *)wmem_alloc(pinfo->pool, payload_length + 1); | |||
| 2573 | tvb_memcpy(tvb, data + 1, start_offset, payload_length); | |||
| 2574 | data[0] = SSH_MSG_KEXINIT20; | |||
| 2575 | if(is_response){ | |||
| 2576 | ssh_hash_buffer_put_string(global_data->kex_server_key_exchange_init, data, payload_length + 1); | |||
| 2577 | }else{ | |||
| 2578 | // Reset array while REKEY: sanitize client key | |||
| 2579 | global_data->kex_client_key_exchange_init = wmem_array_new(wmem_file_scope(), 1); | |||
| 2580 | ssh_hash_buffer_put_string(global_data->kex_client_key_exchange_init, data, payload_length + 1); | |||
| 2581 | } | |||
| 2582 | } | |||
| 2583 | ||||
| 2584 | return offset; | |||
| 2585 | } | |||
| 2586 | ||||
| 2587 | static int | |||
| 2588 | ssh_dissect_proposal(tvbuff_t *tvb, int offset, proto_tree *tree, | |||
| 2589 | int hf_index_length, int hf_index_value, char **store) | |||
| 2590 | { | |||
| 2591 | uint32_t len = tvb_get_ntohl(tvb, offset); | |||
| 2592 | proto_tree_add_uint(tree, hf_index_length, tvb, offset, 4, len); | |||
| 2593 | offset += 4; | |||
| 2594 | ||||
| 2595 | proto_tree_add_item(tree, hf_index_value, tvb, offset, len, | |||
| 2596 | ENC_ASCII0x00000000); | |||
| 2597 | if (store) | |||
| 2598 | *store = (char *) tvb_get_string_enc(wmem_file_scope(), tvb, offset, len, ENC_ASCII0x00000000); | |||
| 2599 | offset += len; | |||
| 2600 | ||||
| 2601 | return offset; | |||
| 2602 | } | |||
| 2603 | ||||
| 2604 | static void | |||
| 2605 | ssh_keylog_read_file(void) | |||
| 2606 | { | |||
| 2607 | if (!pref_keylog_file || !*pref_keylog_file) { | |||
| 2608 | ws_debug("no keylog file preference set")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2608, __func__, "no keylog file preference set"); } } while (0); | |||
| 2609 | return; | |||
| 2610 | } | |||
| 2611 | ||||
| 2612 | if (ssh_keylog_file && file_needs_reopen(ws_filenofileno(ssh_keylog_file), | |||
| 2613 | pref_keylog_file)) { | |||
| 2614 | ssh_keylog_reset(); | |||
| 2615 | g_hash_table_remove_all(ssh_master_key_map); | |||
| 2616 | } | |||
| 2617 | ||||
| 2618 | if (!ssh_keylog_file) { | |||
| 2619 | ssh_keylog_file = ws_fopenfopen(pref_keylog_file, "r"); | |||
| 2620 | if (!ssh_keylog_file) { | |||
| 2621 | 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" , 2622, __func__, "ssh: failed to open key log file %s: %s", pref_keylog_file , g_strerror((*__errno_location ()))); } } while (0) | |||
| 2622 | pref_keylog_file, g_strerror(errno))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2622, __func__, "ssh: failed to open key log file %s: %s", pref_keylog_file , g_strerror((*__errno_location ()))); } } while (0); | |||
| 2623 | return; | |||
| 2624 | } | |||
| 2625 | } | |||
| 2626 | ||||
| 2627 | /* File format: each line follows the format "<cookie> <type> <key>". | |||
| 2628 | * <cookie> is the hex-encoded (client or server) 16 bytes cookie | |||
| 2629 | * (32 characters) found in the SSH_MSG_KEXINIT of the endpoint whose | |||
| 2630 | * private random is disclosed. | |||
| 2631 | * <type> is either SHARED_SECRET or PRIVATE_KEY depending on the | |||
| 2632 | * type of key provided. PRIVAT_KEY is only supported for DH, | |||
| 2633 | * DH group exchange, and ECDH (including Curve25519) key exchanges. | |||
| 2634 | * <key> is the private random number that is used to generate the DH | |||
| 2635 | * negotiation (length depends on algorithm). In RFC4253 it is called | |||
| 2636 | * x for the client and y for the server. | |||
| 2637 | * For openssh and DH group exchange, it can be retrieved using | |||
| 2638 | * DH_get0_key(kex->dh, NULL, &server_random) | |||
| 2639 | * for groupN in file kexdh.c function kex_dh_compute_key | |||
| 2640 | * for custom group in file kexgexs.c function input_kex_dh_gex_init | |||
| 2641 | * For openssh and curve25519, it can be found in function kex_c25519_enc | |||
| 2642 | * in variable server_key. One may also provide the shared secret | |||
| 2643 | * directly if <type> is set to SHARED_SECRET. | |||
| 2644 | * | |||
| 2645 | * Example: | |||
| 2646 | * 90d886612f9c35903db5bb30d11f23c2 PRIVATE_KEY DEF830C22F6C927E31972FFB20B46C96D0A5F2D5E7BE5A3A8804D6BFC431619ED10AF589EEDFF4750DEA00EFD7AFDB814B6F3528729692B1F2482041521AE9DC | |||
| 2647 | */ | |||
| 2648 | for (;;) { | |||
| 2649 | // XXX - What is a reasonable max line length here? Note at a certain | |||
| 2650 | // point we have to increase the maximum ssh_kex_make_bignum supports (not needed for post quantum material (pure binary)). | |||
| 2651 | char buf[4096];// 4096 is needed for mlkem1024 private_key binary meterial: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf | |||
| 2652 | buf[0] = 0; | |||
| 2653 | ||||
| 2654 | if (!fgets(buf, sizeof(buf), ssh_keylog_file)) { | |||
| 2655 | rewind(ssh_keylog_file); // Resets to start of file (to handle parallel multi sessions decryption) | |||
| 2656 | if (ferror(ssh_keylog_file)) { | |||
| ||||
| 2657 | 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" , 2657, __func__, "Error while reading %s, closing it.", pref_keylog_file ); } } while (0); | |||
| 2658 | ssh_keylog_reset(); | |||
| 2659 | g_hash_table_remove_all(ssh_master_key_map); | |||
| 2660 | } | |||
| 2661 | break; | |||
| 2662 | } | |||
| 2663 | ||||
| 2664 | size_t len = strlen(buf); | |||
| 2665 | while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n')){len-=1;buf[len]=0;} | |||
| 2666 | 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" , 2666, __func__, "ssh: raw keylog line read: %s", buf); } } while (0); | |||
| 2667 | ||||
| 2668 | ssh_keylog_process_line(buf); | |||
| 2669 | } | |||
| 2670 | } | |||
| 2671 | ||||
| 2672 | static void | |||
| 2673 | ssh_keylog_process_lines(const uint8_t *data, unsigned datalen) | |||
| 2674 | { | |||
| 2675 | const char *next_line = (const char *)data; | |||
| 2676 | const char *line_end = next_line + datalen; | |||
| 2677 | while (next_line && next_line < line_end) { | |||
| 2678 | const char *line = next_line; | |||
| 2679 | next_line = (const char *)memchr(line, '\n', line_end - line); | |||
| 2680 | ssize_t linelen; | |||
| 2681 | ||||
| 2682 | if (next_line) { | |||
| 2683 | linelen = next_line - line; | |||
| 2684 | next_line++; /* drop LF */ | |||
| 2685 | } else { | |||
| 2686 | linelen = (ssize_t)(line_end - line); | |||
| 2687 | } | |||
| 2688 | if (linelen > 0 && line[linelen - 1] == '\r') { | |||
| 2689 | linelen--; /* drop CR */ | |||
| 2690 | } | |||
| 2691 | ||||
| 2692 | ssh_debug_printf(" checking keylog line: %.*s\n", (int)linelen, line); | |||
| 2693 | 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" , 2693, __func__, "ssh: about to process line: %.*s", (int)linelen , line); } } while (0); | |||
| 2694 | ||||
| 2695 | char * strippedline = g_strndup(line, linelen); | |||
| 2696 | ssh_keylog_process_line(strippedline); | |||
| 2697 | g_free(strippedline); | |||
| 2698 | } | |||
| 2699 | } | |||
| 2700 | ||||
| 2701 | static void | |||
| 2702 | ssh_keylog_process_line(const char *line) | |||
| 2703 | { | |||
| 2704 | ws_noisy("ssh: process line: %s", line)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 2704, __func__, "ssh: process line: %s", line); } } while ( 0); | |||
| 2705 | ||||
| 2706 | char **split = g_strsplit(line, " ", 3); | |||
| 2707 | char *cookie, *type, *key; | |||
| 2708 | size_t cookie_len, key_len; | |||
| 2709 | ||||
| 2710 | if (g_strv_length(split) == 3) { | |||
| 2711 | // New format: [hex-encoded cookie] [key type] [hex-encoded key material] | |||
| 2712 | cookie = split[0]; | |||
| 2713 | type = split[1]; | |||
| 2714 | key = split[2]; | |||
| 2715 | } else if (g_strv_length(split) == 2) { | |||
| 2716 | // Old format: [hex-encoded cookie] [hex-encoded private key] | |||
| 2717 | 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" , 2717, __func__, "ssh keylog: detected old keylog format without explicit key type" ); } } while (0); | |||
| 2718 | type = "PRIVATE_KEY"; | |||
| 2719 | cookie = split[0]; | |||
| 2720 | key = split[1]; | |||
| 2721 | } else { | |||
| 2722 | ws_debug("ssh keylog: invalid format")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2722, __func__, "ssh keylog: invalid format"); } } while (0 ); | |||
| 2723 | g_strfreev(split); | |||
| 2724 | return; | |||
| 2725 | } | |||
| 2726 | ||||
| 2727 | key_len = strlen(key); | |||
| 2728 | cookie_len = strlen(cookie); | |||
| 2729 | if(key_len & 1){ | |||
| 2730 | ws_debug("ssh keylog: invalid format (key should at least be even!)")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2730, __func__, "ssh keylog: invalid format (key should at least be even!)" ); } } while (0); | |||
| 2731 | g_strfreev(split); | |||
| 2732 | return; | |||
| 2733 | } | |||
| 2734 | if(cookie_len & 1){ | |||
| 2735 | ws_debug("ssh keylog: invalid format (cookie should at least be even!)")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2735, __func__, "ssh keylog: invalid format (cookie should at least be even!)" ); } } while (0); | |||
| 2736 | g_strfreev(split); | |||
| 2737 | return; | |||
| 2738 | } | |||
| 2739 | ssh_bignum * bn_cookie = ssh_kex_make_bignum(NULL((void*)0), (unsigned)(cookie_len/2)); | |||
| 2740 | ssh_bignum * bn_priv = ssh_kex_make_bignum(NULL((void*)0), (unsigned)(key_len/2)); | |||
| 2741 | uint8_t c; | |||
| 2742 | for (size_t i = 0; i < key_len/2; i ++) { | |||
| 2743 | char v0 = key[i * 2]; | |||
| 2744 | int8_t h0 = ws_xton(v0); | |||
| 2745 | char v1 = key[i * 2 + 1]; | |||
| 2746 | int8_t h1 = ws_xton(v1); | |||
| 2747 | ||||
| 2748 | if (h0==-1 || h1==-1) { | |||
| 2749 | 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" , 2749, __func__, "ssh: can't process key, invalid hex number: %c%c" , v0, v1); } } while (0); | |||
| 2750 | g_strfreev(split); | |||
| 2751 | return; | |||
| 2752 | } | |||
| 2753 | ||||
| 2754 | c = (h0 << 4) | h1; | |||
| 2755 | ||||
| 2756 | bn_priv->data[i] = c; | |||
| 2757 | } | |||
| 2758 | for (size_t i = 0; i < cookie_len/2; i ++) { | |||
| 2759 | char v0 = cookie[i * 2]; | |||
| 2760 | int8_t h0 = ws_xton(v0); | |||
| 2761 | char v1 = cookie[i * 2 + 1]; | |||
| 2762 | int8_t h1 = ws_xton(v1); | |||
| 2763 | ||||
| 2764 | if (h0==-1 || h1==-1) { | |||
| 2765 | 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" , 2765, __func__, "ssh: can't process cookie, invalid hex number: %c%c" , v0, v1); } } while (0); | |||
| 2766 | g_strfreev(split); | |||
| 2767 | return; | |||
| 2768 | } | |||
| 2769 | ||||
| 2770 | c = (h0 << 4) | h1; | |||
| 2771 | ||||
| 2772 | bn_cookie->data[i] = c; | |||
| 2773 | } | |||
| 2774 | ssh_bignum * bn_priv_ht = g_new(ssh_bignum, 1)((ssh_bignum *) g_malloc_n ((1), sizeof (ssh_bignum))); | |||
| 2775 | bn_priv_ht->length = bn_priv->length; | |||
| 2776 | bn_priv_ht->data = (uint8_t *) g_memdup2(bn_priv->data, bn_priv->length); | |||
| 2777 | ssh_bignum * bn_cookie_ht = g_new(ssh_bignum, 1)((ssh_bignum *) g_malloc_n ((1), sizeof (ssh_bignum))); | |||
| 2778 | bn_cookie_ht->length = bn_cookie->length; | |||
| 2779 | bn_cookie_ht->data = (uint8_t *) g_memdup2(bn_cookie->data, bn_cookie->length); | |||
| 2780 | ||||
| 2781 | char * type_ht = (char *) g_memdup2(type, strlen(type) + 1); | |||
| 2782 | 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 ))); | |||
| 2783 | entry_ht->type = type_ht; | |||
| 2784 | entry_ht->key_material = bn_priv_ht; | |||
| 2785 | g_hash_table_insert(ssh_master_key_map, bn_cookie_ht, entry_ht); | |||
| 2786 | g_strfreev(split); | |||
| 2787 | } | |||
| 2788 | ||||
| 2789 | static void | |||
| 2790 | ssh_keylog_reset(void) | |||
| 2791 | { | |||
| 2792 | if (ssh_keylog_file) { | |||
| 2793 | fclose(ssh_keylog_file); | |||
| 2794 | ssh_keylog_file = NULL((void*)0); | |||
| 2795 | } | |||
| 2796 | } | |||
| 2797 | ||||
| 2798 | static unsigned | |||
| 2799 | ssh_kex_type(char *type) | |||
| 2800 | { | |||
| 2801 | if (type) { | |||
| 2802 | 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") )) { | |||
| 2803 | return SSH_KEX_CURVE255190x00010000; | |||
| 2804 | }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" ) )) { | |||
| 2805 | return SSH_KEX_SNTRUP761X255190x00040000; | |||
| 2806 | }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" ) )) { | |||
| 2807 | return SSH_KEX_MLKEM768X255190x00050000; | |||
| 2808 | }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") )) { | |||
| 2809 | return SSH_KEX_DH_GEX0x00020000; | |||
| 2810 | }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" ) )) { | |||
| 2811 | return SSH_KEX_DH_GROUP140x00030014; | |||
| 2812 | }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" ) )) { | |||
| 2813 | return SSH_KEX_DH_GROUP160x00030016; | |||
| 2814 | }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" ) )) { | |||
| 2815 | return SSH_KEX_DH_GROUP180x00030018; | |||
| 2816 | }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" ) )) { | |||
| 2817 | return SSH_KEX_DH_GROUP10x00030001; | |||
| 2818 | } | |||
| 2819 | } | |||
| 2820 | ||||
| 2821 | return 0; | |||
| 2822 | } | |||
| 2823 | ||||
| 2824 | static unsigned | |||
| 2825 | ssh_kex_hash_type(char *type_string) | |||
| 2826 | { | |||
| 2827 | 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" ) )) { | |||
| 2828 | return SSH_KEX_HASH_SHA11; | |||
| 2829 | }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") )) { | |||
| 2830 | return SSH_KEX_HASH_SHA2562; | |||
| 2831 | }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") )) { | |||
| 2832 | return SSH_KEX_HASH_SHA2562; | |||
| 2833 | }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") )) { | |||
| 2834 | return SSH_KEX_HASH_SHA5124; | |||
| 2835 | } else { | |||
| 2836 | 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" , 2836, __func__, "hash type %s not supported", type_string); } } while (0); | |||
| 2837 | return 0; | |||
| 2838 | } | |||
| 2839 | } | |||
| 2840 | ||||
| 2841 | static ssh_bignum * | |||
| 2842 | ssh_kex_make_bignum(const uint8_t *data, unsigned length) | |||
| 2843 | { | |||
| 2844 | // 512 bytes (4096 bits) is the maximum bignum size we're supporting | |||
| 2845 | // Actually we need 513 bytes, to make provision for signed values | |||
| 2846 | // Diffie-Hellman group 18 has 8192 bits | |||
| 2847 | if (length == 0 || length > 1025) { | |||
| 2848 | return NULL((void*)0); | |||
| 2849 | } | |||
| 2850 | ||||
| 2851 | ssh_bignum *bn = wmem_new0(wmem_file_scope(), ssh_bignum)((ssh_bignum*)wmem_alloc0((wmem_file_scope()), sizeof(ssh_bignum ))); | |||
| 2852 | bn->data = (uint8_t *)wmem_alloc0(wmem_file_scope(), length); | |||
| 2853 | ||||
| 2854 | if (data) { | |||
| 2855 | memcpy(bn->data, data, length); | |||
| 2856 | } | |||
| 2857 | ||||
| 2858 | bn->length = length; | |||
| 2859 | return bn; | |||
| 2860 | } | |||
| 2861 | ||||
| 2862 | static bool_Bool | |||
| 2863 | ssh_read_e(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data) | |||
| 2864 | { | |||
| 2865 | // store the client's public part (e) for later usage | |||
| 2866 | uint32_t length = tvb_get_ntohl(tvb, offset); | |||
| 2867 | global_data->kex_e = ssh_kex_make_bignum(NULL((void*)0), length); | |||
| 2868 | if (!global_data->kex_e) { | |||
| 2869 | return false0; | |||
| 2870 | } | |||
| 2871 | tvb_memcpy(tvb, global_data->kex_e->data, offset + 4, length); | |||
| 2872 | return true1; | |||
| 2873 | } | |||
| 2874 | ||||
| 2875 | static bool_Bool | |||
| 2876 | ssh_read_f(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data) | |||
| 2877 | { | |||
| 2878 | // store the server's public part (f) for later usage | |||
| 2879 | uint32_t length = tvb_get_ntohl(tvb, offset); | |||
| 2880 | global_data->kex_f = ssh_kex_make_bignum(NULL((void*)0), length); | |||
| 2881 | if (!global_data->kex_f) { | |||
| 2882 | return false0; | |||
| 2883 | } | |||
| 2884 | tvb_memcpy(tvb, global_data->kex_f->data, offset + 4, length); | |||
| 2885 | return true1; | |||
| 2886 | } | |||
| 2887 | ||||
| 2888 | static int // add support of client PQ hybrid key (e) | |||
| 2889 | ssh_read_e_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data) | |||
| 2890 | { | |||
| 2891 | // Read length of PQ client key | |||
| 2892 | uint32_t length = tvb_get_ntohl(tvb, offset); | |||
| 2893 | ||||
| 2894 | // Sanity check | |||
| 2895 | if (length == 0 || length > 65535) { | |||
| 2896 | 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" , 2896, __func__, "ssh_read_e_pq: Invalid PQ key length: %u", length); } } while (0); | |||
| 2897 | return false0; | |||
| 2898 | } | |||
| 2899 | ||||
| 2900 | // Free any existing data (if dissecting multiple sessions) | |||
| 2901 | wmem_free(wmem_file_scope(), global_data->kex_e_pq); | |||
| 2902 | ||||
| 2903 | // Allocate and store the PQ client key | |||
| 2904 | global_data->kex_e_pq = (unsigned char *)wmem_alloc(wmem_file_scope(), length); | |||
| 2905 | global_data->kex_e_pq_len = length; | |||
| 2906 | ||||
| 2907 | tvb_memcpy(tvb, global_data->kex_e_pq, offset + 4, length); | |||
| 2908 | ||||
| 2909 | 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" , 2909, __func__, "Stored %u bytes of client PQ key - stored new_offset_client: %d - offset: %d" , length, offset + 4 + length, offset); } } while (0); | |||
| 2910 | return offset + 4 + length; // consuming packet (advancing offset) | |||
| 2911 | } | |||
| 2912 | ||||
| 2913 | static int // add support of server PQ hybrid key (f) | |||
| 2914 | ssh_read_f_pq(tvbuff_t *tvb, int offset, struct ssh_flow_data *global_data) | |||
| 2915 | { | |||
| 2916 | // Read length of PQ server key | |||
| 2917 | uint32_t length = tvb_get_ntohl(tvb, offset); | |||
| 2918 | ||||
| 2919 | // Sanity check | |||
| 2920 | if (length == 0 || length > 65535) { | |||
| 2921 | 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" , 2921, __func__, "ssh_read_f_pq: Invalid PQ key length: %u", length); } } while (0); | |||
| 2922 | return false0; | |||
| 2923 | } | |||
| 2924 | ||||
| 2925 | // Free any existing data | |||
| 2926 | wmem_free(wmem_file_scope(), global_data->kex_f_pq); | |||
| 2927 | ||||
| 2928 | // Allocate and store the PQ server key | |||
| 2929 | global_data->kex_f_pq = (unsigned char *)wmem_alloc(wmem_file_scope(), length); | |||
| 2930 | global_data->kex_f_pq_len = length; | |||
| 2931 | ||||
| 2932 | tvb_memcpy(tvb, global_data->kex_f_pq, offset + 4, length); | |||
| 2933 | ||||
| 2934 | 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" , 2934, __func__, "Stored %u bytes of server PQ key - stored new_offset_server: %d - offset: %d" , length, offset + 4 + length, offset); } } while (0); | |||
| 2935 | return offset + 4 + length; // consuming packet (advancing offset) | |||
| 2936 | } | |||
| 2937 | ||||
| 2938 | ||||
| 2939 | static ssh_bignum * | |||
| 2940 | ssh_read_mpint(tvbuff_t *tvb, int offset) | |||
| 2941 | { | |||
| 2942 | // store the DH group modulo (p) for later usage | |||
| 2943 | int length = tvb_get_ntohl(tvb, offset); | |||
| 2944 | ssh_bignum * bn = ssh_kex_make_bignum(NULL((void*)0), length); | |||
| 2945 | if (!bn) { | |||
| 2946 | ws_debug("invalid bignum length %u", length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 2946, __func__, "invalid bignum length %u", length); } } while (0); | |||
| 2947 | return NULL((void*)0); | |||
| 2948 | } | |||
| 2949 | tvb_memcpy(tvb, bn->data, offset + 4, length); | |||
| 2950 | return bn; | |||
| 2951 | } | |||
| 2952 | ||||
| 2953 | static void | |||
| 2954 | ssh_keylog_hash_write_secret(struct ssh_flow_data *global_data) | |||
| 2955 | { | |||
| 2956 | /* | |||
| 2957 | * This computation is defined differently for each key exchange method: | |||
| 2958 | * https://tools.ietf.org/html/rfc4253#page-23 | |||
| 2959 | * https://tools.ietf.org/html/rfc5656#page-8 | |||
| 2960 | * https://tools.ietf.org/html/rfc4419#page-4 | |||
| 2961 | * All key exchange methods: | |||
| 2962 | * https://www.iana.org/assignments/ssh-parameters/ssh-parameters.xhtml#ssh-parameters-16 | |||
| 2963 | */ | |||
| 2964 | ||||
| 2965 | gcry_md_hd_t hd; | |||
| 2966 | ssh_key_map_entry_t *entry; | |||
| 2967 | ssh_bignum *secret = NULL((void*)0); | |||
| 2968 | int length; | |||
| 2969 | bool_Bool client_cookie = false0; | |||
| 2970 | ||||
| 2971 | ssh_keylog_read_file(); | |||
| 2972 | ||||
| 2973 | unsigned kex_type = ssh_kex_type(global_data->kex); | |||
| 2974 | unsigned kex_hash_type = ssh_kex_hash_type(global_data->kex); | |||
| 2975 | ||||
| 2976 | entry = (ssh_key_map_entry_t *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[SERVER_PEER_DATA1].bn_cookie); | |||
| 2977 | if (!entry) { | |||
| 2978 | entry = (ssh_key_map_entry_t *)g_hash_table_lookup(ssh_master_key_map, global_data->peer_data[CLIENT_PEER_DATA0].bn_cookie); | |||
| 2979 | client_cookie = true1; | |||
| 2980 | } | |||
| 2981 | if (!entry) { | |||
| 2982 | 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" , 2982, __func__, "ssh decryption: no entry in keylog file for this session" ); } } while (0); | |||
| 2983 | global_data->do_decrypt = false0; | |||
| 2984 | return; | |||
| 2985 | } | |||
| 2986 | ||||
| 2987 | if (!strcmp(entry->type, "PRIVATE_KEY")) { | |||
| 2988 | if (client_cookie) { | |||
| 2989 | secret = ssh_kex_shared_secret(kex_type, global_data->kex_f, entry->key_material, global_data->kex_gex_p); | |||
| 2990 | } else { | |||
| 2991 | secret = ssh_kex_shared_secret(kex_type, global_data->kex_e, entry->key_material, global_data->kex_gex_p); | |||
| 2992 | } | |||
| 2993 | } else if (!strcmp(entry->type, "SHARED_SECRET")) { | |||
| 2994 | secret = ssh_kex_make_bignum(entry->key_material->data, entry->key_material->length); | |||
| 2995 | } else { | |||
| 2996 | 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" , 2996, __func__, "ssh decryption: unknown key type in keylog file" ); } } while (0); | |||
| 2997 | global_data->do_decrypt = false0; | |||
| 2998 | return; | |||
| 2999 | } | |||
| 3000 | ||||
| 3001 | if (!secret) { | |||
| 3002 | 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" , 3002, __func__, "ssh decryption: no key material for this session" ); } } while (0); | |||
| 3003 | global_data->do_decrypt = false0; | |||
| 3004 | return; | |||
| 3005 | } | |||
| 3006 | ||||
| 3007 | // shared secret data needs to be written as an mpint, and we need it later | |||
| 3008 | if (kex_type == SSH_KEX_SNTRUP761X255190x00040000 || kex_type == SSH_KEX_MLKEM768X255190x00050000) { | |||
| 3009 | // Reset array while REKEY: sanitize shared_secret: | |||
| 3010 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1); | |||
| 3011 | // For PQ KEMs: use shared_secret as-is, whether SHARED_SECRET or PRIVATE_KEY | |||
| 3012 | // Do NOT prepend 0x00 (OpenSSH already encodes correctly for PQ KEM) | |||
| 3013 | ssh_hash_buffer_put_string(global_data->kex_shared_secret, secret->data, secret->length); | |||
| 3014 | } else { | |||
| 3015 | // For all other KEX types (e.g., curve25519, ecdh-sha2, etc.) | |||
| 3016 | // Pad with 0x00 if MSB is set, to comply with mpint format (RFC 4251) | |||
| 3017 | if (secret->data[0] & 0x80) { // Stored in Big endian | |||
| 3018 | length = secret->length + 1; | |||
| 3019 | char *tmp = (char *)wmem_alloc0(wmem_packet_scope(), length); | |||
| 3020 | memcpy(tmp + 1, secret->data, secret->length); | |||
| 3021 | tmp[0] = 0; | |||
| 3022 | secret->data = tmp; | |||
| 3023 | secret->length = length; | |||
| 3024 | } | |||
| 3025 | // Reset array while REKEY: sanitize shared_secret: | |||
| 3026 | global_data->kex_shared_secret = wmem_array_new(wmem_file_scope(), 1); | |||
| 3027 | ssh_hash_buffer_put_string(global_data->kex_shared_secret, secret->data, secret->length); | |||
| 3028 | } | |||
| 3029 | ||||
| 3030 | wmem_array_t * kex_gex_p = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3031 | 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);} | |||
| 3032 | wmem_array_t * kex_gex_g = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3033 | 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);} | |||
| 3034 | wmem_array_t * kex_e = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3035 | if(global_data->kex_e){ssh_hash_buffer_put_string(kex_e, global_data->kex_e->data, global_data->kex_e->length);} | |||
| 3036 | wmem_array_t * kex_f = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3037 | if(global_data->kex_f){ssh_hash_buffer_put_string(kex_f, global_data->kex_f->data, global_data->kex_f->length);} | |||
| 3038 | wmem_array_t * kex_e_pq = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3039 | 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);} | |||
| 3040 | wmem_array_t * kex_f_pq = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3041 | 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);} | |||
| 3042 | ||||
| 3043 | wmem_array_t * kex_hash_buffer = wmem_array_new(wmem_packet_scope(), 1); | |||
| 3044 | 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)); | |||
| 3045 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_client_version), wmem_array_get_count(global_data->kex_client_version)); | |||
| 3046 | 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)); | |||
| 3047 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_server_version), wmem_array_get_count(global_data->kex_server_version)); | |||
| 3048 | 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)); | |||
| 3049 | 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)); | |||
| 3050 | 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)); | |||
| 3051 | 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)); | |||
| 3052 | 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)); | |||
| 3053 | 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)); | |||
| 3054 | if(kex_type==SSH_KEX_DH_GEX0x00020000){ | |||
| 3055 | 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)); | |||
| 3056 | 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)); | |||
| 3057 | 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)); | |||
| 3058 | 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)); | |||
| 3059 | 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)); | |||
| 3060 | 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)); | |||
| 3061 | ssh_print_data("key modulo (p)", (const unsigned char *)wmem_array_get_raw(kex_gex_p), wmem_array_get_count(kex_gex_p)); | |||
| 3062 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_gex_p), wmem_array_get_count(kex_gex_p)); | |||
| 3063 | ssh_print_data("key base (g)", (const unsigned char *)wmem_array_get_raw(kex_gex_g), wmem_array_get_count(kex_gex_g)); | |||
| 3064 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_gex_g), wmem_array_get_count(kex_gex_g)); | |||
| 3065 | ssh_print_data("key client (e)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3066 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3067 | ssh_print_data("key server (f)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3068 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3069 | } | |||
| 3070 | 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){ | |||
| 3071 | ssh_print_data("key client (e)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3072 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3073 | ssh_print_data("key server (f)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3074 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3075 | } | |||
| 3076 | if(kex_type==SSH_KEX_CURVE255190x00010000){ | |||
| 3077 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3078 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e), wmem_array_get_count(kex_e)); | |||
| 3079 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3080 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f), wmem_array_get_count(kex_f)); | |||
| 3081 | } | |||
| 3082 | if (kex_type==SSH_KEX_SNTRUP761X255190x00040000){ // Add support of sntrup761x25519 | |||
| 3083 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq)); | |||
| 3084 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq)); | |||
| 3085 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq)); | |||
| 3086 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq)); | |||
| 3087 | ws_noisy("Switch to SSH_KEX_SNTRUP761X25519")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 3087, __func__, "Switch to SSH_KEX_SNTRUP761X25519"); } } while (0); | |||
| 3088 | } | |||
| 3089 | if (kex_type==SSH_KEX_MLKEM768X255190x00050000){ // Add support of mlkem768x25519 | |||
| 3090 | ssh_print_data("key client (Q_C)", (const unsigned char *)wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq)); | |||
| 3091 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_e_pq), wmem_array_get_count(kex_e_pq)); | |||
| 3092 | ssh_print_data("key server (Q_S)", (const unsigned char *)wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq)); | |||
| 3093 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(kex_f_pq), wmem_array_get_count(kex_f_pq)); | |||
| 3094 | ws_noisy("Switch to SSH_KEX_MLKEM768X25519")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 3094, __func__, "Switch to SSH_KEX_MLKEM768X25519"); } } while (0); | |||
| 3095 | } | |||
| 3096 | 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)); | |||
| 3097 | wmem_array_append(kex_hash_buffer, wmem_array_get_raw(global_data->kex_shared_secret), wmem_array_get_count(global_data->kex_shared_secret)); | |||
| 3098 | ||||
| 3099 | ssh_print_data("exchange", (const unsigned char *)wmem_array_get_raw(kex_hash_buffer), wmem_array_get_count(kex_hash_buffer)); | |||
| 3100 | ||||
| 3101 | unsigned hash_len = 32; | |||
| 3102 | if(kex_hash_type==SSH_KEX_HASH_SHA11) { | |||
| 3103 | gcry_md_open(&hd, GCRY_MD_SHA1, 0); | |||
| 3104 | hash_len = 20; | |||
| 3105 | } else if(kex_hash_type==SSH_KEX_HASH_SHA2562) { | |||
| 3106 | gcry_md_open(&hd, GCRY_MD_SHA256, 0); | |||
| 3107 | hash_len = 32; | |||
| 3108 | } else if(kex_hash_type==SSH_KEX_HASH_SHA5124) { | |||
| 3109 | gcry_md_open(&hd, GCRY_MD_SHA512, 0); | |||
| 3110 | hash_len = 64; | |||
| 3111 | } else { | |||
| 3112 | 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" , 3112, __func__, "kex_hash_type type %d not supported", kex_hash_type ); } } while (0); | |||
| 3113 | return; | |||
| 3114 | } | |||
| 3115 | char *exchange_hash = (char *)wmem_alloc0(wmem_file_scope(), hash_len); | |||
| 3116 | gcry_md_write(hd, wmem_array_get_raw(kex_hash_buffer), wmem_array_get_count(kex_hash_buffer)); | |||
| 3117 | memcpy(exchange_hash, gcry_md_read(hd, 0), hash_len); | |||
| 3118 | gcry_md_close(hd); | |||
| 3119 | ssh_print_data("hash", exchange_hash, hash_len); | |||
| 3120 | global_data->secret = secret; | |||
| 3121 | ssh_derive_symmetric_keys(secret, exchange_hash, hash_len, global_data); | |||
| 3122 | } | |||
| 3123 | ||||
| 3124 | // the purpose of this function is to deal with all different kex methods | |||
| 3125 | static ssh_bignum * | |||
| 3126 | ssh_kex_shared_secret(int kex_type, ssh_bignum *pub, ssh_bignum *priv, ssh_bignum *modulo) | |||
| 3127 | { | |||
| 3128 | DISSECTOR_ASSERT(pub != NULL)((void) ((pub != ((void*)0)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3128, "pub != ((void*)0)")))); | |||
| 3129 | DISSECTOR_ASSERT(priv != NULL)((void) ((priv != ((void*)0)) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3129, "priv != ((void*)0)")))); | |||
| 3130 | ||||
| 3131 | ssh_bignum *secret = ssh_kex_make_bignum(NULL((void*)0), pub->length); | |||
| 3132 | if (!secret) { | |||
| 3133 | ws_debug("invalid key length %u", pub->length)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3133, __func__, "invalid key length %u", pub->length); } } while (0); | |||
| 3134 | return NULL((void*)0); | |||
| 3135 | } | |||
| 3136 | ||||
| 3137 | if(kex_type==SSH_KEX_DH_GEX0x00020000){ | |||
| 3138 | gcry_mpi_t b = NULL((void*)0); | |||
| 3139 | gcry_mpi_scan(&b, GCRYMPI_FMT_USG, pub->data, pub->length, NULL((void*)0)); | |||
| 3140 | gcry_mpi_t d = NULL((void*)0), e = NULL((void*)0), m = NULL((void*)0); | |||
| 3141 | size_t result_len = 0; | |||
| 3142 | d = gcry_mpi_new(pub->length*8); | |||
| 3143 | gcry_mpi_scan(&e, GCRYMPI_FMT_USG, priv->data, priv->length, NULL((void*)0)); | |||
| 3144 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, modulo->data, modulo->length, NULL((void*)0)); | |||
| 3145 | gcry_mpi_powm(d, b, e, m); // gcry_mpi_powm(d, b, e, m) => d = b^e % m | |||
| 3146 | gcry_mpi_print(GCRYMPI_FMT_USG, secret->data, secret->length, &result_len, d); | |||
| 3147 | secret->length = (unsigned)result_len; // Should not be larger than what fits in a 32-bit unsigned integer... | |||
| 3148 | gcry_mpi_release(d); | |||
| 3149 | gcry_mpi_release(b); | |||
| 3150 | gcry_mpi_release(e); | |||
| 3151 | gcry_mpi_release(m); | |||
| 3152 | ||||
| 3153 | }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){ | |||
| 3154 | gcry_mpi_t m = NULL((void*)0); | |||
| 3155 | if(kex_type==SSH_KEX_DH_GROUP10x00030001){ | |||
| 3156 | static const uint8_t p[] = { | |||
| 3157 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, | |||
| 3158 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, | |||
| 3159 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |||
| 3160 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, | |||
| 3161 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, | |||
| 3162 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |||
| 3163 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, | |||
| 3164 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}; | |||
| 3165 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0)); | |||
| 3166 | }else if(kex_type==SSH_KEX_DH_GROUP140x00030014){ | |||
| 3167 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF | |||
| 3168 | static const uint8_t p[] = { | |||
| 3169 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, | |||
| 3170 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, | |||
| 3171 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |||
| 3172 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, | |||
| 3173 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, | |||
| 3174 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |||
| 3175 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, | |||
| 3176 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, | |||
| 3177 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, | |||
| 3178 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, | |||
| 3179 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, | |||
| 3180 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, | |||
| 3181 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, | |||
| 3182 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, | |||
| 3183 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, | |||
| 3184 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; | |||
| 3185 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0)); | |||
| 3186 | }else if(kex_type==SSH_KEX_DH_GROUP160x00030016){ | |||
| 3187 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF | |||
| 3188 | static const uint8_t p[] = { | |||
| 3189 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, | |||
| 3190 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, | |||
| 3191 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |||
| 3192 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, | |||
| 3193 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, | |||
| 3194 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |||
| 3195 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, | |||
| 3196 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, | |||
| 3197 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, | |||
| 3198 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, | |||
| 3199 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, | |||
| 3200 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, | |||
| 3201 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, | |||
| 3202 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, | |||
| 3203 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, | |||
| 3204 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, | |||
| 3205 | 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, | |||
| 3206 | 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, | |||
| 3207 | 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, | |||
| 3208 | 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, | |||
| 3209 | 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, | |||
| 3210 | 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, | |||
| 3211 | 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, | |||
| 3212 | 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, | |||
| 3213 | 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, | |||
| 3214 | 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, | |||
| 3215 | 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, | |||
| 3216 | 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, | |||
| 3217 | 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, | |||
| 3218 | 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, | |||
| 3219 | 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, | |||
| 3220 | 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}; | |||
| 3221 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0)); | |||
| 3222 | }else if(kex_type==SSH_KEX_DH_GROUP180x00030018){ | |||
| 3223 | //p:FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF | |||
| 3224 | static const uint8_t p[] = { | |||
| 3225 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, | |||
| 3226 | 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, | |||
| 3227 | 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, | |||
| 3228 | 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, | |||
| 3229 | 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, | |||
| 3230 | 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, | |||
| 3231 | 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, | |||
| 3232 | 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, | |||
| 3233 | 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, | |||
| 3234 | 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, | |||
| 3235 | 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, | |||
| 3236 | 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, | |||
| 3237 | 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, | |||
| 3238 | 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, | |||
| 3239 | 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, | |||
| 3240 | 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, | |||
| 3241 | 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, | |||
| 3242 | 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7, | |||
| 3243 | 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D, | |||
| 3244 | 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, | |||
| 3245 | 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, | |||
| 3246 | 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, | |||
| 3247 | 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, | |||
| 3248 | 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01, 0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7, | |||
| 3249 | 0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26, 0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C, | |||
| 3250 | 0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA, 0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8, | |||
| 3251 | 0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9, 0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6, | |||
| 3252 | 0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D, 0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2, | |||
| 3253 | 0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED, 0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF, | |||
| 3254 | 0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C, 0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9, | |||
| 3255 | 0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1, 0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F, | |||
| 3256 | 0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26, | |||
| 3257 | 0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE, 0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD, | |||
| 3258 | 0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E, 0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE, | |||
| 3259 | 0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31, 0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18, | |||
| 3260 | 0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED, 0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B, | |||
| 3261 | 0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B, 0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42, | |||
| 3262 | 0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF, 0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC, | |||
| 3263 | 0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03, 0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6, | |||
| 3264 | 0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82, 0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E, | |||
| 3265 | 0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3, 0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE, | |||
| 3266 | 0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5, 0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA, | |||
| 3267 | 0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8, 0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0, | |||
| 3268 | 0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28, 0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76, | |||
| 3269 | 0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0, 0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C, | |||
| 3270 | 0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32, 0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68, | |||
| 3271 | 0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE, 0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6, | |||
| 3272 | 0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59, 0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4, | |||
| 3273 | 0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C, 0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA, | |||
| 3274 | 0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00, 0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED, | |||
| 3275 | 0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66, 0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68, | |||
| 3276 | 0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78, 0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D, | |||
| 3277 | 0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9, 0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07, | |||
| 3278 | 0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7, 0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B, | |||
| 3279 | 0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD, 0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8, | |||
| 3280 | 0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A, 0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6, | |||
| 3281 | 0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D, 0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36, | |||
| 3282 | 0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1, 0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D, | |||
| 3283 | 0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1, 0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73, | |||
| 3284 | 0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68, 0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92, | |||
| 3285 | 0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7, 0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B, | |||
| 3286 | 0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47, 0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA, | |||
| 3287 | 0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF, 0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71, | |||
| 3288 | 0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}; | |||
| 3289 | gcry_mpi_scan(&m, GCRYMPI_FMT_USG, p, sizeof(p), NULL((void*)0)); | |||
| 3290 | } | |||
| 3291 | ||||
| 3292 | gcry_mpi_t b = NULL((void*)0); | |||
| 3293 | gcry_mpi_scan(&b, GCRYMPI_FMT_USG, pub->data, pub->length, NULL((void*)0)); | |||
| 3294 | gcry_mpi_t d = NULL((void*)0), e = NULL((void*)0); | |||
| 3295 | size_t result_len = 0; | |||
| 3296 | d = gcry_mpi_new(pub->length*8); | |||
| 3297 | gcry_mpi_scan(&e, GCRYMPI_FMT_USG, priv->data, priv->length, NULL((void*)0)); | |||
| 3298 | gcry_mpi_powm(d, b, e, m); // gcry_mpi_powm(d, b, e, m) => d = b^e % m | |||
| 3299 | gcry_mpi_print(GCRYMPI_FMT_USG, secret->data, secret->length, &result_len, d); | |||
| 3300 | secret->length = (unsigned)result_len; // Should not be larger than what fits in a 32-bit unsigned integer... | |||
| 3301 | gcry_mpi_release(d); | |||
| 3302 | gcry_mpi_release(b); | |||
| 3303 | gcry_mpi_release(e); | |||
| 3304 | gcry_mpi_release(m); | |||
| 3305 | }else if(kex_type==SSH_KEX_CURVE255190x00010000){ | |||
| 3306 | if (crypto_scalarmult_curve25519(secret->data, priv->data, pub->data)) { | |||
| 3307 | ws_debug("curve25519: can't compute shared secret")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3307, __func__, "curve25519: can't compute shared secret"); } } while (0); | |||
| 3308 | return NULL((void*)0); | |||
| 3309 | } | |||
| 3310 | } else { | |||
| 3311 | 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" , 3311, __func__, "kex_type type %d not supported", kex_type) ; } } while (0); | |||
| 3312 | return 0; | |||
| 3313 | } | |||
| 3314 | ||||
| 3315 | return secret; | |||
| 3316 | } | |||
| 3317 | ||||
| 3318 | static char * | |||
| 3319 | ssh_string(const char *string, unsigned length) | |||
| 3320 | { | |||
| 3321 | char *ssh_string = (char *)wmem_alloc(wmem_packet_scope(), length + 4); | |||
| 3322 | ssh_string[0] = (length >> 24) & 0xff; | |||
| 3323 | ssh_string[1] = (length >> 16) & 0xff; | |||
| 3324 | ssh_string[2] = (length >> 8) & 0xff; | |||
| 3325 | ssh_string[3] = length & 0xff; | |||
| 3326 | memcpy(ssh_string + 4, string, length); | |||
| 3327 | return ssh_string; | |||
| 3328 | } | |||
| 3329 | ||||
| 3330 | static void | |||
| 3331 | ssh_hash_buffer_put_string(wmem_array_t *buffer, const char *string, | |||
| 3332 | unsigned length) | |||
| 3333 | { | |||
| 3334 | if (!buffer) { | |||
| 3335 | return; | |||
| 3336 | } | |||
| 3337 | ||||
| 3338 | char *string_with_length = ssh_string(string, length); | |||
| 3339 | wmem_array_append(buffer, string_with_length, length + 4); | |||
| 3340 | } | |||
| 3341 | ||||
| 3342 | static void | |||
| 3343 | ssh_hash_buffer_put_uint32(wmem_array_t *buffer, unsigned val) | |||
| 3344 | { | |||
| 3345 | if (!buffer) { | |||
| 3346 | return; | |||
| 3347 | } | |||
| 3348 | ||||
| 3349 | char buf[4]; | |||
| 3350 | buf[0] = (val >> 24); buf[1] = (val >> 16); buf[2] = (val >> 8); buf[3] = (val >> 0); | |||
| 3351 | wmem_array_append(buffer, buf, 4); | |||
| 3352 | } | |||
| 3353 | ||||
| 3354 | static void ssh_derive_symmetric_keys(ssh_bignum *secret, char *exchange_hash, | |||
| 3355 | unsigned hash_length, struct ssh_flow_data *global_data) | |||
| 3356 | { | |||
| 3357 | if (!global_data->session_id) { | |||
| 3358 | global_data->session_id = exchange_hash; | |||
| 3359 | global_data->session_id_length = hash_length; | |||
| 3360 | } | |||
| 3361 | ||||
| 3362 | unsigned int we_need = 0; | |||
| 3363 | for(int peer_cnt=0;peer_cnt<2;peer_cnt++){ | |||
| 3364 | struct ssh_peer_data * peer_data = &global_data->peer_data[peer_cnt]; | |||
| 3365 | // required size of key depends on cipher used. chacha20 wants 64 bytes | |||
| 3366 | unsigned need = 0; | |||
| 3367 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) { | |||
| 3368 | need = 64; | |||
| 3369 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id || CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id) { | |||
| 3370 | need = 16; | |||
| 3371 | } else if (CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id) { | |||
| 3372 | need = 24; | |||
| 3373 | } else if (CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) { | |||
| 3374 | need = 32; | |||
| 3375 | } else { | |||
| 3376 | ssh_debug_printf("ssh: cipher (%d) is unknown or not set\n", peer_data->cipher_id); | |||
| 3377 | ssh_debug_flush(); | |||
| 3378 | } | |||
| 3379 | if(peer_data->mac_id == CIPHER_MAC_SHA2_2560x00020001){ | |||
| 3380 | need = 32; | |||
| 3381 | }else{ | |||
| 3382 | ssh_debug_printf("ssh: MAC (%d) is unknown or not set\n", peer_data->mac_id); | |||
| 3383 | ssh_debug_flush(); | |||
| 3384 | } | |||
| 3385 | if (we_need<need) { | |||
| 3386 | we_need = need; | |||
| 3387 | } | |||
| 3388 | } | |||
| 3389 | ||||
| 3390 | for (int i = 0; i < 6; i ++) { | |||
| 3391 | ssh_derive_symmetric_key(secret, exchange_hash, hash_length, | |||
| 3392 | 'A' + i, &global_data->new_keys[i], global_data, we_need); | |||
| 3393 | if(i==0){ ssh_print_data("Initial IV client to server", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3394 | }else if(i==1){ ssh_print_data("Initial IV server to client", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3395 | }else if(i==2){ ssh_print_data("Encryption key client to server", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3396 | }else if(i==3){ ssh_print_data("Encryption key server to client", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3397 | }else if(i==4){ ssh_print_data("Integrity key client to server", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3398 | }else if(i==5){ ssh_print_data("Integrity key server to client", global_data->new_keys[i].data, global_data->new_keys[i].length); | |||
| 3399 | } | |||
| 3400 | } | |||
| 3401 | } | |||
| 3402 | ||||
| 3403 | static void ssh_derive_symmetric_key(ssh_bignum *secret, char *exchange_hash, | |||
| 3404 | unsigned hash_length, char id, ssh_bignum *result_key, | |||
| 3405 | struct ssh_flow_data *global_data, unsigned we_need) | |||
| 3406 | { | |||
| 3407 | gcry_md_hd_t hd; | |||
| 3408 | ||||
| 3409 | unsigned kex_hash_type = ssh_kex_hash_type(global_data->kex); | |||
| 3410 | int algo = GCRY_MD_SHA256; | |||
| 3411 | if(kex_hash_type==SSH_KEX_HASH_SHA11){ | |||
| 3412 | algo = GCRY_MD_SHA1; | |||
| 3413 | }else if(kex_hash_type==SSH_KEX_HASH_SHA2562){ | |||
| 3414 | algo = GCRY_MD_SHA256; | |||
| 3415 | }else if(kex_hash_type==SSH_KEX_HASH_SHA5124){ | |||
| 3416 | algo = GCRY_MD_SHA512; | |||
| 3417 | } | |||
| 3418 | unsigned len = gcry_md_get_algo_dlen(algo); | |||
| 3419 | ||||
| 3420 | result_key->data = (unsigned char *)wmem_alloc(wmem_file_scope(), we_need); | |||
| 3421 | ||||
| 3422 | char *secret_with_length = ssh_string(secret->data, secret->length); | |||
| 3423 | ||||
| 3424 | if (gcry_md_open(&hd, algo, 0) == 0) { | |||
| 3425 | gcry_md_write(hd, secret_with_length, secret->length + 4); | |||
| 3426 | gcry_md_write(hd, exchange_hash, hash_length); | |||
| 3427 | 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); | |||
| 3428 | gcry_md_write(hd, global_data->session_id, hash_length); | |||
| 3429 | unsigned add_length = MIN(len, we_need)(((len) < (we_need)) ? (len) : (we_need)); | |||
| 3430 | memcpy(result_key->data, gcry_md_read(hd, 0), add_length); | |||
| 3431 | gcry_md_close(hd); | |||
| 3432 | } | |||
| 3433 | ||||
| 3434 | // expand key | |||
| 3435 | for (unsigned have = len; have < we_need; have += len) { | |||
| 3436 | if (gcry_md_open(&hd, algo, 0) == 0) { | |||
| 3437 | gcry_md_write(hd, secret_with_length, secret->length + 4); | |||
| 3438 | gcry_md_write(hd, exchange_hash, hash_length); | |||
| 3439 | gcry_md_write(hd, result_key->data+have-len, len); | |||
| 3440 | unsigned add_length = MIN(len, we_need - have)(((len) < (we_need - have)) ? (len) : (we_need - have)); | |||
| 3441 | memcpy(result_key->data+have, gcry_md_read(hd, 0), add_length); | |||
| 3442 | gcry_md_close(hd); | |||
| 3443 | } | |||
| 3444 | } | |||
| 3445 | ||||
| 3446 | result_key->length = we_need; | |||
| 3447 | } | |||
| 3448 | ||||
| 3449 | static void | |||
| 3450 | ssh_choose_enc_mac(struct ssh_flow_data *global_data) | |||
| 3451 | { | |||
| 3452 | for(int peer_cnt=0;peer_cnt<2;peer_cnt++){ | |||
| 3453 | struct ssh_peer_data * peer_data = &global_data->peer_data[peer_cnt]; | |||
| 3454 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].enc_proposals[peer_cnt], | |||
| 3455 | global_data->peer_data[SERVER_PEER_DATA1].enc_proposals[peer_cnt], | |||
| 3456 | &peer_data->enc); | |||
| 3457 | /* some ciphers have their own MAC so the "negotiated" one is meaningless */ | |||
| 3458 | if(peer_data->enc && (0 == strcmp(peer_data->enc, "aes128-gcm@openssh.com") || | |||
| 3459 | 0 == strcmp(peer_data->enc, "aes256-gcm@openssh.com"))) { | |||
| 3460 | peer_data->mac = wmem_strdup(wmem_file_scope(), (const char *)"<implicit>"); | |||
| 3461 | peer_data->mac_length = 16; | |||
| 3462 | peer_data->length_is_plaintext = 1; | |||
| 3463 | } | |||
| 3464 | else if(peer_data->enc && 0 == strcmp(peer_data->enc, "chacha20-poly1305@openssh.com")) { | |||
| 3465 | peer_data->mac = wmem_strdup(wmem_file_scope(), (const char *)"<implicit>"); | |||
| 3466 | peer_data->mac_length = 16; | |||
| 3467 | } | |||
| 3468 | else { | |||
| 3469 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].mac_proposals[peer_cnt], | |||
| 3470 | global_data->peer_data[SERVER_PEER_DATA1].mac_proposals[peer_cnt], | |||
| 3471 | &peer_data->mac); | |||
| 3472 | ssh_set_mac_length(peer_data); | |||
| 3473 | } | |||
| 3474 | ssh_choose_algo(global_data->peer_data[CLIENT_PEER_DATA0].comp_proposals[peer_cnt], | |||
| 3475 | global_data->peer_data[SERVER_PEER_DATA1].comp_proposals[peer_cnt], | |||
| 3476 | &peer_data->comp); | |||
| 3477 | } | |||
| 3478 | ||||
| 3479 | ssh_decryption_set_cipher_id(&global_data->peer_data[CLIENT_PEER_DATA0]); | |||
| 3480 | ssh_decryption_set_mac_id(&global_data->peer_data[CLIENT_PEER_DATA0]); | |||
| 3481 | ssh_decryption_set_cipher_id(&global_data->peer_data[SERVER_PEER_DATA1]); | |||
| 3482 | ssh_decryption_set_mac_id(&global_data->peer_data[SERVER_PEER_DATA1]); | |||
| 3483 | } | |||
| 3484 | ||||
| 3485 | static void | |||
| 3486 | ssh_decryption_set_cipher_id(struct ssh_peer_data *peer) | |||
| 3487 | { | |||
| 3488 | char *cipher_name = peer->enc; | |||
| 3489 | ||||
| 3490 | if (!cipher_name) { | |||
| 3491 | peer->cipher = NULL((void*)0); | |||
| 3492 | ws_debug("ERROR: cipher_name is NULL")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3492, __func__, "ERROR: cipher_name is NULL"); } } while (0 ); | |||
| 3493 | } else if (0 == strcmp(cipher_name, "chacha20-poly1305@openssh.com")) { // add chacha20-poly1305@openssh.com | |||
| 3494 | peer->cipher_id = GCRY_CIPHER_CHACHA20; | |||
| 3495 | } else if (0 == strcmp(cipher_name, "chacha20-poly1305")) { // add chacha20-poly1305 | |||
| 3496 | peer->cipher_id = GCRY_CIPHER_CHACHA20; | |||
| 3497 | } else if (0 == strcmp(cipher_name, "aes128-gcm@openssh.com")) { | |||
| 3498 | peer->cipher_id = CIPHER_AES128_GCM0x00040001; | |||
| 3499 | } else if (0 == strcmp(cipher_name, "aes128-gcm")) { | |||
| 3500 | peer->cipher_id = CIPHER_AES128_GCM0x00040001; | |||
| 3501 | } else if (0 == strcmp(cipher_name, "aes256-gcm@openssh.com")) { | |||
| 3502 | peer->cipher_id = CIPHER_AES256_GCM0x00040004; | |||
| 3503 | } else if (0 == strcmp(cipher_name, "aes256-gcm")) { | |||
| 3504 | peer->cipher_id = CIPHER_AES256_GCM0x00040004; | |||
| 3505 | } else if (0 == strcmp(cipher_name, "aes128-cbc")) { | |||
| 3506 | peer->cipher_id = CIPHER_AES128_CBC0x00020001; | |||
| 3507 | } else if (0 == strcmp(cipher_name, "aes192-cbc")) { | |||
| 3508 | peer->cipher_id = CIPHER_AES192_CBC0x00020002; | |||
| 3509 | } else if (0 == strcmp(cipher_name, "aes256-cbc")) { | |||
| 3510 | peer->cipher_id = CIPHER_AES256_CBC0x00020004; | |||
| 3511 | } else if (0 == strcmp(cipher_name, "aes128-ctr")) { | |||
| 3512 | peer->cipher_id = CIPHER_AES128_CTR0x00010001; | |||
| 3513 | } else if (0 == strcmp(cipher_name, "aes192-ctr")) { | |||
| 3514 | peer->cipher_id = CIPHER_AES192_CTR0x00010003; | |||
| 3515 | } else if (0 == strcmp(cipher_name, "aes256-ctr")) { | |||
| 3516 | peer->cipher_id = CIPHER_AES256_CTR0x00010004; | |||
| 3517 | } else if (0 == strcmp(cipher_name, "none")) { | |||
| 3518 | peer->cipher_id = CIPHER_NULL0x00080000; | |||
| 3519 | peer->length_is_plaintext = 1; | |||
| 3520 | } else { | |||
| 3521 | peer->cipher = NULL((void*)0); | |||
| 3522 | ws_debug("decryption not supported: %s", cipher_name)do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3522, __func__, "decryption not supported: %s", cipher_name ); } } while (0); | |||
| 3523 | } | |||
| 3524 | } | |||
| 3525 | ||||
| 3526 | static void | |||
| 3527 | ssh_decryption_set_mac_id(struct ssh_peer_data *peer) | |||
| 3528 | { | |||
| 3529 | char *mac_name = peer->mac; | |||
| 3530 | ||||
| 3531 | if (!mac_name) { | |||
| 3532 | peer->mac = NULL((void*)0); | |||
| 3533 | ws_debug("ERROR: mac_name is NULL")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3533, __func__, "ERROR: mac_name is NULL"); } } while (0); | |||
| 3534 | } else if (0 == strcmp(mac_name, "hmac-sha2-256")) { | |||
| 3535 | peer->mac_id = CIPHER_MAC_SHA2_2560x00020001; | |||
| 3536 | } else { | |||
| 3537 | 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" , 3537, __func__, "decryption MAC not supported: %s", mac_name ); } } while (0); | |||
| 3538 | } | |||
| 3539 | } | |||
| 3540 | ||||
| 3541 | static bool_Bool | |||
| 3542 | gcry_cipher_destroy_cb(wmem_allocator_t *allocator _U___attribute__((unused)), wmem_cb_event_t event _U___attribute__((unused)), void *user_data) | |||
| 3543 | { | |||
| 3544 | gcry_cipher_hd_t hd = (gcry_cipher_hd_t)user_data; | |||
| 3545 | ||||
| 3546 | gcry_cipher_close(hd); | |||
| 3547 | ||||
| 3548 | return false0; | |||
| 3549 | } | |||
| 3550 | ||||
| 3551 | static void | |||
| 3552 | ssh_decryption_setup_cipher(struct ssh_peer_data *peer_data, | |||
| 3553 | ssh_bignum *iv, ssh_bignum *key) | |||
| 3554 | { | |||
| 3555 | gcry_error_t err; | |||
| 3556 | gcry_cipher_hd_t *hd1, *hd2; | |||
| 3557 | ||||
| 3558 | hd1 = &peer_data->cipher; | |||
| 3559 | hd2 = &peer_data->cipher_2; | |||
| 3560 | ||||
| 3561 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) { | |||
| 3562 | if (gcry_cipher_open(hd1, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_STREAM, 0) || | |||
| 3563 | gcry_cipher_open(hd2, GCRY_CIPHER_CHACHA20, GCRY_CIPHER_MODE_STREAM, 0)) { | |||
| 3564 | gcry_cipher_close(*hd1); | |||
| 3565 | gcry_cipher_close(*hd2); | |||
| 3566 | 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" , 3566, __func__, "ssh: can't open chacha20 cipher handles"); } } while (0); | |||
| 3567 | return; | |||
| 3568 | } | |||
| 3569 | ||||
| 3570 | char k1[32]; | |||
| 3571 | char k2[32]; | |||
| 3572 | if(key->data){ | |||
| 3573 | memcpy(k1, key->data, 32); | |||
| 3574 | memcpy(k2, key->data + 32, 32); | |||
| 3575 | }else{ | |||
| 3576 | memset(k1, 0, 32); | |||
| 3577 | memset(k2, 0, 32); | |||
| 3578 | } | |||
| 3579 | ||||
| 3580 | ssh_debug_printf("ssh: cipher is chacha20\n"); | |||
| 3581 | ssh_print_data("key 1", k1, 32); | |||
| 3582 | ssh_print_data("key 2", k2, 32); | |||
| 3583 | ||||
| 3584 | if ((err = gcry_cipher_setkey(*hd1, k1, 32))) { | |||
| 3585 | gcry_cipher_close(*hd1); | |||
| 3586 | 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" , 3586, __func__, "ssh: can't set chacha20 cipher key %s", gcry_strerror (err)); } } while (0); | |||
| 3587 | return; | |||
| 3588 | } | |||
| 3589 | ||||
| 3590 | if ((err = gcry_cipher_setkey(*hd2, k2, 32))) { | |||
| 3591 | gcry_cipher_close(*hd1); | |||
| 3592 | gcry_cipher_close(*hd2); | |||
| 3593 | 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" , 3593, __func__, "ssh: can't set chacha20 cipher key %s", gcry_strerror (err)); } } while (0); | |||
| 3594 | return; | |||
| 3595 | } | |||
| 3596 | ||||
| 3597 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1); | |||
| 3598 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd2); | |||
| 3599 | ||||
| 3600 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id) { | |||
| 3601 | int iKeyLen = CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id?16:CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id?24:32; | |||
| 3602 | 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)) { | |||
| 3603 | gcry_cipher_close(*hd1); | |||
| 3604 | 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" , 3604, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0); | |||
| 3605 | return; | |||
| 3606 | } | |||
| 3607 | char k1[32], iv1[16]; | |||
| 3608 | if(key->data){ | |||
| 3609 | memcpy(k1, key->data, iKeyLen); | |||
| 3610 | }else{ | |||
| 3611 | memset(k1, 0, iKeyLen); | |||
| 3612 | } | |||
| 3613 | if(iv->data){ | |||
| 3614 | memcpy(iv1, iv->data, 16); | |||
| 3615 | }else{ | |||
| 3616 | memset(iv1, 0, 16); | |||
| 3617 | } | |||
| 3618 | ||||
| 3619 | ssh_debug_printf("ssh: cipher is aes%d-cbc\n", iKeyLen*8); | |||
| 3620 | ssh_print_data("key", k1, iKeyLen); | |||
| 3621 | ssh_print_data("iv", iv1, 16); | |||
| 3622 | ||||
| 3623 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) { | |||
| 3624 | gcry_cipher_close(*hd1); | |||
| 3625 | 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" , 3625, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0); | |||
| 3626 | 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" , 3626, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 3627 | return; | |||
| 3628 | } | |||
| 3629 | ||||
| 3630 | if ((err = gcry_cipher_setiv(*hd1, iv1, 16))) { | |||
| 3631 | gcry_cipher_close(*hd1); | |||
| 3632 | 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" , 3632, __func__, "ssh: can't set aes%d cipher iv", iKeyLen*8 ); } } while (0); | |||
| 3633 | 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" , 3633, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 3634 | return; | |||
| 3635 | } | |||
| 3636 | ||||
| 3637 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1); | |||
| 3638 | ||||
| 3639 | } else if (CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id) { | |||
| 3640 | int iKeyLen = CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id?16:CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id?24:32; | |||
| 3641 | 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)) { | |||
| 3642 | gcry_cipher_close(*hd1); | |||
| 3643 | 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" , 3643, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0); | |||
| 3644 | return; | |||
| 3645 | } | |||
| 3646 | char k1[32], iv1[16]; | |||
| 3647 | if(key->data){ | |||
| 3648 | memcpy(k1, key->data, iKeyLen); | |||
| 3649 | }else{ | |||
| 3650 | memset(k1, 0, iKeyLen); | |||
| 3651 | } | |||
| 3652 | if(iv->data){ | |||
| 3653 | memcpy(iv1, iv->data, 16); | |||
| 3654 | }else{ | |||
| 3655 | memset(iv1, 0, 16); | |||
| 3656 | } | |||
| 3657 | ||||
| 3658 | ssh_debug_printf("ssh: cipher is aes%d-ctr\n", iKeyLen*8); | |||
| 3659 | ssh_print_data("key", k1, iKeyLen); | |||
| 3660 | ssh_print_data("iv", iv1, 16); | |||
| 3661 | ||||
| 3662 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) { | |||
| 3663 | gcry_cipher_close(*hd1); | |||
| 3664 | 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" , 3664, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0); | |||
| 3665 | 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" , 3665, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 3666 | return; | |||
| 3667 | } | |||
| 3668 | ||||
| 3669 | if ((err = gcry_cipher_setctr(*hd1, iv1, 16))) { | |||
| 3670 | gcry_cipher_close(*hd1); | |||
| 3671 | 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" , 3671, __func__, "ssh: can't set aes%d cipher iv", iKeyLen*8 ); } } while (0); | |||
| 3672 | 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" , 3672, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 3673 | return; | |||
| 3674 | } | |||
| 3675 | ||||
| 3676 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1); | |||
| 3677 | ||||
| 3678 | } else if (CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) { | |||
| 3679 | int iKeyLen = CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id?16:32; | |||
| 3680 | 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)) { | |||
| 3681 | gcry_cipher_close(*hd1); | |||
| 3682 | 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" , 3682, __func__, "ssh: can't open aes%d cipher handle", iKeyLen *8); } } while (0); | |||
| 3683 | return; | |||
| 3684 | } | |||
| 3685 | ||||
| 3686 | char k1[32], iv2[12]; | |||
| 3687 | if(key->data){ | |||
| 3688 | memcpy(k1, key->data, iKeyLen); | |||
| 3689 | }else{ | |||
| 3690 | memset(k1, 0, iKeyLen); | |||
| 3691 | } | |||
| 3692 | if(iv->data){ | |||
| 3693 | memcpy(peer_data->iv, iv->data, 12); | |||
| 3694 | }else{ | |||
| 3695 | memset(iv2, 0, 12); | |||
| 3696 | } | |||
| 3697 | ||||
| 3698 | ssh_debug_printf("ssh: cipher is aes%d-gcm\n", iKeyLen*8); | |||
| 3699 | ssh_print_data("key", k1, iKeyLen); | |||
| 3700 | ssh_print_data("iv", peer_data->iv, 12); | |||
| 3701 | ||||
| 3702 | if ((err = gcry_cipher_setkey(*hd1, k1, iKeyLen))) { | |||
| 3703 | gcry_cipher_close(*hd1); | |||
| 3704 | 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" , 3704, __func__, "ssh: can't set aes%d cipher key", iKeyLen* 8); } } while (0); | |||
| 3705 | 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" , 3705, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 3706 | return; | |||
| 3707 | } | |||
| 3708 | ||||
| 3709 | wmem_register_callback(wmem_file_scope(), gcry_cipher_destroy_cb, *hd1); | |||
| 3710 | ||||
| 3711 | } else { | |||
| 3712 | ssh_debug_printf("ssh: cipher (%d) is unknown or not set\n", peer_data->cipher_id); | |||
| 3713 | } | |||
| 3714 | } | |||
| 3715 | ||||
| 3716 | static void | |||
| 3717 | ssh_decryption_setup_mac(struct ssh_peer_data *peer_data, | |||
| 3718 | ssh_bignum *iv) | |||
| 3719 | { | |||
| 3720 | if(peer_data->mac_id == CIPHER_MAC_SHA2_2560x00020001){ | |||
| 3721 | if(iv->data){ | |||
| 3722 | memcpy(peer_data->hmac_iv, iv->data, 32); | |||
| 3723 | }else{ | |||
| 3724 | memset(peer_data->hmac_iv, 0, 32); | |||
| 3725 | } | |||
| 3726 | peer_data->hmac_iv_len = 32; | |||
| 3727 | ssh_debug_printf("ssh: mac is hmac-sha2-256\n"); | |||
| 3728 | ssh_print_data("iv", peer_data->hmac_iv, peer_data->hmac_iv_len); | |||
| 3729 | }else{ | |||
| 3730 | ws_debug("ssh: unsupported MAC")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3730, __func__, "ssh: unsupported MAC"); } } while (0); | |||
| 3731 | } | |||
| 3732 | } | |||
| 3733 | ||||
| 3734 | /* libgcrypt wrappers for HMAC/message digest operations {{{ */ | |||
| 3735 | /* hmac abstraction layer */ | |||
| 3736 | #define SSH_HMACgcry_md_hd_t gcry_md_hd_t | |||
| 3737 | ||||
| 3738 | static inline int | |||
| 3739 | ssh_hmac_init(SSH_HMACgcry_md_hd_t* md, const void * key, int len, int algo) | |||
| 3740 | { | |||
| 3741 | gcry_error_t err; | |||
| 3742 | const char *err_str, *err_src; | |||
| 3743 | ||||
| 3744 | err = gcry_md_open(md,algo, GCRY_MD_FLAG_HMAC); | |||
| 3745 | if (err != 0) { | |||
| 3746 | err_str = gcry_strerror(err); | |||
| 3747 | err_src = gcry_strsource(err); | |||
| 3748 | ssh_debug_printf("ssh_hmac_init(): gcry_md_open failed %s/%s", err_str, err_src); | |||
| 3749 | return -1; | |||
| 3750 | } | |||
| 3751 | err = gcry_md_setkey(*(md), key, len); | |||
| 3752 | if (err != 0) { | |||
| 3753 | err_str = gcry_strerror(err); | |||
| 3754 | err_src = gcry_strsource(err); | |||
| 3755 | ssh_debug_printf("ssh_hmac_init(): gcry_md_setkey(..., ..., %d) failed %s/%s", len, err_str, err_src); | |||
| 3756 | return -1; | |||
| 3757 | } | |||
| 3758 | return 0; | |||
| 3759 | } | |||
| 3760 | ||||
| 3761 | static inline void | |||
| 3762 | ssh_hmac_update(SSH_HMACgcry_md_hd_t* md, const void* data, int len) | |||
| 3763 | { | |||
| 3764 | gcry_md_write(*(md), data, len); | |||
| 3765 | } | |||
| 3766 | ||||
| 3767 | static inline void | |||
| 3768 | ssh_hmac_final(SSH_HMACgcry_md_hd_t* md, unsigned char* data, unsigned* datalen) | |||
| 3769 | { | |||
| 3770 | int algo; | |||
| 3771 | unsigned len; | |||
| 3772 | ||||
| 3773 | algo = gcry_md_get_algo (*(md)); | |||
| 3774 | len = gcry_md_get_algo_dlen(algo); | |||
| 3775 | DISSECTOR_ASSERT(len <= *datalen)((void) ((len <= *datalen) ? (void)0 : (proto_report_dissector_bug ("%s:%u: failed assertion \"%s\"", "epan/dissectors/packet-ssh.c" , 3775, "len <= *datalen")))); | |||
| 3776 | memcpy(data, gcry_md_read(*(md), algo), len); | |||
| 3777 | *datalen = len; | |||
| 3778 | } | |||
| 3779 | ||||
| 3780 | static inline void | |||
| 3781 | ssh_hmac_cleanup(SSH_HMACgcry_md_hd_t* md) | |||
| 3782 | { | |||
| 3783 | gcry_md_close(*(md)); | |||
| 3784 | } | |||
| 3785 | /* libgcrypt wrappers for HMAC/message digest operations }}} */ | |||
| 3786 | ||||
| 3787 | /* Decryption integrity check {{{ */ | |||
| 3788 | ||||
| 3789 | static int | |||
| 3790 | ssh_get_digest_by_id(unsigned mac_id) | |||
| 3791 | { | |||
| 3792 | if(mac_id==CIPHER_MAC_SHA2_2560x00020001){ | |||
| 3793 | return GCRY_MD_SHA256; | |||
| 3794 | } | |||
| 3795 | return -1; | |||
| 3796 | } | |||
| 3797 | ||||
| 3798 | static void | |||
| 3799 | ssh_calc_mac(struct ssh_peer_data *peer_data, uint32_t seqnr, uint8_t* data, uint32_t datalen, uint8_t* calc_mac) | |||
| 3800 | { | |||
| 3801 | SSH_HMACgcry_md_hd_t hm; | |||
| 3802 | int md; | |||
| 3803 | uint32_t len; | |||
| 3804 | uint8_t buf[DIGEST_MAX_SIZE48]; | |||
| 3805 | ||||
| 3806 | md=ssh_get_digest_by_id(peer_data->mac_id); | |||
| 3807 | // ssl_debug_printf("ssh_check_mac mac type:%s md %d\n", | |||
| 3808 | // ssl_cipher_suite_dig(decoder->cipher_suite)->name, md); | |||
| 3809 | ||||
| 3810 | memset(calc_mac, 0, DIGEST_MAX_SIZE48); | |||
| 3811 | ||||
| 3812 | if (md == -1) { | |||
| 3813 | return; | |||
| 3814 | } | |||
| 3815 | if (ssh_hmac_init(&hm, peer_data->hmac_iv, peer_data->hmac_iv_len, md) != 0) | |||
| 3816 | return; | |||
| 3817 | ||||
| 3818 | /* hash sequence number */ | |||
| 3819 | phton32(buf, seqnr); | |||
| 3820 | ||||
| 3821 | ssh_print_data("Mac IV", peer_data->hmac_iv, peer_data->hmac_iv_len); | |||
| 3822 | ssh_print_data("Mac seq", buf, 4); | |||
| 3823 | ssh_print_data("Mac data", data, datalen); | |||
| 3824 | ||||
| 3825 | ssh_hmac_update(&hm,buf,4); | |||
| 3826 | ||||
| 3827 | ssh_hmac_update(&hm,data,datalen); | |||
| 3828 | ||||
| 3829 | /* get digest and digest len*/ | |||
| 3830 | len = sizeof(buf); | |||
| 3831 | ssh_hmac_final(&hm,buf,&len); | |||
| 3832 | ssh_hmac_cleanup(&hm); | |||
| 3833 | ssh_print_data("Mac", buf, len); | |||
| 3834 | memcpy(calc_mac, buf, len); | |||
| 3835 | ||||
| 3836 | return; | |||
| 3837 | } | |||
| 3838 | /* Decryption integrity check }}} */ | |||
| 3839 | ||||
| 3840 | static ssh_packet_info_t * | |||
| 3841 | ssh_get_packet_info(packet_info *pinfo, bool_Bool is_response) | |||
| 3842 | { | |||
| 3843 | ssh_packet_info_t *packet = (ssh_packet_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_ssh, 0); | |||
| 3844 | if(!packet){ | |||
| 3845 | packet = wmem_new0(wmem_file_scope(), ssh_packet_info_t)((ssh_packet_info_t*)wmem_alloc0((wmem_file_scope()), sizeof( ssh_packet_info_t))); | |||
| 3846 | packet->from_server = is_response; | |||
| 3847 | packet->messages = NULL((void*)0); | |||
| 3848 | p_add_proto_data(wmem_file_scope(), pinfo, proto_ssh, 0, packet); | |||
| 3849 | } | |||
| 3850 | return packet; | |||
| 3851 | } | |||
| 3852 | ||||
| 3853 | static unsigned | |||
| 3854 | ssh_decrypt_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 3855 | struct ssh_peer_data *peer_data, int offset) | |||
| 3856 | { | |||
| 3857 | bool_Bool is_response = ssh_peer_data_from_server(peer_data); | |||
| 3858 | ||||
| 3859 | gcry_error_t err; | |||
| 3860 | unsigned message_length = 0, seqnr; | |||
| 3861 | char *plain = NULL((void*)0), *mac; | |||
| 3862 | unsigned mac_len, data_len = 0; | |||
| 3863 | uint8_t calc_mac[DIGEST_MAX_SIZE48]; | |||
| 3864 | memset(calc_mac, 0, DIGEST_MAX_SIZE48); | |||
| 3865 | unsigned remaining = tvb_captured_length_remaining(tvb, offset); | |||
| 3866 | ||||
| 3867 | mac_len = peer_data->mac_length; | |||
| 3868 | seqnr = peer_data->sequence_number; | |||
| 3869 | ||||
| 3870 | /* General algorithm: | |||
| 3871 | * 1. If there are not enough bytes for the packet_length, and we can | |||
| 3872 | * do reassembly, ask for one more segment. | |||
| 3873 | * 2. Retrieve packet_length (encrypted in some modes). | |||
| 3874 | * 3. Sanity check packet_length (the field is 4 bytes, but packet_length | |||
| 3875 | * is unlikely to be much larger than 32768, which provides good indication | |||
| 3876 | * a packet is continuation data or, in some modes, failed decryption. | |||
| 3877 | * https://www.rfc-editor.org/rfc/rfc4253.html#section-6.1 ) | |||
| 3878 | * 4. If there are not enough bytes for packet_length, and we can do | |||
| 3879 | * reassembly, tell the TCP dissector how many more bytes we need. | |||
| 3880 | * 5. If the packet is truncated and we cannot reassemble, at this | |||
| 3881 | * point we conclude that it is the next SSH packet, and advance the | |||
| 3882 | * sequence number, invocation_counter, etc. before throwing an exception. | |||
| 3883 | * 6. If we do have all the data, we decrypt and check the MAC before | |||
| 3884 | * doing all that. (XXX - Advancing seqnr regardless could make sense | |||
| 3885 | * in some ciphers.) | |||
| 3886 | * 7. Possibly the MAC should be checked before decryption in some ciphers | |||
| 3887 | * if we have all the data; possibly there should be a "do not check the | |||
| 3888 | * MAC" preference a la TLS. | |||
| 3889 | */ | |||
| 3890 | ||||
| 3891 | if (GCRY_CIPHER_CHACHA20 == peer_data->cipher_id) { | |||
| 3892 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) { | |||
| 3893 | /* Can do reassembly, and the packet length is split across | |||
| 3894 | * segment boundaries. */ | |||
| 3895 | pinfo->desegment_offset = offset; | |||
| 3896 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 3897 | return tvb_captured_length(tvb); | |||
| 3898 | } | |||
| 3899 | ||||
| 3900 | const char *ctext = (const char *)tvb_get_ptr(tvb, offset, 4); | |||
| 3901 | uint8_t plain_length_buf[4]; | |||
| 3902 | ||||
| 3903 | if (!ssh_decrypt_chacha20(peer_data->cipher_2, seqnr, 0, ctext, 4, | |||
| 3904 | plain_length_buf, 4)) { | |||
| 3905 | ws_debug("ERROR: could not decrypt packet len")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3905, __func__, "ERROR: could not decrypt packet len"); } } while (0); | |||
| 3906 | return tvb_captured_length(tvb); | |||
| 3907 | } | |||
| 3908 | ||||
| 3909 | message_length = pntoh32(plain_length_buf); | |||
| 3910 | ||||
| 3911 | ssh_debug_printf("chachapoly_crypt seqnr=%d [%u]\n", seqnr, message_length); | |||
| 3912 | ||||
| 3913 | ssh_debug_printf("%s plain for seq = %d len = %u\n", is_response?"s2c":"c2s", seqnr, message_length); | |||
| 3914 | if (message_length > SSH_MAX_PACKET_LEN32768) { | |||
| 3915 | 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" , 3915, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0); | |||
| 3916 | return tvb_captured_length(tvb); | |||
| 3917 | } | |||
| 3918 | if (remaining < message_length + 4 + mac_len) { | |||
| 3919 | // Need desegmentation; as "the chacha20-poly1305@openssh.com AEAD | |||
| 3920 | // uses the sequence number as an initialisation vector (IV) to | |||
| 3921 | // generate its per-packet MAC key and is otherwise stateless | |||
| 3922 | // between packets," we need no special handling here. | |||
| 3923 | // https://www.ietf.org/id/draft-miller-sshm-strict-kex-01.html | |||
| 3924 | // | |||
| 3925 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 3926 | pinfo->desegment_offset = offset; | |||
| 3927 | pinfo->desegment_len = message_length + 4 + mac_len - remaining; | |||
| 3928 | return tvb_captured_length(tvb); | |||
| 3929 | } | |||
| 3930 | // If we can't desegment, we will have an exception below in | |||
| 3931 | // the tvb_get_ptr. Advance the sequence number so that the | |||
| 3932 | // next SSH packet start will decrypt correctly. | |||
| 3933 | peer_data->sequence_number++; | |||
| 3934 | } | |||
| 3935 | ||||
| 3936 | plain = (char *)wmem_alloc0(pinfo->pool, message_length+4); | |||
| 3937 | memcpy(plain, plain_length_buf, 4); | |||
| 3938 | const char *ctext2 = (const char *)tvb_get_ptr(tvb, offset+4, | |||
| 3939 | message_length); | |||
| 3940 | ||||
| 3941 | /* XXX - "Once the entire packet has been received, the MAC MUST be | |||
| 3942 | * checked before decryption," but we decrypt first. | |||
| 3943 | * https://datatracker.ietf.org/doc/html/draft-ietf-sshm-chacha20-poly1305-01 | |||
| 3944 | */ | |||
| 3945 | if (!ssh_decrypt_chacha20(peer_data->cipher, seqnr, 1, ctext2, | |||
| 3946 | message_length, plain+4, message_length)) { | |||
| 3947 | ws_debug("ERROR: could not decrypt packet payload")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3947, __func__, "ERROR: could not decrypt packet payload"); } } while (0); | |||
| 3948 | return tvb_captured_length(tvb); | |||
| 3949 | } | |||
| 3950 | ||||
| 3951 | mac = (char *)tvb_get_ptr(tvb, offset + 4 + message_length, mac_len); | |||
| 3952 | char poly_key[32], iv[16]; | |||
| 3953 | ||||
| 3954 | memset(poly_key, 0, 32); | |||
| 3955 | memset(iv, 0, 8); | |||
| 3956 | phton64(iv+8, (uint64_t)seqnr); | |||
| 3957 | gcry_cipher_setiv(peer_data->cipher, iv, mac_len); | |||
| 3958 | gcry_cipher_encrypt(peer_data->cipher, poly_key, 32, poly_key, 32); | |||
| 3959 | ||||
| 3960 | gcry_mac_hd_t mac_hd; | |||
| 3961 | gcry_mac_open(&mac_hd, GCRY_MAC_POLY1305, 0, NULL((void*)0)); | |||
| 3962 | gcry_mac_setkey(mac_hd, poly_key, 32); | |||
| 3963 | gcry_mac_write(mac_hd, ctext, 4); | |||
| 3964 | gcry_mac_write(mac_hd, ctext2, message_length); | |||
| 3965 | if (gcry_mac_verify(mac_hd, mac, mac_len)) { | |||
| 3966 | ws_debug("ssh: MAC does not match")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 3966, __func__, "ssh: MAC does not match"); } } while (0); | |||
| 3967 | } | |||
| 3968 | size_t buflen = DIGEST_MAX_SIZE48; | |||
| 3969 | gcry_mac_read(mac_hd, calc_mac, &buflen); | |||
| 3970 | gcry_mac_close(mac_hd); | |||
| 3971 | ||||
| 3972 | data_len = message_length + 4; | |||
| 3973 | ||||
| 3974 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr); | |||
| 3975 | ssh_print_data("", plain, message_length+4); | |||
| 3976 | } else if (CIPHER_AES128_GCM0x00040001 == peer_data->cipher_id || CIPHER_AES256_GCM0x00040004 == peer_data->cipher_id) { | |||
| 3977 | ||||
| 3978 | /* AES GCM for Secure Shell [RFC 5647] */ | |||
| 3979 | /* The message length is Additional Authenticated Data */ | |||
| 3980 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) { | |||
| 3981 | /* Can do reassembly, and the packet length is split across | |||
| 3982 | * segment boundaries. */ | |||
| 3983 | pinfo->desegment_offset = offset; | |||
| 3984 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 3985 | return tvb_captured_length(tvb); | |||
| 3986 | } | |||
| 3987 | message_length = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000); | |||
| 3988 | ssh_debug_printf("length: %d, remaining: %d\n", message_length, remaining); | |||
| 3989 | /* The minimum size of a packet (not counting mac) is 16. */ | |||
| 3990 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 16) { | |||
| 3991 | 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" , 3991, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0); | |||
| 3992 | return tvb_captured_length(tvb); | |||
| 3993 | } | |||
| 3994 | ||||
| 3995 | /* SSH requires that the data to be encrypted (not including the AAD, | |||
| 3996 | * so message_length) be a multiple of the block size, 16 octets */ | |||
| 3997 | if (message_length % 16 != 0) { | |||
| 3998 | ssh_debug_printf("length not a multiple of block length (16)!\n"); | |||
| 3999 | } | |||
| 4000 | ||||
| 4001 | if (message_length + 4 + mac_len > remaining) { | |||
| 4002 | // Need desegmentation; as the message length was unencrypted | |||
| 4003 | // AAD, we need no special handling here. | |||
| 4004 | if (pinfo->can_desegment) { | |||
| 4005 | pinfo->desegment_offset = offset; | |||
| 4006 | pinfo->desegment_len = message_length + 4 + mac_len - remaining; | |||
| 4007 | return tvb_captured_length(tvb); | |||
| 4008 | } | |||
| 4009 | // If we can't desegment, we will have an exception below in | |||
| 4010 | // the tvb_get_ptr. Advance the sequence number (less crucial | |||
| 4011 | // than with ChaCha20, as it's not an input.) | |||
| 4012 | peer_data->sequence_number++; | |||
| 4013 | } | |||
| 4014 | ||||
| 4015 | /* Set the IV and increment the invocation_counter for the next | |||
| 4016 | * packet. Do this before retrieving the ciphertext with tvb_get_ptr | |||
| 4017 | * in case this packet is truncated. | |||
| 4018 | */ | |||
| 4019 | if ((err = gcry_cipher_setiv(peer_data->cipher, peer_data->iv, 12))) { | |||
| 4020 | //gcry_cipher_close(peer_data->cipher); | |||
| 4021 | //Don't close this unless we also remove the wmem callback | |||
| 4022 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests | |||
| 4023 | #ifndef _WIN32 | |||
| 4024 | 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" , 4024, __func__, "ssh: can't set aes128 cipher iv"); } } while (0); | |||
| 4025 | 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" , 4025, __func__, "libgcrypt: %d %s %s", gcry_err_code(err), gcry_strsource (err), gcry_strerror(err)); } } while (0); | |||
| 4026 | #endif //ndef _WIN32 | |||
| 4027 | return tvb_captured_length(tvb); | |||
| 4028 | } | |||
| 4029 | // Increment invocation_counter for next packet | |||
| 4030 | int idx = 12; | |||
| 4031 | do{ | |||
| 4032 | idx -= 1; | |||
| 4033 | peer_data->iv[idx] += 1; | |||
| 4034 | }while(idx>4 && peer_data->iv[idx]==0); | |||
| 4035 | ||||
| 4036 | const char *ctext = (const char *)tvb_get_ptr(tvb, offset + 4, | |||
| 4037 | message_length); | |||
| 4038 | plain = (char *)wmem_alloc(pinfo->pool, message_length+4); | |||
| 4039 | phton32(plain, message_length); | |||
| 4040 | ||||
| 4041 | if ((err = gcry_cipher_authenticate(peer_data->cipher, plain, 4))) { | |||
| 4042 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests | |||
| 4043 | #ifndef _WIN32 | |||
| 4044 | 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" , 4044, __func__, "can't authenticate using aes128-gcm: %s\n" , gpg_strerror(err)); } } while (0); | |||
| 4045 | #endif //ndef _WIN32 | |||
| 4046 | return tvb_captured_length(tvb); | |||
| 4047 | } | |||
| 4048 | ||||
| 4049 | if ((err = gcry_cipher_decrypt(peer_data->cipher, plain+4, message_length, | |||
| 4050 | ctext, message_length))) { | |||
| 4051 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests | |||
| 4052 | #ifndef _WIN32 | |||
| 4053 | 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" , 4053, __func__, "can't decrypt aes-gcm %d %s %s", gcry_err_code (err), gcry_strsource(err), gcry_strerror(err)); } } while (0 ); | |||
| 4054 | ||||
| 4055 | #endif //ndef _WIN32 | |||
| 4056 | return tvb_captured_length(tvb); | |||
| 4057 | } | |||
| 4058 | ||||
| 4059 | if (gcry_cipher_gettag (peer_data->cipher, calc_mac, 16)) { | |||
| 4060 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests | |||
| 4061 | #ifndef _WIN32 | |||
| 4062 | 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" , 4062, __func__, "aes128-gcm, gcry_cipher_gettag() failed\n" ); } } while (0); | |||
| 4063 | #endif //ndef _WIN32 | |||
| 4064 | return tvb_captured_length(tvb); | |||
| 4065 | } | |||
| 4066 | ||||
| 4067 | if ((err = gcry_cipher_reset(peer_data->cipher)gcry_cipher_ctl ((peer_data->cipher), GCRYCTL_RESET, ((void *)0), 0))) { | |||
| 4068 | // TODO: temporary work-around as long as a Windows python bug is triggered by automated tests | |||
| 4069 | #ifndef _WIN32 | |||
| 4070 | 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" , 4070, __func__, "aes-gcm, gcry_cipher_reset failed: %s\n", gpg_strerror (err)); } } while (0); | |||
| 4071 | #endif //ndef _WIN32 | |||
| 4072 | return tvb_captured_length(tvb); | |||
| 4073 | } | |||
| 4074 | ||||
| 4075 | data_len = message_length + 4; | |||
| 4076 | ||||
| 4077 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr); | |||
| 4078 | ssh_print_data("", plain, message_length+4); | |||
| 4079 | ||||
| 4080 | } else if (CIPHER_AES128_CBC0x00020001 == peer_data->cipher_id || CIPHER_AES128_CTR0x00010001 == peer_data->cipher_id || | |||
| 4081 | CIPHER_AES192_CBC0x00020002 == peer_data->cipher_id || CIPHER_AES192_CTR0x00010003 == peer_data->cipher_id || | |||
| 4082 | CIPHER_AES256_CBC0x00020004 == peer_data->cipher_id || CIPHER_AES256_CTR0x00010004 == peer_data->cipher_id) { | |||
| 4083 | ||||
| 4084 | 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" , 4084, __func__, "Getting raw bytes of length %d", tvb_reported_length_remaining (tvb, offset)); } } while (0); | |||
| 4085 | /* In CBC and CTR mode, the message length is encrypted as well. | |||
| 4086 | * We need to decrypt one block, 16 octets, to get the length. | |||
| 4087 | */ | |||
| 4088 | if (ssh_desegment && pinfo->can_desegment && remaining < 16) { | |||
| 4089 | /* Can do reassembly, and the packet length is split across | |||
| 4090 | * segment boundaries. */ | |||
| 4091 | pinfo->desegment_offset = offset; | |||
| 4092 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 4093 | return tvb_captured_length(tvb); | |||
| 4094 | } | |||
| 4095 | /* Do we already have the first block decrypted from when the packet | |||
| 4096 | * was too large and segmented? | |||
| 4097 | */ | |||
| 4098 | if (!peer_data->plain0_valid) { | |||
| 4099 | const char *cypher_buf0 = (const char *)tvb_get_ptr(tvb, offset, 16); | |||
| 4100 | ||||
| 4101 | if (gcry_cipher_decrypt(peer_data->cipher, peer_data->plain0, 16, cypher_buf0, 16)) | |||
| 4102 | { | |||
| 4103 | ws_debug("can\'t decrypt aes128")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4103, __func__, "can\'t decrypt aes128"); } } while (0); | |||
| 4104 | return tvb_captured_length(tvb); | |||
| 4105 | } | |||
| 4106 | } | |||
| 4107 | ||||
| 4108 | message_length = pntoh32(peer_data->plain0); | |||
| 4109 | ||||
| 4110 | /* The message_length value doesn't include the length of the | |||
| 4111 | * message_length field itself, so it must be at least 12 bytes. | |||
| 4112 | */ | |||
| 4113 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 12){ | |||
| 4114 | 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" , 4114, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0); | |||
| 4115 | return tvb_captured_length(tvb); | |||
| 4116 | } | |||
| 4117 | ||||
| 4118 | /* SSH requires that the data to be encrypted (message_length+4) | |||
| 4119 | * be a multiple of the block size, 16 octets. */ | |||
| 4120 | if (message_length % 16 != 12) { | |||
| 4121 | ssh_debug_printf("total length not a multiple of block length (16)!\n"); | |||
| 4122 | } | |||
| 4123 | if (remaining < message_length + 4 + mac_len) { | |||
| 4124 | /* Need desegmentation | |||
| 4125 | * | |||
| 4126 | * We will be handed the full encrypted packet again. We can either | |||
| 4127 | * store the decrypted first block, or will need to reset the CTR | |||
| 4128 | * or IV appropriately before decrypting the first block again. | |||
| 4129 | * libgcrypt does not provide an easy way to get the current value | |||
| 4130 | * of the CTR or (or IV/last block for CBC), so we just store the | |||
| 4131 | * decrypted first block. | |||
| 4132 | */ | |||
| 4133 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 4134 | 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" , 4135, __func__, " need_desegmentation: offset = %d, reported_length_remaining = %d\n" , offset, tvb_reported_length_remaining(tvb, offset)); } } while (0) | |||
| 4135 | offset, tvb_reported_length_remaining(tvb, offset))do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4135, __func__, " need_desegmentation: offset = %d, reported_length_remaining = %d\n" , offset, tvb_reported_length_remaining(tvb, offset)); } } while (0); | |||
| 4136 | peer_data->plain0_valid = true1; | |||
| 4137 | pinfo->desegment_offset = offset; | |||
| 4138 | pinfo->desegment_len = message_length + 4 + mac_len - remaining; | |||
| 4139 | return tvb_captured_length(tvb); | |||
| 4140 | } else { | |||
| 4141 | // If we can't desegment, we will have an exception below in | |||
| 4142 | // the tvb_get_ptr. Advance the sequence number so that the | |||
| 4143 | // the hash will work for the next packet. | |||
| 4144 | // | |||
| 4145 | // XXX - In CTR mode, we should advance the CTR based on the | |||
| 4146 | // known length so we can dissect the next block. We would | |||
| 4147 | // also need to reset the CTR after failing to dissect a | |||
| 4148 | // packet_length on the continuation data that comes next. | |||
| 4149 | peer_data->sequence_number++; | |||
| 4150 | } | |||
| 4151 | } | |||
| 4152 | peer_data->plain0_valid = false0; | |||
| 4153 | plain = (char *)wmem_alloc(pinfo->pool, message_length+4); | |||
| 4154 | memcpy(plain, peer_data->plain0, 16); | |||
| 4155 | ||||
| 4156 | if (message_length - 12 > 0) { | |||
| 4157 | /* All of these functions actually do handle the case where | |||
| 4158 | * there is no data left, so the check is unnecessary. | |||
| 4159 | */ | |||
| 4160 | char *ct = (char *)tvb_get_ptr(tvb, offset + 16, message_length - 12); | |||
| 4161 | if ((err = gcry_cipher_decrypt(peer_data->cipher, plain + 16, message_length - 12, ct, message_length - 12))) | |||
| 4162 | { | |||
| 4163 | 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" , 4163, __func__, "can't decrypt aes-cbc/ctr %d %s %s", gcry_err_code (err), gcry_strsource(err), gcry_strerror(err)); } } while (0 ); | |||
| 4164 | return tvb_captured_length(tvb); | |||
| 4165 | } | |||
| 4166 | } | |||
| 4167 | ||||
| 4168 | ssh_debug_printf("%s plain text seq=%d", is_response?"s2c":"c2s",seqnr); | |||
| 4169 | ssh_print_data("", plain, message_length+4); | |||
| 4170 | ||||
| 4171 | data_len = message_length + 4; | |||
| 4172 | ||||
| 4173 | // XXX - In -etm modes, should calculate MAC based on ciphertext. | |||
| 4174 | ssh_calc_mac(peer_data, seqnr, plain, data_len, calc_mac); | |||
| 4175 | } else if (CIPHER_NULL0x00080000 == peer_data->cipher_id) { | |||
| 4176 | if (ssh_desegment && pinfo->can_desegment && remaining < 4) { | |||
| 4177 | /* Can do reassembly, and the packet length is split across | |||
| 4178 | * segment boundaries. */ | |||
| 4179 | pinfo->desegment_offset = offset; | |||
| 4180 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 4181 | return tvb_captured_length(tvb); | |||
| 4182 | } | |||
| 4183 | message_length = tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000); | |||
| 4184 | ssh_debug_printf("length: %d, remaining: %d\n", message_length, remaining); | |||
| 4185 | if (message_length > SSH_MAX_PACKET_LEN32768 || message_length < 8) { | |||
| 4186 | 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" , 4186, __func__, "ssh: unreasonable message length %u", message_length ); } } while (0); | |||
| 4187 | return tvb_captured_length(tvb); | |||
| 4188 | } | |||
| 4189 | ||||
| 4190 | if (message_length + 4 + mac_len > remaining) { | |||
| 4191 | // Need desegmentation; as the message length was unencrypted | |||
| 4192 | // AAD, we need no special handling here. | |||
| 4193 | if (pinfo->can_desegment) { | |||
| 4194 | pinfo->desegment_offset = offset; | |||
| 4195 | pinfo->desegment_len = message_length + 4 + mac_len - remaining; | |||
| 4196 | return tvb_captured_length(tvb); | |||
| 4197 | } | |||
| 4198 | // If we can't desegment, we will have an exception below in | |||
| 4199 | // the tvb_memdup. Advance the sequence number (not crucial). | |||
| 4200 | peer_data->sequence_number++; | |||
| 4201 | } | |||
| 4202 | data_len = message_length + 4; | |||
| 4203 | plain = tvb_memdup(pinfo->pool, tvb, offset, data_len); | |||
| 4204 | ||||
| 4205 | // XXX - In -etm modes, should calculate MAC based on ciphertext. | |||
| 4206 | ssh_calc_mac(peer_data, seqnr, plain, data_len, calc_mac); | |||
| 4207 | } | |||
| 4208 | ||||
| 4209 | if (mac_len && data_len) { | |||
| 4210 | mac = (char *)tvb_get_ptr(tvb, offset + data_len, mac_len); | |||
| 4211 | if (!memcmp(mac, calc_mac, mac_len)){ | |||
| 4212 | ws_noisy("MAC OK")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_NOISY, "epan/dissectors/packet-ssh.c" , 4212, __func__, "MAC OK"); } } while (0); | |||
| 4213 | }else{ | |||
| 4214 | ws_debug("MAC ERR")do { if (1) { ws_log_full("packet-ssh", LOG_LEVEL_DEBUG, "epan/dissectors/packet-ssh.c" , 4214, __func__, "MAC ERR"); } } while (0); | |||
| 4215 | /* Bad MAC, just show the packet as encrypted. We can get | |||
| 4216 | * this for a known encryption type with no keys currently. */ | |||
| 4217 | if (!ssh_ignore_mac_failed) { | |||
| 4218 | return tvb_captured_length(tvb); | |||
| 4219 | } | |||
| 4220 | } | |||
| 4221 | } | |||
| 4222 | ||||
| 4223 | if(plain){ | |||
| 4224 | // Save message | |||
| 4225 | ||||
| 4226 | ssh_packet_info_t *packet = ssh_get_packet_info(pinfo, is_response); | |||
| 4227 | ||||
| 4228 | int record_id = tvb_raw_offset(tvb)+offset; | |||
| 4229 | ssh_message_info_t *message; | |||
| 4230 | ||||
| 4231 | message = wmem_new(wmem_file_scope(), ssh_message_info_t)((ssh_message_info_t*)wmem_alloc((wmem_file_scope()), sizeof( ssh_message_info_t))); | |||
| 4232 | message->sequence_number = peer_data->sequence_number++; | |||
| 4233 | message->plain_data = wmem_memdup(wmem_file_scope(), plain, data_len); | |||
| 4234 | message->data_len = data_len; | |||
| 4235 | message->id = record_id; | |||
| 4236 | message->next = NULL((void*)0); | |||
| 4237 | memcpy(message->calc_mac, calc_mac, DIGEST_MAX_SIZE48); | |||
| 4238 | ssh_debug_printf("%s->sequence_number++ > %d\n", is_response?"server":"client", peer_data->sequence_number); | |||
| 4239 | ||||
| 4240 | ssh_message_info_t **pmessage = &packet->messages; | |||
| 4241 | while(*pmessage){ | |||
| 4242 | pmessage = &(*pmessage)->next; | |||
| 4243 | } | |||
| 4244 | *pmessage = message; | |||
| 4245 | } | |||
| 4246 | ||||
| 4247 | offset += message_length + mac_len + 4; | |||
| 4248 | return offset; | |||
| 4249 | } | |||
| 4250 | ||||
| 4251 | static bool_Bool | |||
| 4252 | ssh_decrypt_chacha20(gcry_cipher_hd_t hd, | |||
| 4253 | uint32_t seqnr, uint32_t counter, const unsigned char *ctext, unsigned ctext_len, | |||
| 4254 | unsigned char *plain, unsigned plain_len) | |||
| 4255 | { | |||
| 4256 | unsigned char seq[8]; | |||
| 4257 | unsigned char iv[16]; | |||
| 4258 | ||||
| 4259 | phton64(seq, (uint64_t)seqnr); | |||
| 4260 | ||||
| 4261 | // chacha20 uses a different cipher handle for the packet payload & length | |||
| 4262 | // the payload uses a block counter | |||
| 4263 | if (counter) { | |||
| 4264 | unsigned char ctr[8] = {1,0,0,0,0,0,0,0}; | |||
| 4265 | memcpy(iv, ctr, 8); | |||
| 4266 | memcpy(iv+8, seq, 8); | |||
| 4267 | } | |||
| 4268 | ||||
| 4269 | return ((!counter && gcry_cipher_setiv(hd, seq, 8) == 0) || | |||
| 4270 | (counter && gcry_cipher_setiv(hd, iv, 16) == 0)) && | |||
| 4271 | gcry_cipher_decrypt(hd, plain, plain_len, ctext, ctext_len) == 0; | |||
| 4272 | } | |||
| 4273 | ||||
| 4274 | static int | |||
| 4275 | ssh_dissect_decrypted_packet(tvbuff_t *tvb, packet_info *pinfo, | |||
| 4276 | struct ssh_peer_data *peer_data, proto_tree *tree, | |||
| 4277 | ssh_message_info_t *message) | |||
| 4278 | { | |||
| 4279 | int offset = 0; // TODO: | |||
| 4280 | int dissected_len = 0; | |||
| 4281 | tvbuff_t* payload_tvb; | |||
| 4282 | ||||
| 4283 | char* plaintext = message->plain_data; | |||
| 4284 | unsigned plaintext_len = message->data_len; | |||
| 4285 | ||||
| 4286 | col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL((void*)0), "Encrypted packet (plaintext_len=%d)", plaintext_len); | |||
| 4287 | ||||
| 4288 | tvbuff_t *packet_tvb = tvb_new_child_real_data(tvb, plaintext, plaintext_len, plaintext_len); | |||
| 4289 | add_new_data_source(pinfo, packet_tvb, "Decrypted Packet"); | |||
| 4290 | ||||
| 4291 | unsigned plen; | |||
| 4292 | uint32_t padding_length; | |||
| 4293 | unsigned remain_length; | |||
| 4294 | unsigned msg_code; | |||
| 4295 | ||||
| 4296 | proto_item *ti, *padding_ti; | |||
| 4297 | proto_item *msg_type_tree = NULL((void*)0); | |||
| 4298 | ||||
| 4299 | /* | |||
| 4300 | * We use "tvb_ensure_captured_length_remaining()" to make sure there | |||
| 4301 | * actually *is* data remaining. | |||
| 4302 | * | |||
| 4303 | * This means we're guaranteed that "remain_length" is positive. | |||
| 4304 | */ | |||
| 4305 | remain_length = tvb_ensure_captured_length_remaining(packet_tvb, offset); | |||
| 4306 | /* | |||
| 4307 | * Can we do reassembly? | |||
| 4308 | */ | |||
| 4309 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 4310 | /* | |||
| 4311 | * Yes - would an SSH header starting at this offset | |||
| 4312 | * be split across segment boundaries? | |||
| 4313 | */ | |||
| 4314 | if (remain_length < 4) { | |||
| 4315 | /* | |||
| 4316 | * Yes. Tell the TCP dissector where the data for | |||
| 4317 | * this message starts in the data it handed us and | |||
| 4318 | * that we need "some more data." Don't tell it | |||
| 4319 | * exactly how many bytes we need because if/when we | |||
| 4320 | * ask for even more (after the header) that will | |||
| 4321 | * break reassembly. | |||
| 4322 | */ | |||
| 4323 | pinfo->desegment_offset = offset; | |||
| 4324 | pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT0x0fffffff; | |||
| 4325 | return offset; | |||
| 4326 | } | |||
| 4327 | } | |||
| 4328 | /* XXX - Defragmentation needs to be done in ssh_decrypt_packet, and the | |||
| 4329 | * checks there should mean that the above never has an effect. (It's | |||
| 4330 | * copied from ssh_dissect_key_exchange.) | |||
| 4331 | */ | |||
| 4332 | plen = tvb_get_ntohl(packet_tvb, offset); | |||
| 4333 | ||||
| 4334 | if (ssh_desegment && pinfo->can_desegment) { | |||
| 4335 | if (plen + 4 > remain_length) { | |||
| 4336 | pinfo->desegment_offset = offset; | |||
| 4337 | pinfo->desegment_len = plen+4 - remain_length; | |||
| 4338 | return offset; | |||
| 4339 | } | |||
| 4340 | } | |||
| 4341 | /* | |||
| 4342 | * Need to check plen > 0x80000000 here | |||
| 4343 | */ | |||
| 4344 | ||||
| 4345 | ti = proto_tree_add_uint(tree, hf_ssh_packet_length, packet_tvb, | |||
| 4346 | offset, 4, plen); | |||
| 4347 | if (plen < 8) { | |||
| 4348 | /* RFC 4253 6: "[T]he length of the concatenation of 'packet_length', | |||
| 4349 | * 'padding_length', 'payload', and 'random padding' MUST be a multiple | |||
| 4350 | * of the cipher block size or 8, whichever is larger,... even when | |||
| 4351 | * using stream ciphers." | |||
| 4352 | * | |||
| 4353 | * Modes that do not encrypt plen with the same key as the other three | |||
| 4354 | * cannot follow this as written and delete 'packet_length' from the | |||
| 4355 | * above sentence. As padding_length is one byte and random_padding at | |||
| 4356 | * least four, packet_length must be at least 8 in all modes. | |||
| 4357 | */ | |||
| 4358 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Packet length is %d, MUST be at least 8", plen); | |||
| 4359 | } else if (plen >= SSH_MAX_PACKET_LEN32768) { | |||
| 4360 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_length, "Overly large number %d", plen); | |||
| 4361 | plen = remain_length-4; | |||
| 4362 | } | |||
| 4363 | offset+=4; | |||
| 4364 | ||||
| 4365 | /* padding length */ | |||
| 4366 | padding_ti = proto_tree_add_item_ret_uint(tree, hf_ssh_padding_length, packet_tvb, offset, 1, ENC_NA0x00000000, &padding_length); | |||
| 4367 | /* RFC 4253 6: "There MUST be at least four bytes of padding." */ | |||
| 4368 | if (padding_length < 4) { | |||
| 4369 | expert_add_info_format(pinfo, padding_ti, &ei_ssh_padding_length, "Padding length is %d, MUST be at least 4", padding_length); | |||
| 4370 | } | |||
| 4371 | unsigned payload_length; | |||
| 4372 | if (ckd_sub(&payload_length, plen, padding_length + 1)__builtin_sub_overflow((plen), (padding_length + 1), (&payload_length ))) { | |||
| 4373 | expert_add_info_format(pinfo, padding_ti, &ei_ssh_padding_length, "Padding length is too large [%d], implies a negative payload length", padding_length); | |||
| 4374 | payload_length = 0; | |||
| 4375 | } | |||
| 4376 | offset += 1; | |||
| 4377 | ||||
| 4378 | /* msg_code */ | |||
| 4379 | msg_code = tvb_get_uint8(packet_tvb, offset); | |||
| 4380 | /* XXX - Payload compression could have been negotiated */ | |||
| 4381 | payload_tvb = tvb_new_subset_length(packet_tvb, offset, (int)payload_length); | |||
| 4382 | bool_Bool is_response = ssh_peer_data_from_server(peer_data); | |||
| 4383 | ||||
| 4384 | /* Transport layer protocol */ | |||
| 4385 | /* Generic (1-19) */ | |||
| 4386 | if(msg_code >= 1 && msg_code <= 19) { | |||
| 4387 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4388 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Transport (generic)"); | |||
| 4389 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4390 | dissected_len = ssh_dissect_transport_generic(payload_tvb, pinfo, 1, peer_data, msg_type_tree, msg_code); | |||
| 4391 | } | |||
| 4392 | /* Algorithm negotiation (20-29) */ | |||
| 4393 | /* Normally these messages are all dissected in ssh_dissect_key_exchange */ | |||
| 4394 | else if(msg_code >=20 && msg_code <= 29) { | |||
| 4395 | //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); | |||
| 4396 | ||||
| 4397 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4398 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Transport (algorithm negotiation)"); | |||
| 4399 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4400 | dissected_len = 1; | |||
| 4401 | ||||
| 4402 | 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" , 4402, __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); | |||
| 4403 | switch(msg_code) | |||
| 4404 | { | |||
| 4405 | case SSH_MSG_KEXINIT20: | |||
| 4406 | { | |||
| 4407 | 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" , 4407, __func__, "ssh: REKEY msg_code 20: storing frame %u number, offset %d" , pinfo->num, offset); } } while (0); | |||
| 4408 | peer_data->rekey_trigger_frame = pinfo->num; | |||
| 4409 | // Reset array while REKEY: sanitize server_key_exchange_init and force do_decrypt : | |||
| 4410 | peer_data->global_data->kex_server_key_exchange_init = wmem_array_new(wmem_file_scope(), 1); | |||
| 4411 | peer_data->global_data->do_decrypt = true1; | |||
| 4412 | dissected_len = ssh_dissect_key_init(payload_tvb, pinfo, offset - 4, msg_type_tree, is_response, peer_data->global_data); | |||
| 4413 | break; | |||
| 4414 | } | |||
| 4415 | case SSH_MSG_NEWKEYS21: | |||
| 4416 | { | |||
| 4417 | if (peer_data->rekey_pending) { | |||
| 4418 | 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" , 4418, __func__, "ssh: REKEY pending... NEWKEYS frame %u", pinfo ->num); } } while (0); | |||
| 4419 | 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" , 4419, __func__, "ssh: decrypting frame %u with key ID %u, seq=%u" , pinfo->num, peer_data->cipher_id, peer_data->sequence_number ); } } while (0); | |||
| 4420 | if (peer_data->global_data->ext_kex_strict) { | |||
| 4421 | peer_data->sequence_number = 0; | |||
| 4422 | ssh_debug_printf("%s->sequence_number reset to 0 (Strict KEX)\n", is_response ? "server" : "client"); | |||
| 4423 | 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" , 4423, __func__, "ssh: REKEY reset %s sequence number to 0 at frame %u (Strict KEX)" , is_response ? "server" : "client", pinfo->num); } } while (0); | |||
| 4424 | } | |||
| 4425 | // finalize the rekey (activate the new keys) | |||
| 4426 | if (!is_response) { // Only process client-sent NEWKEYS | |||
| 4427 | // Activate new key material into peer_data->cipher | |||
| 4428 | ssh_debug_printf("Activating new keys for CLIENT => SERVER\n"); | |||
| 4429 | ssh_decryption_setup_cipher(peer_data, &peer_data->global_data->new_keys[0], &peer_data->global_data->new_keys[2]); | |||
| 4430 | ssh_decryption_setup_mac(peer_data, &peer_data->global_data->new_keys[4]); | |||
| 4431 | } else { // Only process server-sent NEWKEYS | |||
| 4432 | // Activate new key material into peer_data->cipher | |||
| 4433 | ssh_debug_printf("Activating new keys for SERVER => CLIENT\n"); | |||
| 4434 | ssh_decryption_setup_cipher(peer_data, &peer_data->global_data->new_keys[1], &peer_data->global_data->new_keys[3]); | |||
| 4435 | ssh_decryption_setup_mac(peer_data, &peer_data->global_data->new_keys[5]); | |||
| 4436 | } | |||
| 4437 | // Finishing REKEY | |||
| 4438 | peer_data->rekey_pending = false0; | |||
| 4439 | 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" , 4439, __func__, "ssh: REKEY done... switched to NEWKEYS at frame %u" , pinfo->num); } } while (0); | |||
| 4440 | } | |||
| 4441 | break; | |||
| 4442 | } | |||
| 4443 | } | |||
| 4444 | } | |||
| 4445 | /* Key exchange method specific (reusable) (30-49) */ | |||
| 4446 | /* Normally these messages are all dissected in ssh_dissect_key_exchange */ | |||
| 4447 | else if (msg_code >=30 && msg_code <= 49) { | |||
| 4448 | //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); | |||
| 4449 | ||||
| 4450 | 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)"); | |||
| 4451 | 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" , 4451, __func__, "ssh: rekey KEX_xxx_INIT/KEX_xxx_REPLY detected in frame %u" , pinfo->num); } } while (0); | |||
| 4452 | peer_data->rekey_pending = true1; | |||
| 4453 | dissected_len = peer_data->global_data->kex_specific_dissector(msg_code, payload_tvb, pinfo, offset -5, msg_type_tree, peer_data->global_data); | |||
| 4454 | } | |||
| 4455 | ||||
| 4456 | /* User authentication protocol */ | |||
| 4457 | /* Generic (50-59) */ | |||
| 4458 | else if (msg_code >= 50 && msg_code <= 59) { | |||
| 4459 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4460 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: User Authentication (generic)"); | |||
| 4461 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4462 | dissected_len = ssh_dissect_userauth_generic(payload_tvb, pinfo, 1, msg_type_tree, msg_code); | |||
| 4463 | } | |||
| 4464 | /* User authentication method specific (reusable) (60-79) */ | |||
| 4465 | else if (msg_code >= 60 && msg_code <= 79) { | |||
| 4466 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(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: User Authentication: (method specific)"); | |||
| 4468 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4469 | dissected_len = ssh_dissect_userauth_specific(payload_tvb, pinfo, 1, msg_type_tree, msg_code); | |||
| 4470 | } | |||
| 4471 | ||||
| 4472 | /* Connection protocol */ | |||
| 4473 | /* Generic (80-89) */ | |||
| 4474 | else if (msg_code >= 80 && msg_code <= 89) { | |||
| 4475 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4476 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Connection (generic)"); | |||
| 4477 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4478 | dissected_len = ssh_dissect_connection_generic(payload_tvb, pinfo, 1, msg_type_tree, msg_code); | |||
| 4479 | } | |||
| 4480 | /* Channel related messages (90-127) */ | |||
| 4481 | else if (msg_code >= 90 && msg_code <= 127) { | |||
| 4482 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4483 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Connection: (channel related message)"); | |||
| 4484 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4485 | dissected_len = ssh_dissect_connection_specific(payload_tvb, pinfo, peer_data, 1, msg_type_tree, msg_code, message); | |||
| 4486 | } | |||
| 4487 | ||||
| 4488 | /* Reserved for client protocols (128-191) */ | |||
| 4489 | else if (msg_code >= 128 && msg_code <= 191) { | |||
| 4490 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 4491 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Client protocol"); | |||
| 4492 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4493 | offset+=1; | |||
| 4494 | // TODO: dissected_len = ssh_dissect_client(payload_tvb, pinfo, global_data, 1, msg_type_tree, is_response, msg_code); | |||
| 4495 | } | |||
| 4496 | ||||
| 4497 | /* Local extensions (192-255) */ | |||
| 4498 | else if (msg_code >= 192 && msg_code <= 255) { | |||
| 4499 | msg_type_tree = proto_tree_add_subtree(tree, packet_tvb, offset, plen-1, ett_key_exchange, NULL((void*)0), "Message: Local extension"); | |||
| 4500 | dissected_len = ssh_dissect_local_extension(payload_tvb, pinfo, 0, peer_data, msg_type_tree, msg_code); | |||
| 4501 | } | |||
| 4502 | ||||
| 4503 | /* XXX - ssh_dissect_key_exchange only adds undecoded payload here, | |||
| 4504 | * i.e., tvb_reported_length_remaining(payload_tvb, dissected_len) | |||
| 4505 | */ | |||
| 4506 | if (payload_length > 0) { | |||
| 4507 | proto_tree_add_item(msg_type_tree, hf_ssh_payload, packet_tvb, offset, payload_length, ENC_NA0x00000000); | |||
| 4508 | } | |||
| 4509 | if(dissected_len!=(int)payload_length){ | |||
| 4510 | 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); | |||
| 4511 | } | |||
| 4512 | offset += payload_length; | |||
| 4513 | ||||
| 4514 | /* padding */ | |||
| 4515 | proto_tree_add_item(tree, hf_ssh_padding_string, packet_tvb, offset, padding_length, ENC_NA0x00000000); | |||
| 4516 | offset += padding_length; | |||
| 4517 | ||||
| 4518 | if (peer_data->mac_length) { | |||
| 4519 | 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); | |||
| 4520 | offset += peer_data->mac_length; | |||
| 4521 | } | |||
| 4522 | ti = proto_tree_add_uint(tree, hf_ssh_seq_num, tvb, offset, 0, message->sequence_number); | |||
| 4523 | proto_item_set_generated(ti); | |||
| 4524 | return offset; | |||
| 4525 | } | |||
| 4526 | ||||
| 4527 | static int | |||
| 4528 | ssh_dissect_transport_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 4529 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code) | |||
| 4530 | { | |||
| 4531 | (void)pinfo; | |||
| 4532 | if(msg_code==SSH_MSG_DISCONNECT1){ | |||
| 4533 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_reason, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4534 | offset += 4; | |||
| 4535 | unsigned nlen; | |||
| 4536 | nlen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4537 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_description_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4538 | offset += 4; | |||
| 4539 | proto_tree_add_item(msg_type_tree, hf_ssh_disconnect_description, packet_tvb, offset, nlen, ENC_ASCII0x00000000); | |||
| 4540 | offset += nlen; | |||
| 4541 | nlen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4542 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4543 | offset += 4; | |||
| 4544 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag, packet_tvb, offset, nlen, ENC_ASCII0x00000000); | |||
| 4545 | offset += nlen; | |||
| 4546 | }else if(msg_code==SSH_MSG_IGNORE2){ | |||
| 4547 | offset += ssh_tree_add_string(packet_tvb, offset, msg_type_tree, hf_ssh_ignore_data, hf_ssh_ignore_data_length); | |||
| 4548 | }else if(msg_code==SSH_MSG_DEBUG4){ | |||
| 4549 | unsigned slen; | |||
| 4550 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_always_display, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4551 | offset += 1; | |||
| 4552 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4553 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_message_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4554 | offset += 4; | |||
| 4555 | proto_tree_add_item(msg_type_tree, hf_ssh_debug_message, packet_tvb, offset, slen, ENC_UTF_80x00000002); | |||
| 4556 | offset += slen; | |||
| 4557 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4558 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4559 | offset += 4; | |||
| 4560 | proto_tree_add_item(msg_type_tree, hf_ssh_lang_tag, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4561 | offset += slen; | |||
| 4562 | }else if(msg_code==SSH_MSG_SERVICE_REQUEST5){ | |||
| 4563 | unsigned nlen; | |||
| 4564 | nlen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4565 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4566 | offset += 4; | |||
| 4567 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name, packet_tvb, offset, nlen, ENC_ASCII0x00000000); | |||
| 4568 | offset += nlen; | |||
| 4569 | }else if(msg_code==SSH_MSG_SERVICE_ACCEPT6){ | |||
| 4570 | unsigned nlen; | |||
| 4571 | nlen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4572 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4573 | offset += 4; | |||
| 4574 | proto_tree_add_item(msg_type_tree, hf_ssh_service_name, packet_tvb, offset, nlen, ENC_ASCII0x00000000); | |||
| 4575 | offset += nlen; | |||
| 4576 | }else if(msg_code==SSH_MSG_EXT_INFO7){ | |||
| 4577 | unsigned ext_cnt; | |||
| 4578 | ext_cnt = tvb_get_ntohl(packet_tvb, offset); | |||
| 4579 | proto_tree_add_item(msg_type_tree, hf_ssh_ext_count, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4580 | offset += 4; | |||
| 4581 | for(unsigned ext_index = 0; ext_index < ext_cnt; ext_index++) { | |||
| 4582 | offset = ssh_dissect_rfc8308_extension(packet_tvb, pinfo, offset, peer_data, msg_type_tree); | |||
| 4583 | } | |||
| 4584 | } | |||
| 4585 | return offset; | |||
| 4586 | } | |||
| 4587 | ||||
| 4588 | static int | |||
| 4589 | ssh_dissect_rfc8308_extension(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 4590 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree) | |||
| 4591 | { | |||
| 4592 | (void)pinfo; | |||
| 4593 | unsigned ext_name_slen = tvb_get_ntohl(packet_tvb, offset); | |||
| 4594 | uint8_t *ext_name = tvb_get_string_enc(pinfo->pool, packet_tvb, offset + 4, ext_name_slen, ENC_ASCII0x00000000); | |||
| 4595 | unsigned ext_value_slen = tvb_get_ntohl(packet_tvb, offset + 4 + ext_name_slen); | |||
| 4596 | unsigned ext_len = 8 + ext_name_slen + ext_value_slen; | |||
| 4597 | 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); | |||
| 4598 | ||||
| 4599 | proto_tree_add_item(ext_tree, hf_ssh_ext_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4600 | offset += 4; | |||
| 4601 | proto_tree_add_item(ext_tree, hf_ssh_ext_name, packet_tvb, offset, ext_name_slen, ENC_ASCII0x00000000); | |||
| 4602 | offset += ext_name_slen; | |||
| 4603 | proto_tree_add_item(ext_tree, hf_ssh_ext_value_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4604 | offset += 4; | |||
| 4605 | proto_tree_add_item(ext_tree, hf_ssh_ext_value, packet_tvb, offset, ext_value_slen, ENC_NA0x00000000); | |||
| 4606 | ||||
| 4607 | if (g_str_equal(ext_name, "server-sig-algs")(strcmp ((const char *) (ext_name), (const char *) ("server-sig-algs" )) == 0)) { | |||
| 4608 | // server-sig-algs (RFC8308 Sec. 3.1) | |||
| 4609 | proto_tree_add_item(ext_tree, hf_ssh_ext_server_sig_algs_algorithms, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000); | |||
| 4610 | offset += ext_value_slen; | |||
| 4611 | } else if (g_str_equal(ext_name, "delay-compression")(strcmp ((const char *) (ext_name), (const char *) ("delay-compression" )) == 0)) { | |||
| 4612 | // delay-compression (RFC8308 Sec 3.2) | |||
| 4613 | unsigned slen; | |||
| 4614 | slen = tvb_get_ntohl(packet_tvb, offset); | |||
| 4615 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_client_to_server_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4616 | offset += 4; | |||
| 4617 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_client_to_server, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4618 | offset += slen; | |||
| 4619 | slen = tvb_get_ntohl(packet_tvb, offset); | |||
| 4620 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_server_to_client_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4621 | offset += 4; | |||
| 4622 | proto_tree_add_item(ext_tree, hf_ssh_ext_delay_compression_algorithms_server_to_client, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4623 | offset += slen; | |||
| 4624 | } else if (g_str_equal(ext_name, "no-flow-control")(strcmp ((const char *) (ext_name), (const char *) ("no-flow-control" )) == 0)) { | |||
| 4625 | // no-flow-control (RFC 8308 Sec 3.3) | |||
| 4626 | proto_tree_add_item(ext_tree, hf_ssh_ext_no_flow_control_value, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000); | |||
| 4627 | offset += ext_value_slen; | |||
| 4628 | } else if (g_str_equal(ext_name, "elevation")(strcmp ((const char *) (ext_name), (const char *) ("elevation" )) == 0)) { | |||
| 4629 | // elevation (RFC 8308 Sec 3.4) | |||
| 4630 | proto_tree_add_item(ext_tree, hf_ssh_ext_elevation_value, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000); | |||
| 4631 | offset += ext_value_slen; | |||
| 4632 | } else if (g_str_equal(ext_name, "publickey-algorithms@roumenpetrov.info")(strcmp ((const char *) (ext_name), (const char *) ("publickey-algorithms@roumenpetrov.info" )) == 0)) { | |||
| 4633 | // publickey-algorithms@roumenpetrov.info (proprietary) | |||
| 4634 | proto_tree_add_item(ext_tree, hf_ssh_ext_prop_publickey_algorithms_algorithms, packet_tvb, offset, ext_value_slen, ENC_ASCII0x00000000); | |||
| 4635 | offset += ext_value_slen; | |||
| 4636 | } else if (g_str_equal(ext_name, "ping@openssh.com")(strcmp ((const char *) (ext_name), (const char *) ("ping@openssh.com" )) == 0)) { | |||
| 4637 | // ping@openssh.com (proprietary w/ primitive extension value) | |||
| 4638 | peer_data->global_data->ext_ping_openssh_offered = true1; | |||
| 4639 | offset += ext_value_slen; | |||
| 4640 | } else { | |||
| 4641 | offset += ext_value_slen; | |||
| 4642 | } | |||
| 4643 | ||||
| 4644 | // The following extensions do not require advanced dissection: | |||
| 4645 | // - global-requests-ok | |||
| 4646 | // - ext-auth-info | |||
| 4647 | // - publickey-hostbound@openssh.com | |||
| 4648 | // - ext-info-in-auth@openssh.com | |||
| 4649 | ||||
| 4650 | return offset; | |||
| 4651 | } | |||
| 4652 | ||||
| 4653 | static int | |||
| 4654 | ssh_dissect_userauth_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 4655 | int offset, proto_item *msg_type_tree, unsigned msg_code) | |||
| 4656 | { | |||
| 4657 | if(msg_code==SSH_MSG_USERAUTH_REQUEST50){ | |||
| 4658 | uint32_t slen; | |||
| 4659 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_user_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4660 | offset += 4; | |||
| 4661 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_user_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4662 | offset += slen; | |||
| 4663 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_service_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4664 | offset += 4; | |||
| 4665 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_service_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4666 | offset += slen; | |||
| 4667 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_method_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4668 | offset += 4; | |||
| 4669 | const uint8_t* key_type; | |||
| 4670 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_userauth_method_name, packet_tvb, offset, slen, ENC_ASCII0x00000000, pinfo->pool, &key_type); | |||
| 4671 | offset += slen; | |||
| 4672 | if (0 == strcmp(key_type, "none")) { | |||
| 4673 | }else if (0 == strcmp(key_type, "publickey") || 0 == strcmp(key_type, "publickey-hostbound-v00@openssh.com")) { | |||
| 4674 | uint8_t bHaveSignature = tvb_get_uint8(packet_tvb, offset); | |||
| 4675 | int dissected_len = 0; | |||
| 4676 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_have_signature, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4677 | offset += 1; | |||
| 4678 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_pka_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4679 | offset += 4; | |||
| 4680 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4681 | offset += slen; | |||
| 4682 | proto_item *ti; | |||
| 4683 | ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_blob_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4684 | offset += 4; | |||
| 4685 | dissected_len = ssh_dissect_public_key_blob(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree); | |||
| 4686 | if(dissected_len!=(int)slen){ | |||
| 4687 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen); | |||
| 4688 | } | |||
| 4689 | offset += slen; | |||
| 4690 | if (0 == strcmp(key_type, "publickey-hostbound-v00@openssh.com")) { | |||
| 4691 | // Host key - but should we add it to global data or not? | |||
| 4692 | offset += ssh_tree_add_hostkey(packet_tvb, offset, msg_type_tree, "Server host key", | |||
| 4693 | ett_key_exchange_host_key, NULL((void*)0)); | |||
| 4694 | } | |||
| 4695 | if(bHaveSignature){ | |||
| 4696 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_signature_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4697 | offset += 4; | |||
| 4698 | proto_item *signature_tree = NULL((void*)0); | |||
| 4699 | signature_tree = proto_tree_add_subtree(msg_type_tree, packet_tvb, offset, slen, ett_userauth_pk_signature, NULL((void*)0), "Public key signature"); | |||
| 4700 | dissected_len = ssh_dissect_public_key_signature(packet_tvb, pinfo, offset, signature_tree) - offset; | |||
| 4701 | if(dissected_len!=(int)slen){ | |||
| 4702 | expert_add_info_format(pinfo, signature_tree, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen); | |||
| 4703 | } | |||
| 4704 | offset += slen; | |||
| 4705 | } | |||
| 4706 | }else if (0 == strcmp(key_type, "password")) { | |||
| 4707 | uint8_t bChangePassword = tvb_get_uint8(packet_tvb, offset); | |||
| 4708 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_change_password, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4709 | offset += 1; | |||
| 4710 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_password_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4711 | offset += 4; | |||
| 4712 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_password, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4713 | offset += slen; | |||
| 4714 | if(bChangePassword){ | |||
| 4715 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_userauth_new_password_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4716 | offset += 4; | |||
| 4717 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_new_password, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4718 | offset += slen; | |||
| 4719 | } | |||
| 4720 | }else{ | |||
| 4721 | } | |||
| 4722 | ||||
| 4723 | }else if(msg_code==SSH_MSG_USERAUTH_FAILURE51){ | |||
| 4724 | unsigned slen; | |||
| 4725 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_auth_failure_list_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4726 | offset += 4; | |||
| 4727 | proto_tree_add_item(msg_type_tree, hf_ssh_auth_failure_list, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4728 | offset += slen; | |||
| 4729 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_partial_success, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 4730 | offset += 1; | |||
| 4731 | } | |||
| 4732 | return offset; | |||
| 4733 | } | |||
| 4734 | ||||
| 4735 | static int | |||
| 4736 | ssh_dissect_userauth_specific(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 4737 | int offset, proto_item *msg_type_tree, unsigned msg_code) | |||
| 4738 | { | |||
| 4739 | if(msg_code==SSH_MSG_USERAUTH_PK_OK60){ | |||
| 4740 | proto_item *ti; | |||
| 4741 | int dissected_len = 0; | |||
| 4742 | unsigned slen; | |||
| 4743 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 4744 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 4745 | offset += 4; | |||
| 4746 | proto_tree_add_item(msg_type_tree, hf_ssh_userauth_pka_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 4747 | offset += slen; | |||
| 4748 | ti = proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_blob_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 4749 | offset += 4; | |||
| 4750 | dissected_len = ssh_dissect_public_key_blob(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree); | |||
| 4751 | if(dissected_len!=(int)slen){ | |||
| 4752 | expert_add_info_format(pinfo, ti, &ei_ssh_packet_decode, "Decoded %d bytes, but packet length is %d bytes", dissected_len, slen); | |||
| 4753 | } | |||
| 4754 | offset += slen; | |||
| 4755 | } | |||
| 4756 | return offset; | |||
| 4757 | } | |||
| 4758 | ||||
| 4759 | static void | |||
| 4760 | ssh_process_payload(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, ssh_channel_info_t *channel) | |||
| 4761 | { | |||
| 4762 | tvbuff_t *next_tvb = tvb_new_subset_remaining(tvb, offset); | |||
| 4763 | if (channel->handle) { | |||
| 4764 | call_dissector(channel->handle, next_tvb, pinfo, proto_tree_get_root(tree)); | |||
| 4765 | } else { | |||
| 4766 | call_data_dissector(next_tvb, pinfo, proto_tree_get_root(tree)); | |||
| 4767 | } | |||
| 4768 | } | |||
| 4769 | ||||
| 4770 | static void | |||
| 4771 | print_ssh_fragment_tree(fragment_head *ipfd_head, proto_tree *tree, proto_tree *ssh_tree, packet_info *pinfo, tvbuff_t *next_tvb) | |||
| 4772 | { | |||
| 4773 | proto_item *ssh_tree_item, *frag_tree_item; | |||
| 4774 | ||||
| 4775 | /* | |||
| 4776 | * The subdissector thought it was completely | |||
| 4777 | * desegmented (although the stuff at the | |||
| 4778 | * end may, in turn, require desegmentation), | |||
| 4779 | * so we show a tree with all segments. | |||
| 4780 | */ | |||
| 4781 | show_fragment_tree(ipfd_head, &ssh_segment_items, | |||
| 4782 | tree, pinfo, next_tvb, &frag_tree_item); | |||
| 4783 | /* | |||
| 4784 | * The toplevel fragment subtree is now | |||
| 4785 | * behind all desegmented data; move it | |||
| 4786 | * right behind the SSH tree. | |||
| 4787 | */ | |||
| 4788 | ssh_tree_item = proto_tree_get_parent(ssh_tree); | |||
| 4789 | /* The SSH protocol item is up a few levels from the message tree */ | |||
| 4790 | ssh_tree_item = proto_item_get_parent_nth(ssh_tree_item, 2); | |||
| 4791 | if (frag_tree_item && ssh_tree_item) { | |||
| 4792 | proto_tree_move_item(tree, ssh_tree_item, frag_tree_item); | |||
| 4793 | } | |||
| 4794 | } | |||
| 4795 | ||||
| 4796 | static uint32_t | |||
| 4797 | ssh_msp_fragment_id(struct tcp_multisegment_pdu *msp) | |||
| 4798 | { | |||
| 4799 | /* | |||
| 4800 | * If a frame contains multiple PDUs, then "first_frame" is not | |||
| 4801 | * sufficient to uniquely identify groups of fragments. Therefore we use | |||
| 4802 | * the tcp reassembly functions that also test msp->seq (the position of | |||
| 4803 | * the initial fragment in the SSH channel). | |||
| 4804 | */ | |||
| 4805 | return msp->first_frame; | |||
| 4806 | } | |||
| 4807 | ||||
| 4808 | static void | |||
| 4809 | ssh_proto_tree_add_segment_data( | |||
| 4810 | proto_tree *tree, | |||
| 4811 | tvbuff_t *tvb, | |||
| 4812 | int offset, | |||
| 4813 | int length, | |||
| 4814 | const char *prefix) | |||
| 4815 | { | |||
| 4816 | proto_tree_add_bytes_format( | |||
| 4817 | tree, | |||
| 4818 | hf_ssh_segment_data, | |||
| 4819 | tvb, | |||
| 4820 | offset, | |||
| 4821 | length, | |||
| 4822 | NULL((void*)0), | |||
| 4823 | "%sSSH segment data (%u %s)", | |||
| 4824 | prefix != NULL((void*)0) ? prefix : "", | |||
| 4825 | length == -1 ? tvb_reported_length_remaining(tvb, offset) : length, | |||
| 4826 | plurality(length, "byte", "bytes")((length) == 1 ? ("byte") : ("bytes"))); | |||
| 4827 | } | |||
| 4828 | ||||
| 4829 | static void | |||
| 4830 | desegment_ssh(tvbuff_t *tvb, packet_info *pinfo, uint32_t seq, | |||
| 4831 | uint32_t nxtseq, proto_tree *tree, ssh_channel_info_t *channel) | |||
| 4832 | { | |||
| 4833 | fragment_head *ipfd_head; | |||
| 4834 | bool_Bool must_desegment; | |||
| 4835 | bool_Bool called_dissector; | |||
| 4836 | int another_pdu_follows; | |||
| 4837 | bool_Bool another_segment_in_frame = false0; | |||
| 4838 | int deseg_offset, offset = 0; | |||
| 4839 | uint32_t deseg_seq; | |||
| 4840 | int nbytes; | |||
| 4841 | proto_item *item; | |||
| 4842 | struct tcp_multisegment_pdu *msp; | |||
| 4843 | bool_Bool first_pdu = true1; | |||
| 4844 | ||||
| 4845 | again: | |||
| 4846 | ipfd_head = NULL((void*)0); | |||
| 4847 | must_desegment = false0; | |||
| 4848 | called_dissector = false0; | |||
| 4849 | another_pdu_follows = 0; | |||
| 4850 | msp = NULL((void*)0); | |||
| 4851 | ||||
| 4852 | /* | |||
| 4853 | * Initialize these to assume no desegmentation. | |||
| 4854 | * If that's not the case, these will be set appropriately | |||
| 4855 | * by the subdissector. | |||
| 4856 | */ | |||
| 4857 | pinfo->desegment_offset = 0; | |||
| 4858 | pinfo->desegment_len = 0; | |||
| 4859 | ||||
| 4860 | /* | |||
| 4861 | * Initialize this to assume that this segment will just be | |||
| 4862 | * added to the middle of a desegmented chunk of data, so | |||
| 4863 | * that we should show it all as data. | |||
| 4864 | * If that's not the case, it will be set appropriately. | |||
| 4865 | */ | |||
| 4866 | deseg_offset = offset; | |||
| 4867 | ||||
| 4868 | /* If we've seen this segment before (e.g., it's a retransmission), | |||
| 4869 | * there's nothing for us to do. Certainly, don't add it to the list | |||
| 4870 | * of multisegment_pdus (that would cause subsequent lookups to find | |||
| 4871 | * the retransmission instead of the original transmission, breaking | |||
| 4872 | * dissection of the desegmented pdu if we'd already seen the end of | |||
| 4873 | * the pdu). | |||
| 4874 | */ | |||
| 4875 | if ((msp = (struct tcp_multisegment_pdu *)wmem_tree_lookup32(channel->multisegment_pdus, seq))) { | |||
| 4876 | const char *prefix; | |||
| 4877 | bool_Bool is_retransmission = false0; | |||
| 4878 | ||||
| 4879 | if (msp->first_frame == pinfo->num) { | |||
| 4880 | /* This must be after the first pass. */ | |||
| 4881 | prefix = ""; | |||
| 4882 | if (msp->last_frame == pinfo->num) { | |||
| 4883 | col_clear(pinfo->cinfo, COL_INFO); | |||
| 4884 | } else { | |||
| 4885 | if (first_pdu) { | |||
| 4886 | col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[SSH segment of a reassembled PDU]"); | |||
| 4887 | } | |||
| 4888 | } | |||
| 4889 | } else { | |||
| 4890 | prefix = "Retransmitted "; | |||
| 4891 | is_retransmission = true1; | |||
| 4892 | } | |||
| 4893 | ||||
| 4894 | if (!is_retransmission) { | |||
| 4895 | ipfd_head = fragment_get(&ssh_reassembly_table, pinfo, msp->first_frame, msp); | |||
| 4896 | if (ipfd_head != NULL((void*)0) && ipfd_head->reassembled_in !=0 && | |||
| 4897 | ipfd_head->reassembled_in != pinfo->num) { | |||
| 4898 | /* Show what frame this was reassembled in if not this one. */ | |||
| 4899 | item=proto_tree_add_uint(tree, *ssh_segment_items.hf_reassembled_in, | |||
| 4900 | tvb, 0, 0, ipfd_head->reassembled_in); | |||
| 4901 | proto_item_set_generated(item); | |||
| 4902 | } | |||
| 4903 | } | |||
| 4904 | nbytes = tvb_reported_length_remaining(tvb, offset); | |||
| 4905 | ssh_proto_tree_add_segment_data(tree, tvb, offset, nbytes, prefix); | |||
| 4906 | return; | |||
| 4907 | } | |||
| 4908 | ||||
| 4909 | /* Else, find the most previous PDU starting before this sequence number */ | |||
| 4910 | msp = (struct tcp_multisegment_pdu *)wmem_tree_lookup32_le(channel->multisegment_pdus, seq-1); | |||
| 4911 | if (msp && msp->seq <= seq && msp->nxtpdu > seq) { | |||
| 4912 | int len; | |||
| 4913 | ||||
| 4914 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 4915 | msp->last_frame = pinfo->num; | |||
| 4916 | msp->last_frame_time = pinfo->abs_ts; | |||
| 4917 | } | |||
| 4918 | ||||
| 4919 | /* OK, this PDU was found, which means the segment continues | |||
| 4920 | * a higher-level PDU and that we must desegment it. | |||
| 4921 | */ | |||
| 4922 | if (msp->flags & MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001) { | |||
| 4923 | /* The dissector asked for the entire segment */ | |||
| 4924 | len = MAX(0, tvb_reported_length_remaining(tvb, offset))(((0) > (tvb_reported_length_remaining(tvb, offset))) ? (0 ) : (tvb_reported_length_remaining(tvb, offset))); | |||
| 4925 | } else { | |||
| 4926 | len = MIN(nxtseq, msp->nxtpdu)(((nxtseq) < (msp->nxtpdu)) ? (nxtseq) : (msp->nxtpdu )) - seq; | |||
| 4927 | } | |||
| 4928 | ||||
| 4929 | ipfd_head = fragment_add(&ssh_reassembly_table, tvb, offset, | |||
| 4930 | pinfo, ssh_msp_fragment_id(msp), msp, | |||
| 4931 | seq - msp->seq, | |||
| 4932 | len, (LT_SEQ (nxtseq,msp->nxtpdu)((int32_t)((nxtseq) - (msp->nxtpdu)) < 0))); | |||
| 4933 | ||||
| 4934 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited) | |||
| 4935 | && msp->flags & MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001) { | |||
| 4936 | msp->flags &= (~MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001); | |||
| 4937 | ||||
| 4938 | /* If we consumed the entire segment there is no | |||
| 4939 | * other pdu starting anywhere inside this segment. | |||
| 4940 | * So update nxtpdu to point at least to the start | |||
| 4941 | * of the next segment. | |||
| 4942 | * (If the subdissector asks for even more data we | |||
| 4943 | * will advance nxtpdu even further later down in | |||
| 4944 | * the code.) | |||
| 4945 | */ | |||
| 4946 | msp->nxtpdu = nxtseq; | |||
| 4947 | } | |||
| 4948 | ||||
| 4949 | if ( (msp->nxtpdu < nxtseq) | |||
| 4950 | && (msp->nxtpdu >= seq) | |||
| 4951 | && (len > 0)) { | |||
| 4952 | another_pdu_follows = msp->nxtpdu - seq; | |||
| 4953 | } | |||
| 4954 | } else { | |||
| 4955 | /* This segment was not found in our table, so it doesn't | |||
| 4956 | * contain a continuation of a higher-level PDU. | |||
| 4957 | * Call the normal subdissector. | |||
| 4958 | */ | |||
| 4959 | ssh_process_payload(tvb, offset, pinfo, tree, channel); | |||
| 4960 | called_dissector = true1; | |||
| 4961 | ||||
| 4962 | /* Did the subdissector ask us to desegment some more data | |||
| 4963 | * before it could handle the packet? | |||
| 4964 | * If so we have to create some structures in our table but | |||
| 4965 | * this is something we only do the first time we see this | |||
| 4966 | * packet. | |||
| 4967 | */ | |||
| 4968 | if (pinfo->desegment_len) { | |||
| 4969 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) | |||
| 4970 | must_desegment = true1; | |||
| 4971 | ||||
| 4972 | /* | |||
| 4973 | * Set "deseg_offset" to the offset in "tvb" | |||
| 4974 | * of the first byte of data that the | |||
| 4975 | * subdissector didn't process. | |||
| 4976 | */ | |||
| 4977 | deseg_offset = offset + pinfo->desegment_offset; | |||
| 4978 | } | |||
| 4979 | ||||
| 4980 | /* Either no desegmentation is necessary, or this is | |||
| 4981 | * segment contains the beginning but not the end of | |||
| 4982 | * a higher-level PDU and thus isn't completely | |||
| 4983 | * desegmented. | |||
| 4984 | */ | |||
| 4985 | ipfd_head = NULL((void*)0); | |||
| 4986 | } | |||
| 4987 | ||||
| 4988 | /* is it completely desegmented? */ | |||
| 4989 | if (ipfd_head && ipfd_head->reassembled_in == pinfo->num) { | |||
| 4990 | /* | |||
| 4991 | * Yes, we think it is. | |||
| 4992 | * We only call subdissector for the last segment. | |||
| 4993 | * Note that the last segment may include more than what | |||
| 4994 | * we needed. | |||
| 4995 | */ | |||
| 4996 | if (nxtseq < msp->nxtpdu) { | |||
| 4997 | /* | |||
| 4998 | * This is *not* the last segment. It is part of a PDU in the same | |||
| 4999 | * frame, so no another PDU can follow this one. | |||
| 5000 | * Do not reassemble SSH yet, it will be done in the final segment. | |||
| 5001 | * (If we are reassembling at FIN, we will do that in dissect_ssl() | |||
| 5002 | * after iterating through all the records.) | |||
| 5003 | * Clear the Info column and avoid displaying [SSH segment of a | |||
| 5004 | * reassembled PDU], the payload dissector will typically set it. | |||
| 5005 | * (This is needed here for the second pass.) | |||
| 5006 | */ | |||
| 5007 | another_pdu_follows = 0; | |||
| 5008 | col_clear(pinfo->cinfo, COL_INFO); | |||
| 5009 | another_segment_in_frame = true1; | |||
| 5010 | } else { | |||
| 5011 | /* | |||
| 5012 | * OK, this is the last segment of the PDU and also the | |||
| 5013 | * last segment in this frame. | |||
| 5014 | * Let's call the subdissector with the desegmented | |||
| 5015 | * data. | |||
| 5016 | */ | |||
| 5017 | tvbuff_t *next_tvb; | |||
| 5018 | int old_len; | |||
| 5019 | ||||
| 5020 | /* | |||
| 5021 | * Reset column in case multiple SSH segments form the PDU | |||
| 5022 | * and this last SSH segment is not in the first TCP segment of | |||
| 5023 | * this frame. | |||
| 5024 | * XXX prevent clearing the column if the last layer is not SSH? | |||
| 5025 | */ | |||
| 5026 | /* Clear column during the first pass. */ | |||
| 5027 | col_clear(pinfo->cinfo, COL_INFO); | |||
| 5028 | ||||
| 5029 | /* create a new TVB structure for desegmented data */ | |||
| 5030 | next_tvb = tvb_new_chain(tvb, ipfd_head->tvb_data); | |||
| 5031 | ||||
| 5032 | /* add desegmented data to the data source list */ | |||
| 5033 | add_new_data_source(pinfo, next_tvb, "Reassembled SSH"); | |||
| 5034 | ||||
| 5035 | /* call subdissector */ | |||
| 5036 | ssh_process_payload(next_tvb, 0, pinfo, tree, channel); | |||
| 5037 | called_dissector = true1; | |||
| 5038 | ||||
| 5039 | /* | |||
| 5040 | * OK, did the subdissector think it was completely | |||
| 5041 | * desegmented, or does it think we need even more | |||
| 5042 | * data? | |||
| 5043 | */ | |||
| 5044 | old_len = (int)(tvb_reported_length(next_tvb) - tvb_reported_length_remaining(tvb, offset)); | |||
| 5045 | if (pinfo->desegment_len && pinfo->desegment_offset <= old_len) { | |||
| 5046 | /* | |||
| 5047 | * "desegment_len" isn't 0, so it needs more | |||
| 5048 | * data for something - and "desegment_offset" | |||
| 5049 | * is before "old_len", so it needs more data | |||
| 5050 | * to dissect the stuff we thought was | |||
| 5051 | * completely desegmented (as opposed to the | |||
| 5052 | * stuff at the beginning being completely | |||
| 5053 | * desegmented, but the stuff at the end | |||
| 5054 | * being a new higher-level PDU that also | |||
| 5055 | * needs desegmentation). | |||
| 5056 | */ | |||
| 5057 | fragment_set_partial_reassembly(&ssh_reassembly_table, | |||
| 5058 | pinfo, ssh_msp_fragment_id(msp), msp); | |||
| 5059 | /* Update msp->nxtpdu to point to the new next | |||
| 5060 | * pdu boundary. | |||
| 5061 | */ | |||
| 5062 | if (pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT0x0fffffff) { | |||
| 5063 | /* We want reassembly of at least one | |||
| 5064 | * more segment so set the nxtpdu | |||
| 5065 | * boundary to one byte into the next | |||
| 5066 | * segment. | |||
| 5067 | * This means that the next segment | |||
| 5068 | * will complete reassembly even if it | |||
| 5069 | * is only one single byte in length. | |||
| 5070 | */ | |||
| 5071 | msp->nxtpdu = seq + tvb_reported_length_remaining(tvb, offset) + 1; | |||
| 5072 | msp->flags |= MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001; | |||
| 5073 | } else if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) { | |||
| 5074 | /* This is not the first segment, and we thought reassembly | |||
| 5075 | * would be done now, but now we know we desegment at FIN. | |||
| 5076 | * E.g., a HTTP response where the headers were split | |||
| 5077 | * across segments (so previous ONE_MORE_SEGMENT) and | |||
| 5078 | * also no Content-Length (so now DESEGMENT_UNTIL_FIN). | |||
| 5079 | */ | |||
| 5080 | channel->flags |= TCP_FLOW_REASSEMBLE_UNTIL_FIN0x0001; | |||
| 5081 | msp->nxtpdu = nxtseq + 0x40000000; | |||
| 5082 | } else { | |||
| 5083 | msp->nxtpdu = seq + tvb_reported_length_remaining(tvb, offset) + pinfo->desegment_len; | |||
| 5084 | } | |||
| 5085 | /* Since we need at least some more data | |||
| 5086 | * there can be no pdu following in the | |||
| 5087 | * tail of this segment. | |||
| 5088 | */ | |||
| 5089 | another_pdu_follows = 0; | |||
| 5090 | } else { | |||
| 5091 | /* | |||
| 5092 | * Show the stuff in this TCP segment as | |||
| 5093 | * just raw TCP segment data. | |||
| 5094 | */ | |||
| 5095 | nbytes = another_pdu_follows > 0 | |||
| 5096 | ? another_pdu_follows | |||
| 5097 | : tvb_reported_length_remaining(tvb, offset); | |||
| 5098 | ssh_proto_tree_add_segment_data(tree, tvb, offset, nbytes, NULL((void*)0)); | |||
| 5099 | ||||
| 5100 | /* Show details of the reassembly */ | |||
| 5101 | print_ssh_fragment_tree(ipfd_head, proto_tree_get_root(tree), tree, pinfo, next_tvb); | |||
| 5102 | ||||
| 5103 | /* Did the subdissector ask us to desegment | |||
| 5104 | * some more data? This means that the data | |||
| 5105 | * at the beginning of this segment completed | |||
| 5106 | * a higher-level PDU, but the data at the | |||
| 5107 | * end of this segment started a higher-level | |||
| 5108 | * PDU but didn't complete it. | |||
| 5109 | * | |||
| 5110 | * If so, we have to create some structures | |||
| 5111 | * in our table, but this is something we | |||
| 5112 | * only do the first time we see this packet. | |||
| 5113 | */ | |||
| 5114 | if (pinfo->desegment_len) { | |||
| 5115 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) | |||
| 5116 | must_desegment = true1; | |||
| 5117 | ||||
| 5118 | /* The stuff we couldn't dissect | |||
| 5119 | * must have come from this segment, | |||
| 5120 | * so it's all in "tvb". | |||
| 5121 | * | |||
| 5122 | * "pinfo->desegment_offset" is | |||
| 5123 | * relative to the beginning of | |||
| 5124 | * "next_tvb"; we want an offset | |||
| 5125 | * relative to the beginning of "tvb". | |||
| 5126 | * | |||
| 5127 | * First, compute the offset relative | |||
| 5128 | * to the *end* of "next_tvb" - i.e., | |||
| 5129 | * the number of bytes before the end | |||
| 5130 | * of "next_tvb" at which the | |||
| 5131 | * subdissector stopped. That's the | |||
| 5132 | * length of "next_tvb" minus the | |||
| 5133 | * offset, relative to the beginning | |||
| 5134 | * of "next_tvb, at which the | |||
| 5135 | * subdissector stopped. | |||
| 5136 | */ | |||
| 5137 | deseg_offset = ipfd_head->datalen - pinfo->desegment_offset; | |||
| 5138 | ||||
| 5139 | /* "tvb" and "next_tvb" end at the | |||
| 5140 | * same byte of data, so the offset | |||
| 5141 | * relative to the end of "next_tvb" | |||
| 5142 | * of the byte at which we stopped | |||
| 5143 | * is also the offset relative to | |||
| 5144 | * the end of "tvb" of the byte at | |||
| 5145 | * which we stopped. | |||
| 5146 | * | |||
| 5147 | * Convert that back into an offset | |||
| 5148 | * relative to the beginning of | |||
| 5149 | * "tvb", by taking the length of | |||
| 5150 | * "tvb" and subtracting the offset | |||
| 5151 | * relative to the end. | |||
| 5152 | */ | |||
| 5153 | deseg_offset = tvb_reported_length(tvb) - deseg_offset; | |||
| 5154 | } | |||
| 5155 | } | |||
| 5156 | } | |||
| 5157 | } | |||
| 5158 | ||||
| 5159 | if (must_desegment) { | |||
| 5160 | /* If the dissector requested "reassemble until FIN" | |||
| 5161 | * just set this flag for the flow and let reassembly | |||
| 5162 | * proceed at normal. We will check/pick up these | |||
| 5163 | * reassembled PDUs later down in dissect_tcp() when checking | |||
| 5164 | * for the FIN flag. | |||
| 5165 | */ | |||
| 5166 | if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) { | |||
| 5167 | channel->flags |= TCP_FLOW_REASSEMBLE_UNTIL_FIN0x0001; | |||
| 5168 | } | |||
| 5169 | /* | |||
| 5170 | * The sequence number at which the stuff to be desegmented | |||
| 5171 | * starts is the sequence number of the byte at an offset | |||
| 5172 | * of "deseg_offset" into "tvb". | |||
| 5173 | * | |||
| 5174 | * The sequence number of the byte at an offset of "offset" | |||
| 5175 | * is "seq", i.e. the starting sequence number of this | |||
| 5176 | * segment, so the sequence number of the byte at | |||
| 5177 | * "deseg_offset" is "seq + (deseg_offset - offset)". | |||
| 5178 | */ | |||
| 5179 | deseg_seq = seq + (deseg_offset - offset); | |||
| 5180 | ||||
| 5181 | if (((nxtseq - deseg_seq) <= 1024*1024) | |||
| 5182 | && (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited))) { | |||
| 5183 | if (pinfo->desegment_len == DESEGMENT_ONE_MORE_SEGMENT0x0fffffff) { | |||
| 5184 | /* The subdissector asked to reassemble using the | |||
| 5185 | * entire next segment. | |||
| 5186 | * Just ask reassembly for one more byte | |||
| 5187 | * but set this msp flag so we can pick it up | |||
| 5188 | * above. | |||
| 5189 | */ | |||
| 5190 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo, | |||
| 5191 | deseg_seq, nxtseq+1, channel->multisegment_pdus); | |||
| 5192 | msp->flags |= MSP_FLAGS_REASSEMBLE_ENTIRE_SEGMENT0x00000001; | |||
| 5193 | } else if (pinfo->desegment_len == DESEGMENT_UNTIL_FIN0x0ffffffe) { | |||
| 5194 | /* Set nxtseq very large so that reassembly won't happen | |||
| 5195 | * until we force it at the end of the stream in dissect_ssl() | |||
| 5196 | * outside this function. | |||
| 5197 | */ | |||
| 5198 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo, | |||
| 5199 | deseg_seq, nxtseq+0x40000000, channel->multisegment_pdus); | |||
| 5200 | } else { | |||
| 5201 | msp = pdu_store_sequencenumber_of_next_pdu(pinfo, | |||
| 5202 | deseg_seq, nxtseq+pinfo->desegment_len, channel->multisegment_pdus); | |||
| 5203 | } | |||
| 5204 | ||||
| 5205 | /* add this segment as the first one for this new pdu */ | |||
| 5206 | fragment_add(&ssh_reassembly_table, tvb, deseg_offset, | |||
| 5207 | pinfo, ssh_msp_fragment_id(msp), msp, | |||
| 5208 | 0, nxtseq - deseg_seq, | |||
| 5209 | LT_SEQ(nxtseq, msp->nxtpdu)((int32_t)((nxtseq) - (msp->nxtpdu)) < 0)); | |||
| 5210 | } | |||
| 5211 | } | |||
| 5212 | ||||
| 5213 | if (!called_dissector || pinfo->desegment_len != 0) { | |||
| 5214 | if (ipfd_head != NULL((void*)0) && ipfd_head->reassembled_in != 0 && | |||
| 5215 | ipfd_head->reassembled_in != pinfo->num && | |||
| 5216 | !(ipfd_head->flags & FD_PARTIAL_REASSEMBLY0x0040)) { | |||
| 5217 | /* | |||
| 5218 | * We know what other frame this PDU is reassembled in; | |||
| 5219 | * let the user know. | |||
| 5220 | */ | |||
| 5221 | item=proto_tree_add_uint(tree, *ssh_segment_items.hf_reassembled_in, | |||
| 5222 | tvb, 0, 0, ipfd_head->reassembled_in); | |||
| 5223 | proto_item_set_generated(item); | |||
| 5224 | } | |||
| 5225 | ||||
| 5226 | /* | |||
| 5227 | * Either we didn't call the subdissector at all (i.e., | |||
| 5228 | * this is a segment that contains the middle of a | |||
| 5229 | * higher-level PDU, but contains neither the beginning | |||
| 5230 | * nor the end), or the subdissector couldn't dissect it | |||
| 5231 | * all, as some data was missing (i.e., it set | |||
| 5232 | * "pinfo->desegment_len" to the amount of additional | |||
| 5233 | * data it needs). | |||
| 5234 | */ | |||
| 5235 | if (!another_segment_in_frame && pinfo->desegment_offset == 0) { | |||
| 5236 | /* | |||
| 5237 | * It couldn't, in fact, dissect any of it (the | |||
| 5238 | * first byte it couldn't dissect is at an offset | |||
| 5239 | * of "pinfo->desegment_offset" from the beginning | |||
| 5240 | * of the payload, and that's 0). | |||
| 5241 | * Just mark this as SSH. | |||
| 5242 | */ | |||
| 5243 | ||||
| 5244 | /* SFTP checks the length before setting the protocol column. | |||
| 5245 | * If other subdissectors don't do this, we'd want to set the | |||
| 5246 | * protocol column back - but we want to get the SSH version | |||
| 5247 | */ | |||
| 5248 | //col_set_str(pinfo->cinfo, COL_PROTOCOL, | |||
| 5249 | // val_to_str_const(session->version, ssl_version_short_names, "SSH")); | |||
| 5250 | if (first_pdu) { | |||
| 5251 | col_append_sep_str(pinfo->cinfo, COL_INFO, " ", "[SSH segment of a reassembled PDU]"); | |||
| 5252 | } | |||
| 5253 | } | |||
| 5254 | ||||
| 5255 | /* | |||
| 5256 | * Show what's left in the packet as just raw SSH segment data. | |||
| 5257 | * XXX - remember what protocol the last subdissector | |||
| 5258 | * was, and report it as a continuation of that, instead? | |||
| 5259 | */ | |||
| 5260 | nbytes = tvb_reported_length_remaining(tvb, deseg_offset); | |||
| 5261 | ssh_proto_tree_add_segment_data(tree, tvb, deseg_offset, nbytes, NULL((void*)0)); | |||
| 5262 | } | |||
| 5263 | pinfo->can_desegment = 0; | |||
| 5264 | pinfo->desegment_offset = 0; | |||
| 5265 | pinfo->desegment_len = 0; | |||
| 5266 | ||||
| 5267 | if (another_pdu_follows) { | |||
| 5268 | /* there was another pdu following this one. */ | |||
| 5269 | pinfo->can_desegment=2; | |||
| 5270 | /* we also have to prevent the dissector from changing the | |||
| 5271 | * PROTOCOL and INFO colums since what follows may be an | |||
| 5272 | * incomplete PDU and we don't want it be changed back from | |||
| 5273 | * <Protocol> to <SSH> | |||
| 5274 | */ | |||
| 5275 | col_set_fence(pinfo->cinfo, COL_INFO); | |||
| 5276 | col_set_writable(pinfo->cinfo, COL_PROTOCOL, false0); | |||
| 5277 | first_pdu = false0; | |||
| 5278 | offset += another_pdu_follows; | |||
| 5279 | seq += another_pdu_follows; | |||
| 5280 | goto again; | |||
| 5281 | } | |||
| 5282 | } | |||
| 5283 | ||||
| 5284 | static void | |||
| 5285 | ssh_dissect_channel_data(tvbuff_t *tvb, packet_info *pinfo, | |||
| 5286 | struct ssh_peer_data *peer_data _U___attribute__((unused)), proto_tree *tree, | |||
| 5287 | ssh_message_info_t *message _U___attribute__((unused)), ssh_channel_info_t *channel) | |||
| 5288 | { | |||
| 5289 | ||||
| 5290 | uint16_t save_can_desegment = pinfo->can_desegment; | |||
| 5291 | ||||
| 5292 | if (ssh_desegment) { | |||
| 5293 | pinfo->can_desegment = 2; | |||
| 5294 | desegment_ssh(tvb, pinfo, message->byte_seq, message->next_byte_seq, tree, channel); | |||
| 5295 | } else { | |||
| 5296 | pinfo->can_desegment = 0; | |||
| 5297 | bool_Bool save_fragmented = pinfo->fragmented; | |||
| 5298 | pinfo->fragmented = true1; | |||
| 5299 | ||||
| 5300 | ssh_process_payload(tvb, 0, pinfo, tree, channel); | |||
| 5301 | pinfo->fragmented = save_fragmented; | |||
| 5302 | } | |||
| 5303 | ||||
| 5304 | pinfo->can_desegment = save_can_desegment; | |||
| 5305 | } | |||
| 5306 | ||||
| 5307 | static int | |||
| 5308 | ssh_dissect_term_modes(tvbuff_t *tvb, packet_info *pinfo _U___attribute__((unused)), proto_tree *tree) | |||
| 5309 | { | |||
| 5310 | proto_item *ti; | |||
| 5311 | proto_tree *term_mode_tree, *subtree; | |||
| 5312 | int offset = 0; | |||
| 5313 | uint32_t opcode, value, idx; | |||
| 5314 | bool_Bool boolval; | |||
| 5315 | ||||
| 5316 | struct tty_opt_info { | |||
| 5317 | unsigned id; | |||
| 5318 | int *hfindex; | |||
| 5319 | }; | |||
| 5320 | static const struct tty_opt_info tty_opts[] = { | |||
| 5321 | { SSH_TTY_OP_END0, NULL((void*)0)}, | |||
| 5322 | { SSH_TTY_OP_VINTR1, &hf_ssh_pty_term_mode_vintr }, | |||
| 5323 | { SSH_TTY_OP_VQUIT2, &hf_ssh_pty_term_mode_vquit }, | |||
| 5324 | { SSH_TTY_OP_VERASE3, &hf_ssh_pty_term_mode_verase }, | |||
| 5325 | { SSH_TTY_OP_VKILL4, &hf_ssh_pty_term_mode_vkill }, | |||
| 5326 | { SSH_TTY_OP_VEOF5, &hf_ssh_pty_term_mode_veof }, | |||
| 5327 | { SSH_TTY_OP_VEOL6, &hf_ssh_pty_term_mode_veol }, | |||
| 5328 | { SSH_TTY_OP_VEOL27, &hf_ssh_pty_term_mode_veol2 }, | |||
| 5329 | { SSH_TTY_OP_VSTART8, &hf_ssh_pty_term_mode_vstart }, | |||
| 5330 | { SSH_TTY_OP_VSTOP9, &hf_ssh_pty_term_mode_vstop }, | |||
| 5331 | { SSH_TTY_OP_VSUSP10, &hf_ssh_pty_term_mode_vsusp }, | |||
| 5332 | { SSH_TTY_OP_VDSUSP11, &hf_ssh_pty_term_mode_vdsusp }, | |||
| 5333 | { SSH_TTY_OP_VREPRINT12, &hf_ssh_pty_term_mode_vreprint }, | |||
| 5334 | { SSH_TTY_OP_VWERASE13, &hf_ssh_pty_term_mode_vwerase }, | |||
| 5335 | { SSH_TTY_OP_VLNEXT14, &hf_ssh_pty_term_mode_vlnext }, | |||
| 5336 | { SSH_TTY_OP_VFLUSH15, &hf_ssh_pty_term_mode_vflush }, | |||
| 5337 | { SSH_TTY_OP_VSWTCH16, &hf_ssh_pty_term_mode_vswtch }, | |||
| 5338 | { SSH_TTY_OP_VSTATUS17, &hf_ssh_pty_term_mode_vstatus }, | |||
| 5339 | { SSH_TTY_OP_VDISCARD18, &hf_ssh_pty_term_mode_vdiscard }, | |||
| 5340 | { SSH_TTY_OP_IGNPAR30, &hf_ssh_pty_term_mode_ignpar }, | |||
| 5341 | { SSH_TTY_OP_PARMRK31, &hf_ssh_pty_term_mode_parmrk }, | |||
| 5342 | { SSH_TTY_OP_INPCK32, &hf_ssh_pty_term_mode_inpck }, | |||
| 5343 | { SSH_TTY_OP_ISTRIP33, &hf_ssh_pty_term_mode_istrip }, | |||
| 5344 | { SSH_TTY_OP_INLCR34, &hf_ssh_pty_term_mode_inlcr }, | |||
| 5345 | { SSH_TTY_OP_IGNCR35, &hf_ssh_pty_term_mode_igncr }, | |||
| 5346 | { SSH_TTY_OP_ICRNL36, &hf_ssh_pty_term_mode_icrnl }, | |||
| 5347 | { SSH_TTY_OP_IUCLC37, &hf_ssh_pty_term_mode_iuclc }, | |||
| 5348 | { SSH_TTY_OP_IXON38, &hf_ssh_pty_term_mode_ixon }, | |||
| 5349 | { SSH_TTY_OP_IXANY39, &hf_ssh_pty_term_mode_ixany }, | |||
| 5350 | { SSH_TTY_OP_IXOFF40, &hf_ssh_pty_term_mode_ixoff }, | |||
| 5351 | { SSH_TTY_OP_IMAXBEL41, &hf_ssh_pty_term_mode_imaxbel }, | |||
| 5352 | { SSH_TTY_OP_IUTF842, &hf_ssh_pty_term_mode_iutf8 }, | |||
| 5353 | { SSH_TTY_OP_ISIG50, &hf_ssh_pty_term_mode_isig }, | |||
| 5354 | { SSH_TTY_OP_ICANON51, &hf_ssh_pty_term_mode_icanon }, | |||
| 5355 | { SSH_TTY_OP_XCASE52, &hf_ssh_pty_term_mode_xcase }, | |||
| 5356 | { SSH_TTY_OP_ECHO53, &hf_ssh_pty_term_mode_echo }, | |||
| 5357 | { SSH_TTY_OP_ECHOE54, &hf_ssh_pty_term_mode_echoe }, | |||
| 5358 | { SSH_TTY_OP_ECHOK55, &hf_ssh_pty_term_mode_echok }, | |||
| 5359 | { SSH_TTY_OP_ECHONL56, &hf_ssh_pty_term_mode_echonl }, | |||
| 5360 | { SSH_TTY_OP_NOFLSH57, &hf_ssh_pty_term_mode_noflsh }, | |||
| 5361 | { SSH_TTY_OP_TOSTOP58, &hf_ssh_pty_term_mode_tostop }, | |||
| 5362 | { SSH_TTY_OP_IEXTEN59, &hf_ssh_pty_term_mode_iexten }, | |||
| 5363 | { SSH_TTY_OP_ECHOCTL60, &hf_ssh_pty_term_mode_echoctl }, | |||
| 5364 | { SSH_TTY_OP_ECHOKE61, &hf_ssh_pty_term_mode_echoke }, | |||
| 5365 | { SSH_TTY_OP_PENDIN62, &hf_ssh_pty_term_mode_pendin }, | |||
| 5366 | { SSH_TTY_OP_OPOST70, &hf_ssh_pty_term_mode_opost }, | |||
| 5367 | { SSH_TTY_OP_OLCUC71, &hf_ssh_pty_term_mode_olcuc }, | |||
| 5368 | { SSH_TTY_OP_ONLCR72, &hf_ssh_pty_term_mode_onlcr }, | |||
| 5369 | { SSH_TTY_OP_OCRNL73, &hf_ssh_pty_term_mode_ocrnl }, | |||
| 5370 | { SSH_TTY_OP_ONOCR74, &hf_ssh_pty_term_mode_onocr }, | |||
| 5371 | { SSH_TTY_OP_ONLRET75, &hf_ssh_pty_term_mode_onlret }, | |||
| 5372 | { SSH_TTY_OP_CS790, &hf_ssh_pty_term_mode_cs7 }, | |||
| 5373 | { SSH_TTY_OP_CS891, &hf_ssh_pty_term_mode_cs8 }, | |||
| 5374 | { SSH_TTY_OP_PARENB92, &hf_ssh_pty_term_mode_parenb }, | |||
| 5375 | { SSH_TTY_OP_PARODD93, &hf_ssh_pty_term_mode_parodd }, | |||
| 5376 | { SSH_TTY_OP_ISPEED128, &hf_ssh_pty_term_mode_ispeed }, | |||
| 5377 | { SSH_TTY_OP_OSPEED129, &hf_ssh_pty_term_mode_ospeed } | |||
| 5378 | }; | |||
| 5379 | ||||
| 5380 | ti = proto_tree_add_item(tree, hf_ssh_pty_term_modes, tvb, offset, tvb_reported_length(tvb), ENC_NA0x00000000); | |||
| 5381 | term_mode_tree = proto_item_add_subtree(ti, ett_term_modes); | |||
| 5382 | while (tvb_reported_length_remaining(tvb, offset)) { | |||
| 5383 | ti = proto_tree_add_item(term_mode_tree, hf_ssh_pty_term_mode, tvb, offset, 5, ENC_NA0x00000000); | |||
| 5384 | subtree = proto_item_add_subtree(ti, ett_term_mode); | |||
| 5385 | proto_tree_add_item_ret_uint(subtree, hf_ssh_pty_term_mode_opcode, tvb, offset, 1, ENC_NA0x00000000, &opcode); | |||
| 5386 | proto_item_append_text(ti, ": %s", val_to_str_const(opcode, ssh_tty_op_vals, "Unknown")); | |||
| 5387 | offset += 1; | |||
| 5388 | if (opcode == SSH_TTY_OP_END0) { | |||
| 5389 | break; | |||
| 5390 | } | |||
| 5391 | for (idx = 0; idx < array_length(tty_opts)(sizeof (tty_opts) / sizeof (tty_opts)[0]); idx++) { | |||
| 5392 | if (tty_opts[idx].id == opcode) break; | |||
| 5393 | } | |||
| 5394 | if (idx >= array_length(tty_opts)(sizeof (tty_opts) / sizeof (tty_opts)[0])) { | |||
| 5395 | proto_tree_add_item_ret_uint(subtree, hf_ssh_pty_term_mode_value, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &value); | |||
| 5396 | proto_item_append_text(ti, "=%d", value); | |||
| 5397 | } else { | |||
| 5398 | 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" , 5398, "tty_opts[idx].hfindex")))); | |||
| 5399 | int hfindex = *tty_opts[idx].hfindex; | |||
| 5400 | switch (proto_registrar_get_ftype(hfindex)) { | |||
| 5401 | case FT_BOOLEAN: | |||
| 5402 | proto_tree_add_item_ret_boolean(subtree, hfindex, tvb, offset + 3, 1, ENC_NA0x00000000, &boolval); | |||
| 5403 | proto_item_append_text(ti, "=%s", boolval ? "True" : "False"); | |||
| 5404 | break; | |||
| 5405 | case FT_CHAR: | |||
| 5406 | proto_tree_add_item_ret_uint(subtree, hfindex, tvb, offset + 3, 1, ENC_NA0x00000000, &value); | |||
| 5407 | proto_item_append_text(ti, "='%s'", format_char(pinfo->pool, (char)value)); | |||
| 5408 | break; | |||
| 5409 | case FT_UINT32: | |||
| 5410 | proto_tree_add_item_ret_uint(subtree, hfindex, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &value); | |||
| 5411 | proto_item_append_text(ti, "=%d", value); | |||
| 5412 | break; | |||
| 5413 | default: | |||
| 5414 | DISSECTOR_ASSERT_NOT_REACHED()(proto_report_dissector_bug("%s:%u: failed assertion \"DISSECTOR_ASSERT_NOT_REACHED\"" , "epan/dissectors/packet-ssh.c", 5414)); | |||
| 5415 | } | |||
| 5416 | } | |||
| 5417 | offset += 4; | |||
| 5418 | } | |||
| 5419 | return offset; | |||
| 5420 | } | |||
| 5421 | ||||
| 5422 | static int | |||
| 5423 | ssh_dissect_connection_specific(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 5424 | struct ssh_peer_data *peer_data, int offset, proto_tree *msg_type_tree, | |||
| 5425 | unsigned msg_code, ssh_message_info_t *message) | |||
| 5426 | { | |||
| 5427 | uint32_t recipient_channel, sender_channel; | |||
| 5428 | ||||
| 5429 | if (msg_code == SSH_MSG_CHANNEL_OPEN90) { | |||
| 5430 | uint32_t slen; | |||
| 5431 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_type_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5432 | offset += 4; | |||
| 5433 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_type_name, packet_tvb, offset, slen, ENC_UTF_80x00000002); | |||
| 5434 | offset += slen; | |||
| 5435 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_sender_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5436 | offset += 4; | |||
| 5437 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_initial_window, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5438 | offset += 4; | |||
| 5439 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_maximum_packet_size, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5440 | offset += 4; | |||
| 5441 | } else if (msg_code == SSH_MSG_CHANNEL_OPEN_CONFIRMATION91) { | |||
| 5442 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel); | |||
| 5443 | offset += 4; | |||
| 5444 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_sender_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &sender_channel); | |||
| 5445 | offset += 4; | |||
| 5446 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 5447 | create_channel(peer_data, recipient_channel, sender_channel); | |||
| 5448 | } | |||
| 5449 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_initial_window, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5450 | offset += 4; | |||
| 5451 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_maximum_packet_size, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5452 | offset += 4; | |||
| 5453 | } else if (msg_code == SSH_MSG_CHANNEL_WINDOW_ADJUST93) { | |||
| 5454 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5455 | offset += 4; | |||
| 5456 | 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 | |||
| 5457 | offset += 4; | |||
| 5458 | } else if (msg_code == SSH_MSG_CHANNEL_DATA94) { | |||
| 5459 | 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); | |||
| 5460 | offset += 4; | |||
| 5461 | // TODO: process according to the type of channel | |||
| 5462 | uint32_t slen; | |||
| 5463 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_data_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5464 | offset += 4; | |||
| 5465 | tvbuff_t* next_tvb = tvb_new_subset_length(packet_tvb, offset, slen); | |||
| 5466 | ||||
| 5467 | ssh_channel_info_t* channel = get_channel_info_for_channel(peer_data, recipient_channel); | |||
| 5468 | if (channel) { | |||
| 5469 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 5470 | message->byte_seq = channel->byte_seq; | |||
| 5471 | channel->byte_seq += slen; | |||
| 5472 | message->next_byte_seq = channel->byte_seq; | |||
| 5473 | } | |||
| 5474 | ssh_dissect_channel_data(next_tvb, pinfo, peer_data, msg_type_tree, message, channel); | |||
| 5475 | } else { | |||
| 5476 | expert_add_info_format(pinfo, ti, &ei_ssh_channel_number, "Could not find configuration for channel %d", recipient_channel); | |||
| 5477 | } | |||
| 5478 | offset += slen; | |||
| 5479 | } else if (msg_code == SSH_MSG_CHANNEL_EXTENDED_DATA95) { | |||
| 5480 | 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); | |||
| 5481 | offset += 4; | |||
| 5482 | // TODO: process according to the type of channel | |||
| 5483 | proto_tree_add_item(msg_type_tree, hf_ssh_channel_data_type_code, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5484 | offset += 4; | |||
| 5485 | uint32_t slen; | |||
| 5486 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_data_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5487 | offset += 4; | |||
| 5488 | tvbuff_t* next_tvb = tvb_new_subset_length(packet_tvb, offset, slen); | |||
| 5489 | ||||
| 5490 | ssh_channel_info_t* channel = get_channel_info_for_channel(peer_data, recipient_channel); | |||
| 5491 | if (channel) { | |||
| 5492 | if (!PINFO_FD_VISITED(pinfo)((pinfo)->fd->visited)) { | |||
| 5493 | message->byte_seq = channel->byte_seq; | |||
| 5494 | channel->byte_seq += slen; | |||
| 5495 | message->next_byte_seq = channel->byte_seq; | |||
| 5496 | } | |||
| 5497 | ssh_dissect_channel_data(next_tvb, pinfo, peer_data, msg_type_tree, message, channel); | |||
| 5498 | } else { | |||
| 5499 | expert_add_info_format(pinfo, ti, &ei_ssh_channel_number, "Could not find configuration for channel %d", recipient_channel); | |||
| 5500 | } | |||
| 5501 | offset += slen; | |||
| 5502 | } else if (msg_code == SSH_MSG_CHANNEL_EOF96) { | |||
| 5503 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5504 | offset += 4; | |||
| 5505 | } else if (msg_code == SSH_MSG_CHANNEL_CLOSE97) { | |||
| 5506 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5507 | offset += 4; | |||
| 5508 | } else if (msg_code == SSH_MSG_CHANNEL_REQUEST98) { | |||
| 5509 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &recipient_channel); | |||
| 5510 | offset += 4; | |||
| 5511 | const uint8_t* request_name; | |||
| 5512 | uint32_t slen; | |||
| 5513 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_channel_request_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5514 | offset += 4; | |||
| 5515 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_channel_request_name, packet_tvb, offset, slen, ENC_UTF_80x00000002, pinfo->pool, &request_name); | |||
| 5516 | offset += slen; | |||
| 5517 | proto_tree_add_item(msg_type_tree, hf_ssh_channel_request_want_reply, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 5518 | offset += 1; | |||
| 5519 | /* RFC 4254 6.5: "Only one of these requests ["shell", "exec", | |||
| 5520 | * or "subsystem"] can succeed per channel." Set up the | |||
| 5521 | * appropriate handler for future CHANNEL_DATA and | |||
| 5522 | * CHANNEL_EXTENDED_DATA messages on the channel. | |||
| 5523 | * | |||
| 5524 | * XXX - For "shell" and "exec", it might make more sense to send | |||
| 5525 | * CHANNEL_DATA to the "data-text-lines" dissector rather than "data". | |||
| 5526 | * Ideally if a pty has been setup there would be a way to interpret | |||
| 5527 | * the escape codes. | |||
| 5528 | */ | |||
| 5529 | if (0 == strcmp(request_name, "subsystem")) { | |||
| 5530 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_subsystem_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5531 | offset += 4; | |||
| 5532 | const uint8_t* subsystem_name; | |||
| 5533 | proto_tree_add_item_ret_string(msg_type_tree, hf_ssh_subsystem_name, packet_tvb, offset, slen, ENC_UTF_80x00000002, pinfo->pool, &subsystem_name); | |||
| 5534 | set_subdissector_for_channel(peer_data, recipient_channel, subsystem_name); | |||
| 5535 | offset += slen; | |||
| 5536 | } else if (0 == strcmp(request_name, "env")) { | |||
| 5537 | /* The encoding for "env" variables and "exec" commands is not | |||
| 5538 | * specified in the SSH protocol, and must match whatever the | |||
| 5539 | * server expects. (Unlike CHANNEL_DATA, it is not affected by | |||
| 5540 | * whatever is in "env" or anything else in the protocol, and the | |||
| 5541 | * strings are passed to execve directly.) In practice the strings | |||
| 5542 | * must not have internal NULs (no UTF-16), and OpenSSH for Windows | |||
| 5543 | * and IBM z/OS force the use of UTF-8 and ISO-8859-1, respectively. | |||
| 5544 | * | |||
| 5545 | * These will probably be ASCII-compatible. | |||
| 5546 | */ | |||
| 5547 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_env_name, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &slen); | |||
| 5548 | offset += slen; | |||
| 5549 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_env_value, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &slen); | |||
| 5550 | offset += slen; | |||
| 5551 | } else if (0 == strcmp(request_name, "exec")) { | |||
| 5552 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_exec_cmd, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &slen); | |||
| 5553 | offset += slen; | |||
| 5554 | set_subdissector_for_channel(peer_data, recipient_channel, "exec"); | |||
| 5555 | } else if (0 == strcmp(request_name, "exit-status")) { | |||
| 5556 | proto_tree_add_item(msg_type_tree, hf_ssh_exit_status, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5557 | offset += 4; | |||
| 5558 | } else if (0 == strcmp(request_name, "shell")) { | |||
| 5559 | set_subdissector_for_channel(peer_data, recipient_channel, "shell"); | |||
| 5560 | } else if (0 == strcmp(request_name, "pty-req")) { | |||
| 5561 | proto_tree_add_item_ret_length(msg_type_tree, hf_ssh_pty_term, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000 | ENC_UTF_80x00000002, &slen); | |||
| 5562 | offset += slen; | |||
| 5563 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_width_char, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5564 | offset += 4; | |||
| 5565 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_height_row, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5566 | offset += 4; | |||
| 5567 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_width_pixel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5568 | offset += 4; | |||
| 5569 | proto_tree_add_item(msg_type_tree, hf_ssh_pty_term_height_pixel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5570 | offset += 4; | |||
| 5571 | proto_tree_add_item_ret_uint(msg_type_tree, hf_ssh_pty_term_modes_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5572 | offset += 4; | |||
| 5573 | offset += ssh_dissect_term_modes(tvb_new_subset_length(packet_tvb, offset, slen), pinfo, msg_type_tree); | |||
| 5574 | } | |||
| 5575 | } else if (msg_code == SSH_MSG_CHANNEL_SUCCESS99) { | |||
| 5576 | proto_tree_add_item(msg_type_tree, hf_ssh_connection_recipient_channel, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5577 | offset += 4; | |||
| 5578 | } | |||
| 5579 | return offset; | |||
| 5580 | } | |||
| 5581 | ||||
| 5582 | /* Channel mapping {{{ */ | |||
| 5583 | ||||
| 5584 | /* The usual flow: | |||
| 5585 | * 1. client sends SSH_MSG_CHANNEL_OPEN with its (sender) channel number | |||
| 5586 | * 2. server responds with SSH_MSG_CHANNEL_OPEN_CONFIRMATION with | |||
| 5587 | * its channel number and echoing the client's number, creating | |||
| 5588 | * a bijective map | |||
| 5589 | * 3. client sends SSH_MSG_CHANNEL_REQUEST which has the name of | |||
| 5590 | * the shell, command, or subsystem to start. This has the recipient's | |||
| 5591 | * channel number (i.e. the server's) | |||
| 5592 | * 4. server may send back a SSG_MSG_CHANNEL_SUCCESS (or _FAILURE) with | |||
| 5593 | * the the recipient (i.e., client) channel number, but this does not | |||
| 5594 | * contain the subsystem name or anything identifying the request to | |||
| 5595 | * which it responds. It MUST be sent in the same order as the | |||
| 5596 | * corresponding request message (RFC 4254 4 Global Requests), so we | |||
| 5597 | * could track it that way, but for our purposes we just treat all | |||
| 5598 | * requests as successes. (If not, either there won't be data or another | |||
| 5599 | * request will supercede it later.) | |||
| 5600 | * | |||
| 5601 | * Either side can open a channel (RFC 4254 5 Channel Mechanism). The | |||
| 5602 | * typical flow is the client opening a channel, but in the case of | |||
| 5603 | * remote port forwarding (7 TCP/IP Port Forwarding) the directions are | |||
| 5604 | * swapped. For port forwarding, all the information is contained in the | |||
| 5605 | * SSH_MSG_CHANNEL_OPEN, there is no SSH_MSG_CHANNEL_REQUEST. | |||
| 5606 | * | |||
| 5607 | * XXX: Channel numbers can be re-used after being closed (5.3 Closing a | |||
| 5608 | * Channel), but not necessarily mapped to the same channel number on the | |||
| 5609 | * other side. If that actually happens, the right way to handle this is | |||
| 5610 | * to track the state changes over time for random packet access (e.g., | |||
| 5611 | * using a multimap with the packet number instead of maps.) | |||
| 5612 | */ | |||
| 5613 | ||||
| 5614 | static struct ssh_peer_data* | |||
| 5615 | get_other_peer_data(struct ssh_peer_data *peer_data) | |||
| 5616 | { | |||
| 5617 | bool_Bool is_server = &peer_data->global_data->peer_data[SERVER_PEER_DATA1]==peer_data; | |||
| 5618 | if (is_server) { | |||
| 5619 | return &peer_data->global_data->peer_data[CLIENT_PEER_DATA0]; | |||
| 5620 | } else { | |||
| 5621 | return &peer_data->global_data->peer_data[SERVER_PEER_DATA1]; | |||
| 5622 | } | |||
| 5623 | } | |||
| 5624 | ||||
| 5625 | /* Create pairings between a recipient channel and the sender's channel, | |||
| 5626 | * from a SSH_MSG_CHANNEL_OPEN_CONFIRMATION. */ | |||
| 5627 | static void | |||
| 5628 | create_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, uint32_t sender_channel) | |||
| 5629 | { | |||
| 5630 | if (peer_data->channel_info == NULL((void*)0)) { | |||
| 5631 | peer_data->channel_info = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); | |||
| 5632 | } | |||
| 5633 | 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))); | |||
| 5634 | ||||
| 5635 | if (peer_data->channel_handles == NULL((void*)0)) { | |||
| 5636 | peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); | |||
| 5637 | } | |||
| 5638 | ||||
| 5639 | 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))); | |||
| 5640 | new_channel->multisegment_pdus = wmem_tree_new(wmem_file_scope()); | |||
| 5641 | wmem_map_insert(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), new_channel); | |||
| 5642 | ||||
| 5643 | /* If the recipient channel is already configured in the other direction, | |||
| 5644 | * set the handle. We need this if we eventually handle port forwarding, | |||
| 5645 | * where all the information to handle the traffic is sent in the | |||
| 5646 | * SSH_MSG_CHANNEL_OPEN message before the CONFIRMATION. It might also | |||
| 5647 | * help if the packets are out of order (i.e. we get the client | |||
| 5648 | * CHANNEL_REQUEST before the CHANNEL_OPEN_CONFIRMATION.) | |||
| 5649 | */ | |||
| 5650 | struct ssh_peer_data *other_peer_data = get_other_peer_data(peer_data); | |||
| 5651 | if (other_peer_data->channel_handles) { | |||
| 5652 | ssh_channel_info_t *peer_channel = wmem_map_lookup(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel))); | |||
| 5653 | if (peer_channel) { | |||
| 5654 | new_channel->handle = peer_channel->handle; | |||
| 5655 | } | |||
| 5656 | } | |||
| 5657 | } | |||
| 5658 | ||||
| 5659 | static ssh_channel_info_t* | |||
| 5660 | get_channel_info_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel) | |||
| 5661 | { | |||
| 5662 | if (peer_data->channel_handles == NULL((void*)0)) { | |||
| 5663 | return NULL((void*)0); | |||
| 5664 | } | |||
| 5665 | ssh_channel_info_t *channel = wmem_map_lookup(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel))); | |||
| 5666 | ||||
| 5667 | return channel; | |||
| 5668 | } | |||
| 5669 | ||||
| 5670 | static void | |||
| 5671 | set_subdissector_for_channel(struct ssh_peer_data *peer_data, uint32_t recipient_channel, const uint8_t* subsystem_name) | |||
| 5672 | { | |||
| 5673 | dissector_handle_t handle = NULL((void*)0); | |||
| 5674 | if (0 == strcmp(subsystem_name, "sftp")) { | |||
| 5675 | handle = sftp_handle; | |||
| 5676 | } else if (0 == strcmp(subsystem_name, "shell") || | |||
| 5677 | 0 == strcmp(subsystem_name, "exec")) { | |||
| 5678 | handle = data_text_lines_handle; | |||
| 5679 | } | |||
| 5680 | ||||
| 5681 | if (handle) { | |||
| 5682 | /* Map this handle to the recipient channel */ | |||
| 5683 | ssh_channel_info_t *channel = NULL((void*)0); | |||
| 5684 | if (peer_data->channel_handles == NULL((void*)0)) { | |||
| 5685 | peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); | |||
| 5686 | } else { | |||
| 5687 | channel = wmem_map_lookup(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel))); | |||
| 5688 | } | |||
| 5689 | if (channel == NULL((void*)0)) { | |||
| 5690 | channel = wmem_new0(wmem_file_scope(), ssh_channel_info_t)((ssh_channel_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_channel_info_t))); | |||
| 5691 | channel->multisegment_pdus = wmem_tree_new(wmem_file_scope()); | |||
| 5692 | wmem_map_insert(peer_data->channel_handles, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), channel); | |||
| 5693 | } | |||
| 5694 | channel->handle = handle; | |||
| 5695 | ||||
| 5696 | /* This recipient channel is the sender channel for the other side. | |||
| 5697 | * Do we know what the recipient channel on the other side is? */ | |||
| 5698 | struct ssh_peer_data *other_peer_data = get_other_peer_data(peer_data); | |||
| 5699 | ||||
| 5700 | wmem_map_t *channel_info = other_peer_data->channel_info; | |||
| 5701 | if (channel_info) { | |||
| 5702 | void *sender_channel_p; | |||
| 5703 | if (wmem_map_lookup_extended(channel_info, GUINT_TO_POINTER(recipient_channel)((gpointer) (gulong) (recipient_channel)), NULL((void*)0), &sender_channel_p)) { | |||
| 5704 | uint32_t sender_channel = GPOINTER_TO_UINT(sender_channel_p)((guint) (gulong) (sender_channel_p)); | |||
| 5705 | /* Yes. See the handle for the other side too. */ | |||
| 5706 | if (other_peer_data->channel_handles == NULL((void*)0)) { | |||
| 5707 | other_peer_data->channel_handles = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); | |||
| 5708 | channel = NULL((void*)0); | |||
| 5709 | } else { | |||
| 5710 | channel = wmem_map_lookup(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel))); | |||
| 5711 | } | |||
| 5712 | if (channel == NULL((void*)0)) { | |||
| 5713 | channel = wmem_new0(wmem_file_scope(), ssh_channel_info_t)((ssh_channel_info_t*)wmem_alloc0((wmem_file_scope()), sizeof (ssh_channel_info_t))); | |||
| 5714 | channel->multisegment_pdus = wmem_tree_new(wmem_file_scope()); | |||
| 5715 | wmem_map_insert(other_peer_data->channel_handles, GUINT_TO_POINTER(sender_channel)((gpointer) (gulong) (sender_channel)), channel); | |||
| 5716 | } | |||
| 5717 | channel->handle = handle; | |||
| 5718 | } | |||
| 5719 | } | |||
| 5720 | } | |||
| 5721 | } | |||
| 5722 | ||||
| 5723 | /* Channel mapping. }}} */ | |||
| 5724 | ||||
| 5725 | static int | |||
| 5726 | ssh_dissect_connection_generic(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 5727 | int offset, proto_item *msg_type_tree, unsigned msg_code) | |||
| 5728 | { | |||
| 5729 | (void)pinfo; | |||
| 5730 | if(msg_code==SSH_MSG_GLOBAL_REQUEST80){ | |||
| 5731 | uint8_t* request_name; | |||
| 5732 | unsigned slen; | |||
| 5733 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 5734 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_name_len, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5735 | offset += 4; | |||
| 5736 | request_name = tvb_get_string_enc(pinfo->pool, packet_tvb, offset, slen, ENC_ASCII0x00000000|ENC_NA0x00000000); | |||
| 5737 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 5738 | offset += slen; | |||
| 5739 | proto_tree_add_item(msg_type_tree, hf_ssh_global_request_want_reply, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 5740 | offset += 1; | |||
| 5741 | if (0 == strcmp(request_name, "hostkeys-00@openssh.com") || | |||
| 5742 | 0 == strcmp(request_name, "hostkeys-prove-00@openssh.com")) { | |||
| 5743 | while (tvb_reported_length_remaining(packet_tvb, offset)) { | |||
| 5744 | offset += ssh_tree_add_hostkey(packet_tvb, offset, msg_type_tree, | |||
| 5745 | "Server host key", ett_key_exchange_host_key, NULL((void*)0)); | |||
| 5746 | } | |||
| 5747 | } | |||
| 5748 | } | |||
| 5749 | return offset; | |||
| 5750 | } | |||
| 5751 | ||||
| 5752 | static int | |||
| 5753 | ssh_dissect_local_extension(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 5754 | int offset, struct ssh_peer_data *peer_data, proto_item *msg_type_tree, unsigned msg_code) { | |||
| 5755 | unsigned slen; | |||
| 5756 | if (peer_data->global_data->ext_ping_openssh_offered && msg_code >= SSH_MSG_PING192 && msg_code <= SSH_MSG_PONG193) { | |||
| 5757 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_ext_ping_msg_vals, "Unknown (%u)")); | |||
| 5758 | proto_tree_add_item(msg_type_tree, hf_ssh2_ext_ping_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 5759 | offset += 1; | |||
| 5760 | if (msg_code == SSH_MSG_PING192) { | |||
| 5761 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 5762 | proto_tree_add_item(msg_type_tree, hf_ssh_ping_data_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5763 | offset += 4; | |||
| 5764 | proto_tree_add_item(msg_type_tree, hf_ssh_ping_data, packet_tvb, offset, slen, ENC_NA0x00000000); | |||
| 5765 | offset += slen; | |||
| 5766 | } else if (msg_code == SSH_MSG_PONG193) { | |||
| 5767 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 5768 | proto_tree_add_item(msg_type_tree, hf_ssh_pong_data_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5769 | offset += 4; | |||
| 5770 | proto_tree_add_item(msg_type_tree, hf_ssh_pong_data, packet_tvb, offset, slen, ENC_NA0x00000000); | |||
| 5771 | offset += slen; | |||
| 5772 | } | |||
| 5773 | } else { | |||
| 5774 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL((void*)0), val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)")); | |||
| 5775 | proto_tree_add_item(msg_type_tree, hf_ssh2_msg_code, packet_tvb, offset, 1, ENC_BIG_ENDIAN0x00000000); | |||
| 5776 | offset += 1; | |||
| 5777 | } | |||
| 5778 | return offset; | |||
| 5779 | } | |||
| 5780 | ||||
| 5781 | static int | |||
| 5782 | ssh_dissect_public_key_blob(tvbuff_t *tvb, packet_info *pinfo, proto_item *tree) | |||
| 5783 | { | |||
| 5784 | uint32_t slen; | |||
| 5785 | const uint8_t* key_type; | |||
| 5786 | ||||
| 5787 | int offset = 0; | |||
| 5788 | proto_tree *blob_tree = NULL((void*)0); | |||
| 5789 | proto_item *blob_item = NULL((void*)0); | |||
| 5790 | ||||
| 5791 | blob_item = proto_tree_add_item(tree, hf_ssh_blob, tvb, offset, tvb_reported_length(tvb), ENC_NA0x00000000); | |||
| 5792 | blob_tree = proto_item_add_subtree(blob_item, ett_userauth_pk_blob); | |||
| 5793 | proto_tree_add_item_ret_uint(blob_tree, hf_ssh_pk_blob_name_length, tvb, offset, 4, ENC_BIG_ENDIAN0x00000000, &slen); | |||
| 5794 | offset += 4; | |||
| 5795 | proto_tree_add_item_ret_string(blob_tree, hf_ssh_pk_blob_name, tvb, offset, slen, ENC_ASCII0x00000000, pinfo->pool, &key_type); | |||
| 5796 | proto_item_append_text(blob_item, " (type: %s)", key_type); | |||
| 5797 | offset += slen; | |||
| 5798 | ||||
| 5799 | if (0 == strcmp(key_type, "ssh-rsa")) { | |||
| 5800 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_e); | |||
| 5801 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_n); | |||
| 5802 | } else if (0 == strcmp(key_type, "ssh-dss")) { | |||
| 5803 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_p); | |||
| 5804 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_q); | |||
| 5805 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_g); | |||
| 5806 | offset += ssh_tree_add_mpint(tvb, offset, blob_tree, hf_ssh_blob_dsa_y); | |||
| 5807 | } 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-" ) )) { | |||
| 5808 | offset += ssh_tree_add_string(tvb, offset, blob_tree, | |||
| 5809 | hf_ssh_blob_ecdsa_curve_id, hf_ssh_blob_ecdsa_curve_id_length); | |||
| 5810 | offset += ssh_tree_add_string(tvb, offset, blob_tree, | |||
| 5811 | hf_ssh_blob_ecdsa_q, hf_ssh_blob_ecdsa_q_length); | |||
| 5812 | } 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") )) { | |||
| 5813 | offset += ssh_tree_add_string(tvb, offset, blob_tree, | |||
| 5814 | hf_ssh_blob_eddsa_key, hf_ssh_blob_eddsa_key_length); | |||
| 5815 | } else { | |||
| 5816 | proto_tree_add_item(blob_tree, hf_ssh_blob_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA0x00000000); | |||
| 5817 | offset += tvb_reported_length_remaining(tvb, offset); | |||
| 5818 | } | |||
| 5819 | ||||
| 5820 | return offset; | |||
| 5821 | } | |||
| 5822 | ||||
| 5823 | static int | |||
| 5824 | ssh_dissect_public_key_signature(tvbuff_t *packet_tvb, packet_info *pinfo, | |||
| 5825 | int offset, proto_item *msg_type_tree) | |||
| 5826 | { | |||
| 5827 | (void)pinfo; | |||
| 5828 | unsigned slen; | |||
| 5829 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 5830 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_blob_name_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5831 | offset += 4; | |||
| 5832 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_blob_name, packet_tvb, offset, slen, ENC_ASCII0x00000000); | |||
| 5833 | offset += slen; | |||
| 5834 | slen = tvb_get_ntohl(packet_tvb, offset) ; | |||
| 5835 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_s_length, packet_tvb, offset, 4, ENC_BIG_ENDIAN0x00000000); | |||
| 5836 | offset += 4; | |||
| 5837 | proto_tree_add_item(msg_type_tree, hf_ssh_pk_sig_s, packet_tvb, offset, slen, ENC_NA0x00000000); | |||
| 5838 | offset += slen; | |||
| 5839 | return offset; | |||
| 5840 | } | |||
| 5841 | ||||
| 5842 | #ifdef SSH_DECRYPT_DEBUG /* {{{ */ | |||
| 5843 | ||||
| 5844 | static FILE* ssh_debug_file; | |||
| 5845 | ||||
| 5846 | static void | |||
| 5847 | ssh_prefs_apply_cb(void) | |||
| 5848 | { | |||
| 5849 | ssh_set_debug(ssh_debug_file_name); | |||
| 5850 | } | |||
| 5851 | ||||
| 5852 | static void | |||
| 5853 | ssh_set_debug(const char* name) | |||
| 5854 | { | |||
| 5855 | static int debug_file_must_be_closed; | |||
| 5856 | int use_stderr; | |||
| 5857 | ||||
| 5858 | use_stderr = name?(strcmp(name, SSH_DEBUG_USE_STDERR"-") == 0):0; | |||
| 5859 | ||||
| 5860 | if (debug_file_must_be_closed) | |||
| 5861 | fclose(ssh_debug_file); | |||
| 5862 | ||||
| 5863 | if (use_stderr) | |||
| 5864 | ssh_debug_file = stderrstderr; | |||
| 5865 | else if (!name || (strcmp(name, "") ==0)) | |||
| 5866 | ssh_debug_file = NULL((void*)0); | |||
| 5867 | else | |||
| 5868 | ssh_debug_file = ws_fopenfopen(name, "w"); | |||
| 5869 | ||||
| 5870 | if (!use_stderr && ssh_debug_file) | |||
| 5871 | debug_file_must_be_closed = 1; | |||
| 5872 | else | |||
| 5873 | debug_file_must_be_closed = 0; | |||
| 5874 | ||||
| 5875 | ssh_debug_printf("Wireshark SSH debug log \n\n"); | |||
| 5876 | #ifdef HAVE_LIBGNUTLS1 | |||
| 5877 | ssh_debug_printf("GnuTLS version: %s\n", gnutls_check_version(NULL((void*)0))); | |||
| 5878 | #endif | |||
| 5879 | ssh_debug_printf("Libgcrypt version: %s\n", gcry_check_version(NULL((void*)0))); | |||
| 5880 | ssh_debug_printf("\n"); | |||
| 5881 | } | |||
| 5882 | ||||
| 5883 | static void | |||
| 5884 | ssh_debug_flush(void) | |||
| 5885 | { | |||
| 5886 | if (ssh_debug_file) | |||
| 5887 | fflush(ssh_debug_file); | |||
| 5888 | } | |||
| 5889 | ||||
| 5890 | static void | |||
| 5891 | ssh_debug_printf(const char* fmt, ...) | |||
| 5892 | { | |||
| 5893 | va_list ap; | |||
| 5894 | ||||
| 5895 | if (!ssh_debug_file) | |||
| 5896 | return; | |||
| 5897 | ||||
| 5898 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
| 5899 | vfprintf(ssh_debug_file, fmt, ap); | |||
| 5900 | va_end(ap)__builtin_va_end(ap); | |||
| 5901 | } | |||
| 5902 | ||||
| 5903 | static void | |||
| 5904 | ssh_print_data(const char* name, const unsigned char* data, size_t len) | |||
| 5905 | { | |||
| 5906 | size_t i, j, k; | |||
| 5907 | if (!ssh_debug_file) | |||
| 5908 | return; | |||
| 5909 | #ifdef OPENSSH_STYLE | |||
| 5910 | fprintf(ssh_debug_file,"%s[%d]\n",name, (int) len); | |||
| 5911 | #else | |||
| 5912 | fprintf(ssh_debug_file,"%s[%d]:\n",name, (int) len); | |||
| 5913 | #endif | |||
| 5914 | for (i=0; i<len; i+=16) { | |||
| 5915 | #ifdef OPENSSH_STYLE | |||
| 5916 | fprintf(ssh_debug_file,"%04u: ", (unsigned int)i); | |||
| 5917 | #else | |||
| 5918 | fprintf(ssh_debug_file,"| "); | |||
| 5919 | #endif | |||
| 5920 | for (j=i, k=0; k<16 && j<len; ++j, ++k) | |||
| 5921 | fprintf(ssh_debug_file,"%.2x ",data[j]); | |||
| 5922 | for (; k<16; ++k) | |||
| 5923 | fprintf(ssh_debug_file," "); | |||
| 5924 | #ifdef OPENSSH_STYLE | |||
| 5925 | fputc(' ', ssh_debug_file); | |||
| 5926 | #else | |||
| 5927 | fputc('|', ssh_debug_file); | |||
| 5928 | #endif | |||
| 5929 | for (j=i, k=0; k<16 && j<len; ++j, ++k) { | |||
| 5930 | unsigned char c = data[j]; | |||
| 5931 | if (!g_ascii_isprint(c)((g_ascii_table[(guchar) (c)] & G_ASCII_PRINT) != 0) || (c=='\t')) c = '.'; | |||
| 5932 | fputc(c, ssh_debug_file); | |||
| 5933 | } | |||
| 5934 | #ifdef OPENSSH_STYLE | |||
| 5935 | fprintf(ssh_debug_file,"\n"); | |||
| 5936 | #else | |||
| 5937 | for (; k<16; ++k) | |||
| 5938 | fputc(' ', ssh_debug_file); | |||
| 5939 | fprintf(ssh_debug_file,"|\n"); | |||
| 5940 | #endif | |||
| 5941 | } | |||
| 5942 | } | |||
| 5943 | ||||
| 5944 | #endif /* SSH_DECRYPT_DEBUG }}} */ | |||
| 5945 | ||||
| 5946 | static void | |||
| 5947 | ssh_secrets_block_callback(const void *secrets, unsigned size) | |||
| 5948 | { | |||
| 5949 | ssh_keylog_process_lines((const uint8_t *)secrets, size); | |||
| 5950 | } | |||
| 5951 | ||||
| 5952 | /* Functions for SSH random hashtables. {{{ */ | |||
| 5953 | static int | |||
| 5954 | ssh_equal (const void *v, const void *v2) | |||
| 5955 | { | |||
| 5956 | if (v == NULL((void*)0) || v2 == NULL((void*)0)) { | |||
| 5957 | return 0; | |||
| 5958 | } | |||
| 5959 | ||||
| 5960 | const ssh_bignum *val1; | |||
| 5961 | const ssh_bignum *val2; | |||
| 5962 | val1 = (const ssh_bignum *)v; | |||
| 5963 | val2 = (const ssh_bignum *)v2; | |||
| 5964 | ||||
| 5965 | if (val1->length == val2->length && | |||
| 5966 | !memcmp(val1->data, val2->data, val2->length)) { | |||
| 5967 | return 1; | |||
| 5968 | } | |||
| 5969 | return 0; | |||
| 5970 | } | |||
| 5971 | ||||
| 5972 | static unsigned | |||
| 5973 | ssh_hash (const void *v) | |||
| 5974 | { | |||
| 5975 | unsigned l,hash; | |||
| 5976 | const ssh_bignum* id; | |||
| 5977 | const unsigned* cur; | |||
| 5978 | ||||
| 5979 | if (v == NULL((void*)0)) { | |||
| 5980 | return 0; | |||
| 5981 | } | |||
| 5982 | ||||
| 5983 | hash = 0; | |||
| 5984 | id = (const ssh_bignum*) v; | |||
| 5985 | ||||
| 5986 | /* id and id->data are mallocated in ssh_save_master_key(). As such 'data' | |||
| 5987 | * should be aligned for any kind of access (for example as a unsigned as | |||
| 5988 | * is done below). The intermediate void* cast is to prevent "cast | |||
| 5989 | * increases required alignment of target type" warnings on CPUs (such | |||
| 5990 | * as SPARCs) that do not allow misaligned memory accesses. | |||
| 5991 | */ | |||
| 5992 | cur = (const unsigned*)(void*) id->data; | |||
| 5993 | ||||
| 5994 | for (l=4; (l < id->length); l+=4, cur++) | |||
| 5995 | hash = hash ^ (*cur); | |||
| 5996 | ||||
| 5997 | return hash; | |||
| 5998 | } | |||
| 5999 | ||||
| 6000 | static void | |||
| 6001 | ssh_free_glib_allocated_bignum(void *data) | |||
| 6002 | { | |||
| 6003 | ssh_bignum * bignum; | |||
| 6004 | if (data == NULL((void*)0)) { | |||
| 6005 | return; | |||
| 6006 | } | |||
| 6007 | ||||
| 6008 | bignum = (ssh_bignum *) data; | |||
| 6009 | g_free(bignum->data); | |||
| 6010 | g_free(bignum); | |||
| 6011 | } | |||
| 6012 | ||||
| 6013 | static void | |||
| 6014 | ssh_free_glib_allocated_entry(void *data) | |||
| 6015 | { | |||
| 6016 | ssh_key_map_entry_t * entry; | |||
| 6017 | if (data == NULL((void*)0)) { | |||
| 6018 | return; | |||
| 6019 | } | |||
| 6020 | ||||
| 6021 | entry = (ssh_key_map_entry_t *) data; | |||
| 6022 | g_free(entry->type); | |||
| 6023 | ssh_free_glib_allocated_bignum(entry->key_material); | |||
| 6024 | g_free(entry); | |||
| 6025 | } | |||
| 6026 | /* Functions for SSH random hashtables. }}} */ | |||
| 6027 | ||||
| 6028 | static void | |||
| 6029 | ssh_shutdown(void) { | |||
| 6030 | g_hash_table_destroy(ssh_master_key_map); | |||
| 6031 | } | |||
| 6032 | ||||
| 6033 | void | |||
| 6034 | proto_register_ssh(void) | |||
| 6035 | { | |||
| 6036 | static hf_register_info hf[] = { | |||
| 6037 | { &hf_ssh_protocol, | |||
| 6038 | { "Protocol", "ssh.protocol", | |||
| 6039 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6040 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6041 | ||||
| 6042 | { &hf_ssh_packet_length, | |||
| 6043 | { "Packet Length", "ssh.packet_length", | |||
| 6044 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6045 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6046 | ||||
| 6047 | { &hf_ssh_packet_length_encrypted, | |||
| 6048 | { "Packet Length (encrypted)", "ssh.packet_length_encrypted", | |||
| 6049 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6050 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6051 | ||||
| 6052 | { &hf_ssh_padding_length, | |||
| 6053 | { "Padding Length", "ssh.padding_length", | |||
| 6054 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6055 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6056 | ||||
| 6057 | { &hf_ssh_payload, | |||
| 6058 | { "Payload", "ssh.payload", | |||
| 6059 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6060 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6061 | ||||
| 6062 | { &hf_ssh_encrypted_packet, | |||
| 6063 | { "Encrypted Packet", "ssh.encrypted_packet", | |||
| 6064 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6065 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6066 | ||||
| 6067 | { &hf_ssh_padding_string, | |||
| 6068 | { "Padding String", "ssh.padding_string", | |||
| 6069 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6070 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6071 | ||||
| 6072 | { &hf_ssh_seq_num, | |||
| 6073 | { "Sequence number", "ssh.seq_num", | |||
| 6074 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6075 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6076 | ||||
| 6077 | { &hf_ssh_mac_string, | |||
| 6078 | { "MAC", "ssh.mac", | |||
| 6079 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6080 | "Message authentication code", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6081 | ||||
| 6082 | { &hf_ssh_mac_status, | |||
| 6083 | { "MAC Status", "ssh.mac.status", FT_UINT8, BASE_NONE, VALS(proto_checksum_vals)((0 ? (const struct _value_string*)0 : ((proto_checksum_vals) ))), 0x0, | |||
| 6084 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6085 | ||||
| 6086 | { &hf_ssh_direction, | |||
| 6087 | { "Direction", "ssh.direction", | |||
| 6088 | FT_BOOLEAN, BASE_NONE, TFS(&tfs_s2c_c2s)((0 ? (const struct true_false_string*)0 : ((&tfs_s2c_c2s )))), 0x0, | |||
| 6089 | "Message direction", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6090 | ||||
| 6091 | { &hf_ssh_msg_code, | |||
| 6092 | { "Message Code", "ssh.message_code", | |||
| 6093 | FT_UINT8, BASE_DEC, VALS(ssh1_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh1_msg_vals)))), 0x0, | |||
| 6094 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6095 | ||||
| 6096 | { &hf_ssh2_msg_code, | |||
| 6097 | { "Message Code", "ssh.message_code", | |||
| 6098 | FT_UINT8, BASE_DEC, VALS(ssh2_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_msg_vals)))), 0x0, | |||
| 6099 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6100 | ||||
| 6101 | { &hf_ssh2_kex_dh_msg_code, | |||
| 6102 | { "Message Code", "ssh.message_code", | |||
| 6103 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_dh_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_dh_msg_vals )))), 0x0, | |||
| 6104 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6105 | ||||
| 6106 | { &hf_ssh2_kex_dh_gex_msg_code, | |||
| 6107 | { "Message Code", "ssh.message_code", | |||
| 6108 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_dh_gex_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_dh_gex_msg_vals )))), 0x0, | |||
| 6109 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6110 | ||||
| 6111 | { &hf_ssh2_kex_ecdh_msg_code, | |||
| 6112 | { "Message Code", "ssh.message_code", | |||
| 6113 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_ecdh_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_ecdh_msg_vals )))), 0x0, | |||
| 6114 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6115 | ||||
| 6116 | { &hf_ssh2_kex_hybrid_msg_code, | |||
| 6117 | { "Message Code", "ssh.message_code", | |||
| 6118 | FT_UINT8, BASE_DEC, VALS(ssh2_kex_hybrid_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_kex_hybrid_msg_vals )))), 0x0, | |||
| 6119 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6120 | ||||
| 6121 | { &hf_ssh2_ext_ping_msg_code, | |||
| 6122 | { "Message Code", "ssh.message_code", | |||
| 6123 | FT_UINT8, BASE_DEC, VALS(ssh2_ext_ping_msg_vals)((0 ? (const struct _value_string*)0 : ((ssh2_ext_ping_msg_vals )))), 0x0, | |||
| 6124 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6125 | ||||
| 6126 | { &hf_ssh_cookie, | |||
| 6127 | { "Cookie", "ssh.cookie", | |||
| 6128 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6129 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6130 | ||||
| 6131 | { &hf_ssh_kex_algorithms, | |||
| 6132 | { "kex_algorithms string", "ssh.kex_algorithms", | |||
| 6133 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6134 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6135 | ||||
| 6136 | { &hf_ssh_server_host_key_algorithms, | |||
| 6137 | { "server_host_key_algorithms string", "ssh.server_host_key_algorithms", | |||
| 6138 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6139 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6140 | ||||
| 6141 | { &hf_ssh_encryption_algorithms_client_to_server, | |||
| 6142 | { "encryption_algorithms_client_to_server string", "ssh.encryption_algorithms_client_to_server", | |||
| 6143 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6144 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6145 | ||||
| 6146 | { &hf_ssh_encryption_algorithms_server_to_client, | |||
| 6147 | { "encryption_algorithms_server_to_client string", "ssh.encryption_algorithms_server_to_client", | |||
| 6148 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6149 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6150 | ||||
| 6151 | { &hf_ssh_mac_algorithms_client_to_server, | |||
| 6152 | { "mac_algorithms_client_to_server string", "ssh.mac_algorithms_client_to_server", | |||
| 6153 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6154 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6155 | ||||
| 6156 | { &hf_ssh_mac_algorithms_server_to_client, | |||
| 6157 | { "mac_algorithms_server_to_client string", "ssh.mac_algorithms_server_to_client", | |||
| 6158 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6159 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6160 | ||||
| 6161 | { &hf_ssh_compression_algorithms_client_to_server, | |||
| 6162 | { "compression_algorithms_client_to_server string", "ssh.compression_algorithms_client_to_server", | |||
| 6163 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6164 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6165 | ||||
| 6166 | { &hf_ssh_compression_algorithms_server_to_client, | |||
| 6167 | { "compression_algorithms_server_to_client string", "ssh.compression_algorithms_server_to_client", | |||
| 6168 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6169 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6170 | ||||
| 6171 | { &hf_ssh_languages_client_to_server, | |||
| 6172 | { "languages_client_to_server string", "ssh.languages_client_to_server", | |||
| 6173 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6174 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6175 | ||||
| 6176 | { &hf_ssh_languages_server_to_client, | |||
| 6177 | { "languages_server_to_client string", "ssh.languages_server_to_client", | |||
| 6178 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6179 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6180 | ||||
| 6181 | { &hf_ssh_kex_algorithms_length, | |||
| 6182 | { "kex_algorithms length", "ssh.kex_algorithms_length", | |||
| 6183 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6184 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6185 | ||||
| 6186 | { &hf_ssh_server_host_key_algorithms_length, | |||
| 6187 | { "server_host_key_algorithms length", "ssh.server_host_key_algorithms_length", | |||
| 6188 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6189 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6190 | ||||
| 6191 | { &hf_ssh_encryption_algorithms_client_to_server_length, | |||
| 6192 | { "encryption_algorithms_client_to_server length", "ssh.encryption_algorithms_client_to_server_length", | |||
| 6193 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6194 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6195 | ||||
| 6196 | { &hf_ssh_encryption_algorithms_server_to_client_length, | |||
| 6197 | { "encryption_algorithms_server_to_client length", "ssh.encryption_algorithms_server_to_client_length", | |||
| 6198 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6199 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6200 | ||||
| 6201 | { &hf_ssh_mac_algorithms_client_to_server_length, | |||
| 6202 | { "mac_algorithms_client_to_server length", "ssh.mac_algorithms_client_to_server_length", | |||
| 6203 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6204 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6205 | ||||
| 6206 | { &hf_ssh_mac_algorithms_server_to_client_length, | |||
| 6207 | { "mac_algorithms_server_to_client length", "ssh.mac_algorithms_server_to_client_length", | |||
| 6208 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6209 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6210 | ||||
| 6211 | { &hf_ssh_compression_algorithms_client_to_server_length, | |||
| 6212 | { "compression_algorithms_client_to_server length", "ssh.compression_algorithms_client_to_server_length", | |||
| 6213 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6214 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6215 | ||||
| 6216 | { &hf_ssh_compression_algorithms_server_to_client_length, | |||
| 6217 | { "compression_algorithms_server_to_client length", "ssh.compression_algorithms_server_to_client_length", | |||
| 6218 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6219 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6220 | ||||
| 6221 | { &hf_ssh_languages_client_to_server_length, | |||
| 6222 | { "languages_client_to_server length", "ssh.languages_client_to_server_length", | |||
| 6223 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6224 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6225 | ||||
| 6226 | { &hf_ssh_languages_server_to_client_length, | |||
| 6227 | { "languages_server_to_client length", "ssh.languages_server_to_client_length", | |||
| 6228 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6229 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6230 | ||||
| 6231 | { &hf_ssh_first_kex_packet_follows, | |||
| 6232 | { "First KEX Packet Follows", "ssh.first_kex_packet_follows", | |||
| 6233 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6234 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6235 | ||||
| 6236 | { &hf_ssh_kex_reserved, | |||
| 6237 | { "Reserved", "ssh.kex.reserved", | |||
| 6238 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6239 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6240 | ||||
| 6241 | { &hf_ssh_kex_hassh_algo, | |||
| 6242 | { "hasshAlgorithms", "ssh.kex.hassh_algorithms", | |||
| 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_kex_hassh, | |||
| 6247 | { "hassh", "ssh.kex.hassh", | |||
| 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_hasshserver_algo, | |||
| 6252 | { "hasshServerAlgorithms", "ssh.kex.hasshserver_algorithms", | |||
| 6253 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6254 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6255 | ||||
| 6256 | { &hf_ssh_kex_hasshserver, | |||
| 6257 | { "hasshServer", "ssh.kex.hasshserver", | |||
| 6258 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6259 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6260 | ||||
| 6261 | { &hf_ssh_hostkey_length, | |||
| 6262 | { "Host key length", "ssh.host_key.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_hostkey_type_length, | |||
| 6267 | { "Host key type length", "ssh.host_key.type_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_hostkey_type, | |||
| 6272 | { "Host key type", "ssh.host_key.type", | |||
| 6273 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6274 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6275 | ||||
| 6276 | { &hf_ssh_hostkey_data, | |||
| 6277 | { "Host key data", "ssh.host_key.data", | |||
| 6278 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6279 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6280 | ||||
| 6281 | { &hf_ssh_hostkey_rsa_n, | |||
| 6282 | { "RSA modulus (N)", "ssh.host_key.rsa.n", | |||
| 6283 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6284 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6285 | ||||
| 6286 | { &hf_ssh_hostkey_rsa_e, | |||
| 6287 | { "RSA public exponent (e)", "ssh.host_key.rsa.e", | |||
| 6288 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6289 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6290 | ||||
| 6291 | { &hf_ssh_hostkey_dsa_p, | |||
| 6292 | { "DSA prime modulus (p)", "ssh.host_key.dsa.p", | |||
| 6293 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6294 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6295 | ||||
| 6296 | { &hf_ssh_hostkey_dsa_q, | |||
| 6297 | { "DSA prime divisor (q)", "ssh.host_key.dsa.q", | |||
| 6298 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6299 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6300 | ||||
| 6301 | { &hf_ssh_hostkey_dsa_g, | |||
| 6302 | { "DSA subgroup generator (g)", "ssh.host_key.dsa.g", | |||
| 6303 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6304 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6305 | ||||
| 6306 | { &hf_ssh_hostkey_dsa_y, | |||
| 6307 | { "DSA public key (y)", "ssh.host_key.dsa.y", | |||
| 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_hostkey_ecdsa_curve_id, | |||
| 6312 | { "ECDSA elliptic curve identifier", "ssh.host_key.ecdsa.id", | |||
| 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_hostkey_ecdsa_curve_id_length, | |||
| 6317 | { "ECDSA elliptic curve identifier length", "ssh.host_key.ecdsa.id_length", | |||
| 6318 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6319 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6320 | ||||
| 6321 | { &hf_ssh_hostkey_ecdsa_q, | |||
| 6322 | { "ECDSA public key (Q)", "ssh.host_key.ecdsa.q", | |||
| 6323 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6324 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6325 | ||||
| 6326 | { &hf_ssh_hostkey_ecdsa_q_length, | |||
| 6327 | { "ECDSA public key length", "ssh.host_key.ecdsa.q_length", | |||
| 6328 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6329 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6330 | ||||
| 6331 | { &hf_ssh_hostkey_eddsa_key, | |||
| 6332 | { "EdDSA public key", "ssh.host_key.eddsa.key", | |||
| 6333 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6334 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6335 | ||||
| 6336 | { &hf_ssh_hostkey_eddsa_key_length, | |||
| 6337 | { "EdDSA public key length", "ssh.host_key.eddsa.key_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_hostsig_length, | |||
| 6342 | { "Host signature length", "ssh.host_sig.length", | |||
| 6343 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6344 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6345 | ||||
| 6346 | { &hf_ssh_hostsig_type_length, | |||
| 6347 | { "Host signature type length", "ssh.host_sig.type_length", | |||
| 6348 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6349 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6350 | ||||
| 6351 | { &hf_ssh_hostsig_type, | |||
| 6352 | { "Host signature type", "ssh.host_sig.type", | |||
| 6353 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6354 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6355 | ||||
| 6356 | { &hf_ssh_hostsig_data, | |||
| 6357 | { "Host signature data", "ssh.host_sig.data", | |||
| 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_hostsig_rsa, | |||
| 6362 | { "RSA signature", "ssh.host_sig.rsa", | |||
| 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_hostsig_dsa, | |||
| 6367 | { "DSA signature", "ssh.host_sig.dsa", | |||
| 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_dh_e, | |||
| 6372 | { "DH client e", "ssh.dh.e", | |||
| 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_dh_f, | |||
| 6377 | { "DH server f", "ssh.dh.f", | |||
| 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_dh_gex_min, | |||
| 6382 | { "DH GEX Min", "ssh.dh_gex.min", | |||
| 6383 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6384 | "Minimal acceptable group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6385 | ||||
| 6386 | { &hf_ssh_dh_gex_nbits, | |||
| 6387 | { "DH GEX Number of Bits", "ssh.dh_gex.nbits", | |||
| 6388 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6389 | "Preferred group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6390 | ||||
| 6391 | { &hf_ssh_dh_gex_max, | |||
| 6392 | { "DH GEX Max", "ssh.dh_gex.max", | |||
| 6393 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6394 | "Maximal acceptable group size", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6395 | ||||
| 6396 | { &hf_ssh_dh_gex_p, | |||
| 6397 | { "DH GEX modulus (P)", "ssh.dh_gex.p", | |||
| 6398 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6399 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6400 | ||||
| 6401 | { &hf_ssh_dh_gex_g, | |||
| 6402 | { "DH GEX base (G)", "ssh.dh_gex.g", | |||
| 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_ecdh_q_c, | |||
| 6407 | { "ECDH client's ephemeral public key (Q_C)", "ssh.ecdh.q_c", | |||
| 6408 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6409 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6410 | ||||
| 6411 | { &hf_ssh_ecdh_q_c_length, | |||
| 6412 | { "ECDH client's ephemeral public key length", "ssh.ecdh.q_c_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_ecdh_q_s, | |||
| 6417 | { "ECDH server's ephemeral public key (Q_S)", "ssh.ecdh.q_s", | |||
| 6418 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6419 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6420 | ||||
| 6421 | { &hf_ssh_ecdh_q_s_length, | |||
| 6422 | { "ECDH server's ephemeral public key length", "ssh.ecdh.q_s_length", | |||
| 6423 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6424 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6425 | ||||
| 6426 | { &hf_ssh_mpint_length, | |||
| 6427 | { "Multi Precision Integer Length", "ssh.mpint_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_ignore_data_length, | |||
| 6432 | { "Debug message length", "ssh.ignore_data_length", | |||
| 6433 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6434 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6435 | ||||
| 6436 | { &hf_ssh_ignore_data, | |||
| 6437 | { "Ignore data", "ssh.ignore_data", | |||
| 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_debug_always_display, | |||
| 6442 | { "Always Display", "ssh.debug_always_display", | |||
| 6443 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6444 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6445 | ||||
| 6446 | { &hf_ssh_debug_message_length, | |||
| 6447 | { "Debug message length", "ssh.debug_name_length", | |||
| 6448 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6449 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6450 | ||||
| 6451 | { &hf_ssh_debug_message, | |||
| 6452 | { "Debug message", "ssh.debug_name", | |||
| 6453 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6454 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6455 | ||||
| 6456 | { &hf_ssh_service_name_length, | |||
| 6457 | { "Service Name length", "ssh.service_name_length", | |||
| 6458 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6459 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6460 | ||||
| 6461 | { &hf_ssh_service_name, | |||
| 6462 | { "Service Name", "ssh.service_name", | |||
| 6463 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6464 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6465 | ||||
| 6466 | { &hf_ssh_disconnect_reason, | |||
| 6467 | { "Disconnect reason", "ssh.disconnect_reason", | |||
| 6468 | FT_UINT32, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6469 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6470 | ||||
| 6471 | { &hf_ssh_disconnect_description_length, | |||
| 6472 | { "Disconnect description length", "ssh.disconnect_description_length", | |||
| 6473 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6474 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6475 | ||||
| 6476 | { &hf_ssh_disconnect_description, | |||
| 6477 | { "Disconnect description", "ssh.disconnect_description", | |||
| 6478 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6479 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6480 | ||||
| 6481 | { &hf_ssh_ext_count, | |||
| 6482 | { "Extension count", "ssh.extension.count", | |||
| 6483 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6484 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6485 | ||||
| 6486 | { &hf_ssh_ext_name_length, | |||
| 6487 | { "Extension name length", "ssh.extension.name_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_ext_name, | |||
| 6492 | { "Extension name", "ssh.extension.name", | |||
| 6493 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6494 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6495 | ||||
| 6496 | { &hf_ssh_ext_value_length, | |||
| 6497 | { "Extension value length", "ssh.extension.value_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_ext_value, | |||
| 6502 | { "Extension value", "ssh.extension.value", | |||
| 6503 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6504 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6505 | ||||
| 6506 | { &hf_ssh_ext_server_sig_algs_algorithms, | |||
| 6507 | { "Accepted signature algorithms", "ssh.extension.server_sig_algs.algorithms", | |||
| 6508 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6509 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6510 | ||||
| 6511 | { &hf_ssh_ext_delay_compression_algorithms_client_to_server_length, | |||
| 6512 | { "Compression algorithms (client to server) length", "ssh.extension.delay_compression.compression_algorithms_client_to_server_length", | |||
| 6513 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6514 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6515 | ||||
| 6516 | { &hf_ssh_ext_delay_compression_algorithms_client_to_server, | |||
| 6517 | { "Compression algorithms (client to server)", "ssh.extension.delay_compression.compression_algorithms_client_to_server", | |||
| 6518 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6519 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6520 | ||||
| 6521 | { &hf_ssh_ext_delay_compression_algorithms_server_to_client_length, | |||
| 6522 | { "Compression algorithms (server to client) length", "ssh.extension.delay_compression.compression_algorithms_server_to_client_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_ext_delay_compression_algorithms_server_to_client, | |||
| 6527 | { "Compression algorithms (server to client)", "ssh.extension.delay_compression.compression_algorithms_server_to_client", | |||
| 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_ext_no_flow_control_value, | |||
| 6532 | { "No flow control flag", "ssh.extension.no_flow_control.value", | |||
| 6533 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6534 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6535 | ||||
| 6536 | { &hf_ssh_ext_elevation_value, | |||
| 6537 | { "Elevation flag", "ssh.extension.elevation.value", | |||
| 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_ext_prop_publickey_algorithms_algorithms, | |||
| 6542 | { "Public key algorithms", "ssh.extension.prop_publickey_algorithms.algorithms", | |||
| 6543 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6544 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6545 | ||||
| 6546 | { &hf_ssh_lang_tag_length, | |||
| 6547 | { "Language tag length", "ssh.lang_tag_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_lang_tag, | |||
| 6552 | { "Language tag", "ssh.lang_tag", | |||
| 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_ping_data_length, | |||
| 6557 | { "Data length", "ssh.ping_data_length", | |||
| 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_ping_data, | |||
| 6562 | { "Data", "ssh.ping_data", | |||
| 6563 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6564 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6565 | ||||
| 6566 | { &hf_ssh_pong_data_length, | |||
| 6567 | { "Data length", "ssh.pong_data_length", | |||
| 6568 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6569 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6570 | ||||
| 6571 | { &hf_ssh_pong_data, | |||
| 6572 | { "Data", "ssh.pong_data", | |||
| 6573 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6574 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6575 | ||||
| 6576 | ||||
| 6577 | { &hf_ssh_userauth_user_name_length, | |||
| 6578 | { "User Name length", "ssh.userauth_user_name_length", | |||
| 6579 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6580 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6581 | ||||
| 6582 | { &hf_ssh_userauth_user_name, | |||
| 6583 | { "User Name", "ssh.userauth_user_name", | |||
| 6584 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6585 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6586 | ||||
| 6587 | { &hf_ssh_userauth_change_password, | |||
| 6588 | { "Change password", "ssh.userauth.change_password", | |||
| 6589 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6590 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6591 | ||||
| 6592 | { &hf_ssh_userauth_service_name_length, | |||
| 6593 | { "Service Name length", "ssh.userauth_service_name_length", | |||
| 6594 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6595 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6596 | ||||
| 6597 | { &hf_ssh_userauth_service_name, | |||
| 6598 | { "Service Name", "ssh.userauth_service_name", | |||
| 6599 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6600 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6601 | ||||
| 6602 | { &hf_ssh_userauth_method_name_length, | |||
| 6603 | { "Method Name length", "ssh.userauth_method_name_length", | |||
| 6604 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6605 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6606 | ||||
| 6607 | { &hf_ssh_userauth_method_name, | |||
| 6608 | { "Method Name", "ssh.userauth_method_name", | |||
| 6609 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6610 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6611 | ||||
| 6612 | { &hf_ssh_userauth_have_signature, | |||
| 6613 | { "Have signature", "ssh.userauth.have_signature", | |||
| 6614 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6615 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6616 | ||||
| 6617 | { &hf_ssh_userauth_password_length, | |||
| 6618 | { "Password length", "ssh.userauth_password_length", | |||
| 6619 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6620 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6621 | ||||
| 6622 | { &hf_ssh_userauth_password, | |||
| 6623 | { "Password", "ssh.userauth_password", | |||
| 6624 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6625 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6626 | ||||
| 6627 | { &hf_ssh_userauth_new_password_length, | |||
| 6628 | { "New password length", "ssh.userauth_new_password_length", | |||
| 6629 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6630 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6631 | ||||
| 6632 | { &hf_ssh_userauth_new_password, | |||
| 6633 | { "New password", "ssh.userauth_new_password", | |||
| 6634 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6635 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6636 | ||||
| 6637 | { &hf_ssh_auth_failure_list_length, | |||
| 6638 | { "Authentications that can continue list len", "ssh.auth_failure_cont_list_length", | |||
| 6639 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6640 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6641 | ||||
| 6642 | { &hf_ssh_auth_failure_list, | |||
| 6643 | { "Authentications that can continue list", "ssh.auth_failure_cont_list", | |||
| 6644 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6645 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6646 | ||||
| 6647 | { &hf_ssh_userauth_partial_success, | |||
| 6648 | { "Partial success", "ssh.userauth.partial_success", | |||
| 6649 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6650 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6651 | ||||
| 6652 | { &hf_ssh_userauth_pka_name_len, | |||
| 6653 | { "Public key algorithm name length", "ssh.userauth_pka_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_pka_name, | |||
| 6658 | { "Public key algorithm name", "ssh.userauth_pka_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_pk_blob_name_length, | |||
| 6663 | { "Public key blob algorithm name length", "ssh.pk_blob_name_length", | |||
| 6664 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6665 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6666 | ||||
| 6667 | { &hf_ssh_pk_blob_name, | |||
| 6668 | { "Public key blob algorithm name", "ssh.pk_blob_name", | |||
| 6669 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6670 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6671 | ||||
| 6672 | { &hf_ssh_blob_length, | |||
| 6673 | { "Public key blob length", "ssh.pk_blob_length", | |||
| 6674 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6675 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6676 | ||||
| 6677 | { &hf_ssh_blob, | |||
| 6678 | { "Public key blob", "ssh.pk_blob", | |||
| 6679 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6680 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6681 | ||||
| 6682 | { &hf_ssh_blob_e, | |||
| 6683 | { "ssh-rsa public exponent (e)", "ssh.pk_blob.ssh-rsa.e", | |||
| 6684 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6685 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6686 | ||||
| 6687 | { &hf_ssh_blob_n, | |||
| 6688 | { "ssh-rsa modulus (n)", "ssh.pk_blob.ssh-rsa.n", | |||
| 6689 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6690 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6691 | ||||
| 6692 | { &hf_ssh_blob_dsa_p, | |||
| 6693 | { "DSA prime modulus (p)", "ssh.pk_blob.dsa.p", | |||
| 6694 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6695 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6696 | ||||
| 6697 | { &hf_ssh_blob_dsa_q, | |||
| 6698 | { "DSA prime divisor (q)", "ssh.pk_blob.dsa.q", | |||
| 6699 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6700 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6701 | ||||
| 6702 | { &hf_ssh_blob_dsa_g, | |||
| 6703 | { "DSA subgroup generator (g)", "ssh.pk_blob.dsa.g", | |||
| 6704 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6705 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6706 | ||||
| 6707 | { &hf_ssh_blob_dsa_y, | |||
| 6708 | { "DSA public key (y)", "ssh.pk_blob.dsa.y", | |||
| 6709 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6710 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6711 | ||||
| 6712 | { &hf_ssh_blob_ecdsa_curve_id, | |||
| 6713 | { "ECDSA elliptic curve identifier", "ssh.pk_blob.ecdsa.id", | |||
| 6714 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6715 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6716 | ||||
| 6717 | { &hf_ssh_blob_ecdsa_curve_id_length, | |||
| 6718 | { "ECDSA elliptic curve identifier length", "ssh.pk_blob.ecdsa.id_length", | |||
| 6719 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6720 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6721 | ||||
| 6722 | { &hf_ssh_blob_ecdsa_q, | |||
| 6723 | { "ECDSA public key (Q)", "ssh.pk_blob.ecdsa.q", | |||
| 6724 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6725 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6726 | ||||
| 6727 | { &hf_ssh_blob_ecdsa_q_length, | |||
| 6728 | { "ECDSA public key length", "ssh.pk_blob.ecdsa.q_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_blob_eddsa_key, | |||
| 6733 | { "EdDSA public key", "ssh.pk_blob.eddsa.key", | |||
| 6734 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6735 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6736 | ||||
| 6737 | { &hf_ssh_blob_eddsa_key_length, | |||
| 6738 | { "EdDSA public key length", "ssh.pk_blob.eddsa.key_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_blob_data, | |||
| 6743 | { "Public key blob data", "ssh.pk_blob.data", | |||
| 6744 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6745 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6746 | ||||
| 6747 | { &hf_ssh_signature_length, | |||
| 6748 | { "Public key signature blob length", "ssh.pk_sig_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_pk_sig_blob_name_length, | |||
| 6753 | { "Public key signature blob algorithm name length", "ssh.pk_sig_blob_name_length", | |||
| 6754 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6755 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6756 | ||||
| 6757 | { &hf_ssh_pk_sig_blob_name, | |||
| 6758 | { "Public key signature blob algorithm name", "ssh.pk_sig_blob_name", | |||
| 6759 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6760 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6761 | ||||
| 6762 | { &hf_ssh_pk_sig_s_length, | |||
| 6763 | { "ssh-rsa signature length", "ssh.sig.ssh-rsa.length", | |||
| 6764 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6765 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6766 | ||||
| 6767 | { &hf_ssh_pk_sig_s, | |||
| 6768 | { "ssh-rsa signature (s)", "ssh.sig.ssh-rsa.s", | |||
| 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_connection_type_name_len, | |||
| 6773 | { "Channel type name length", "ssh.connection_type_name_length", | |||
| 6774 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6775 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6776 | ||||
| 6777 | { &hf_ssh_connection_type_name, | |||
| 6778 | { "Channel type name", "ssh.connection_type_name", | |||
| 6779 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6780 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6781 | ||||
| 6782 | { &hf_ssh_connection_sender_channel, | |||
| 6783 | { "Sender channel", "ssh.connection_sender_channel", | |||
| 6784 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6785 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6786 | ||||
| 6787 | { &hf_ssh_connection_recipient_channel, | |||
| 6788 | { "Recipient channel", "ssh.connection_recipient_channel", | |||
| 6789 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6790 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6791 | ||||
| 6792 | { &hf_ssh_connection_initial_window, | |||
| 6793 | { "Initial window size", "ssh.connection_initial_window_size", | |||
| 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_connection_maximum_packet_size, | |||
| 6798 | { "Maximum packet size", "ssh.userauth_maximum_packet_size", | |||
| 6799 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6800 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6801 | ||||
| 6802 | { &hf_ssh_global_request_name_len, | |||
| 6803 | { "Global request name length", "ssh.global_request_name_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_global_request_name, | |||
| 6808 | { "Global request name", "ssh.global_request_name", | |||
| 6809 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6810 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6811 | ||||
| 6812 | { &hf_ssh_global_request_want_reply, | |||
| 6813 | { "Global request want reply", "ssh.global_request_want_reply", | |||
| 6814 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6815 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6816 | ||||
| 6817 | { &hf_ssh_global_request_hostkeys_array_len, | |||
| 6818 | { "Host keys array length", "ssh.global_request_hostkeys", | |||
| 6819 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6820 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6821 | ||||
| 6822 | { &hf_ssh_channel_request_name_len, | |||
| 6823 | { "Channel request name length", "ssh.channel_request_name_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_channel_request_name, | |||
| 6828 | { "Channel request name", "ssh.channel_request_name", | |||
| 6829 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6830 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6831 | ||||
| 6832 | { &hf_ssh_channel_request_want_reply, | |||
| 6833 | { "Channel request want reply", "ssh.channel_request_want_reply", | |||
| 6834 | FT_UINT8, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6835 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6836 | ||||
| 6837 | { &hf_ssh_subsystem_name_len, | |||
| 6838 | { "Subsystem name length", "ssh.subsystem_name_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_subsystem_name, | |||
| 6843 | { "Subsystem name", "ssh.subsystem_name", | |||
| 6844 | FT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6845 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 6846 | ||||
| 6847 | { &hf_ssh_exec_cmd, | |||
| 6848 | { "Command", "ssh.exec_command", | |||
| 6849 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6850 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6851 | ||||
| 6852 | { &hf_ssh_env_name, | |||
| 6853 | { "Variable name", "ssh.env_name", | |||
| 6854 | FT_UINT_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_env_value, | |||
| 6858 | { "Variable value", "ssh.env_value", | |||
| 6859 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6860 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6861 | ||||
| 6862 | { &hf_ssh_pty_term, | |||
| 6863 | { "TERM environment variable", "ssh.pty_term", | |||
| 6864 | FT_UINT_STRING, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6865 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6866 | ||||
| 6867 | { &hf_ssh_pty_term_width_char, | |||
| 6868 | { "Terminal width, characters", "ssh.pty_term_width_char", | |||
| 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_pty_term_height_row, | |||
| 6873 | { "Terminal height, rows", "ssh.pty_term_height_row", | |||
| 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_pty_term_width_pixel, | |||
| 6878 | { "Terminal width, pixels", "ssh.pty_term_width_pixel", | |||
| 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_pty_term_height_pixel, | |||
| 6883 | { "Terminal height, pixels", "ssh.pty_term_height_pixel", | |||
| 6884 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6885 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6886 | ||||
| 6887 | { &hf_ssh_pty_term_modes_len, | |||
| 6888 | { "Encoded Terminal Modes Length", "ssh.pty_term_modes_length", | |||
| 6889 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 6890 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6891 | ||||
| 6892 | { &hf_ssh_pty_term_modes, | |||
| 6893 | { "Encoded Terminal Modes", "ssh.pty_term_modes", | |||
| 6894 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6895 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6896 | ||||
| 6897 | { &hf_ssh_pty_term_mode, | |||
| 6898 | { "Mode", "ssh.pty_term_mode", | |||
| 6899 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0, | |||
| 6900 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6901 | ||||
| 6902 | { &hf_ssh_pty_term_mode_opcode, | |||
| 6903 | { "Opcode", "ssh.pty_term_mode.opcode", | |||
| 6904 | FT_UINT8, BASE_DEC, VALS(ssh_tty_op_vals)((0 ? (const struct _value_string*)0 : ((ssh_tty_op_vals)))), 0x0, | |||
| 6905 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6906 | ||||
| 6907 | { &hf_ssh_pty_term_mode_vintr, | |||
| 6908 | { "Interrupt character", "ssh.pty_term_mode.vintr", | |||
| 6909 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6910 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 6911 | ||||
| 6912 | { &hf_ssh_pty_term_mode_vquit, | |||
| 6913 | { "Quit character", "ssh.pty_term_mode.vquit", | |||
| 6914 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6915 | "Sends SIGQUIT on POSIX systems", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}}, | |||
| 6916 | ||||
| 6917 | { &hf_ssh_pty_term_mode_verase, | |||
| 6918 | { "Erase the character to the left of the cursor", "ssh.pty_term_mode.verase", | |||
| 6919 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6920 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6921 | ||||
| 6922 | { &hf_ssh_pty_term_mode_vkill, | |||
| 6923 | { "Kill the current input line", "ssh.pty_term_mode.vkill", | |||
| 6924 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6925 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6926 | ||||
| 6927 | { &hf_ssh_pty_term_mode_veof, | |||
| 6928 | { "End-of-file character", "ssh.pty_term_mode.veof", | |||
| 6929 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6930 | "Sends EOF from the terminal", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}}, | |||
| 6931 | ||||
| 6932 | { &hf_ssh_pty_term_mode_veol, | |||
| 6933 | { "End-of-line character", "ssh.pty_term_mode.veol", | |||
| 6934 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6935 | "In additional to carriage return and/or line feed", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6936 | ||||
| 6937 | { &hf_ssh_pty_term_mode_veol2, | |||
| 6938 | { "Additional end-of-line character", "ssh.pty_term_mode.veol2", | |||
| 6939 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6940 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6941 | ||||
| 6942 | { &hf_ssh_pty_term_mode_vstart, | |||
| 6943 | { "Continues paused output", "ssh.pty_term_mode.vstart", | |||
| 6944 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6945 | "Normally Control-Q", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}}, | |||
| 6946 | ||||
| 6947 | { &hf_ssh_pty_term_mode_vstop, | |||
| 6948 | { "Pauses output", "ssh.pty_term_mode.vstop", | |||
| 6949 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6950 | "Normally Control-S", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6951 | ||||
| 6952 | { &hf_ssh_pty_term_mode_vsusp, | |||
| 6953 | { "Suspends the current program", "ssh.pty_term_mode.vsusp", | |||
| 6954 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6955 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6956 | ||||
| 6957 | { &hf_ssh_pty_term_mode_vdsusp, | |||
| 6958 | { "Another suspend character", "ssh.pty_term_mode.vdsusp", | |||
| 6959 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6960 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6961 | ||||
| 6962 | { &hf_ssh_pty_term_mode_vreprint, | |||
| 6963 | { "Reprints the current input line", "ssh.pty_term_mode.vreprint", | |||
| 6964 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6965 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6966 | ||||
| 6967 | { &hf_ssh_pty_term_mode_vwerase, | |||
| 6968 | { "Erase a word to the left of the cursor", "ssh.pty_term_mode.vwerase", | |||
| 6969 | FT_CHAR, BASE_HEX, 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_vlnext, | |||
| 6973 | { "Enter the next character typed literally", "ssh.pty_term_mode.vlnext", | |||
| 6974 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6975 | "Even if a special character", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6976 | ||||
| 6977 | { &hf_ssh_pty_term_mode_vflush, | |||
| 6978 | { "Character to flush output", "ssh.pty_term_mode.vflush", | |||
| 6979 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6980 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)} }, | |||
| 6981 | ||||
| 6982 | { &hf_ssh_pty_term_mode_vswtch, | |||
| 6983 | { "Switch to a different shell layer", "ssh.pty_term_mode.vswtch", | |||
| 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_vstatus, | |||
| 6988 | { "Print system status line", "ssh.pty_term_mode.vstatus", | |||
| 6989 | FT_CHAR, BASE_HEX, NULL((void*)0), 0x0, | |||
| 6990 | "Load, command, pid, etc.", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0)}}, | |||
| 6991 | ||||
| 6992 | { &hf_ssh_pty_term_mode_vdiscard, | |||
| 6993 | { "Toggles the flushing of terminal output", "ssh.pty_term_mode.vdiscard", | |||
| 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_ignpar, | |||
| 6998 | { "Ignore parity flag", "ssh.pty_term_mode.ignpar", | |||
| 6999 | FT_BOOLEAN, BASE_NONE, 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_parmrk, | |||
| 7003 | { "Mark parity and framing errors", "ssh.pty_term_mode.parmrk", | |||
| 7004 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7005 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7006 | ||||
| 7007 | { &hf_ssh_pty_term_mode_inpck, | |||
| 7008 | { "Enable checking of parity errors", "ssh.pty_term_mode.inpck", | |||
| 7009 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7010 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7011 | ||||
| 7012 | { &hf_ssh_pty_term_mode_istrip, | |||
| 7013 | { "Strip 8th bit off characters", "ssh.pty_term_mode.istrip", | |||
| 7014 | FT_BOOLEAN, BASE_NONE, 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_inlcr, | |||
| 7018 | { "Map NL into CR on input", "ssh.pty_term_mode.inlcr", | |||
| 7019 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7020 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7021 | ||||
| 7022 | { &hf_ssh_pty_term_mode_igncr, | |||
| 7023 | { "Ignore CR on input", "ssh.pty_term_mode.igncr", | |||
| 7024 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7025 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7026 | ||||
| 7027 | { &hf_ssh_pty_term_mode_icrnl, | |||
| 7028 | { "Map CR to NL on input", "ssh.pty_term_mode.icrnl", | |||
| 7029 | FT_BOOLEAN, BASE_NONE, 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_iuclc, | |||
| 7033 | { "Translate uppercase characters to lowercase", "ssh.pty_term_mode.iuclc", | |||
| 7034 | FT_BOOLEAN, BASE_NONE, 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_ixon, | |||
| 7038 | { "Enable output flow control", "ssh.pty_term_mode.ixon", | |||
| 7039 | FT_BOOLEAN, BASE_NONE, 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_ixany, | |||
| 7043 | { "Any char will restart after stop", "ssh.pty_term_mode.ixany", | |||
| 7044 | FT_BOOLEAN, BASE_NONE, 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_ixoff, | |||
| 7048 | { "Enable input flow control", "ssh.pty_term_mode.ixoff", | |||
| 7049 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7050 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7051 | ||||
| 7052 | { &hf_ssh_pty_term_mode_imaxbel, | |||
| 7053 | { "Ring bell on input queue full", "ssh.pty_term_mode.imaxbel", | |||
| 7054 | FT_BOOLEAN, BASE_NONE, 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_iutf8, | |||
| 7058 | { "Terminal input and output is assumed to be encoded in UTF-8", "ssh.pty_term_mode.iutf8", | |||
| 7059 | FT_BOOLEAN, BASE_NONE, 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_isig, | |||
| 7063 | { "Enable signals INTR, QUIT, [D]SUSP", "ssh.pty_term_mode.isig", | |||
| 7064 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7065 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7066 | ||||
| 7067 | { &hf_ssh_pty_term_mode_icanon, | |||
| 7068 | { "Canonicalize input lines", "ssh.pty_term_mode.icanon", | |||
| 7069 | FT_BOOLEAN, BASE_NONE, 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_xcase, | |||
| 7073 | { "Enable input and output of uppercase characters by preceding their lowercase equivalents with '\'", "ssh.pty_term_mode.xcase", | |||
| 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_echo, | |||
| 7078 | { "Enable echoing", "ssh.pty_term_mode.echo", | |||
| 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_echoe, | |||
| 7083 | { "Visually erase chars", "ssh.pty_term_mode.echoe", | |||
| 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_echok, | |||
| 7088 | { "Kill character discards current line", "ssh.pty_term_mode.echok", | |||
| 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_echonl, | |||
| 7093 | { "Echo NL even if ECHO is off", "ssh.pty_term_mode.echonl", | |||
| 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_noflsh, | |||
| 7098 | { "No flush after interrupt", "ssh.pty_term_mode.noflsh", | |||
| 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_tostop, | |||
| 7103 | { "Stop background jobs from output", "ssh.pty_term_mode.tostop", | |||
| 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_iexten, | |||
| 7108 | { "Enable extensions", "ssh.pty_term_mode.iexten", | |||
| 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_echoctl, | |||
| 7113 | { "Echo control characters as ^(Char)", "ssh.pty_term_mode.echoctl", | |||
| 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_echoke, | |||
| 7118 | { "Visual erase for line kill", "ssh.pty_term_mode.echoke", | |||
| 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_pendin, | |||
| 7123 | { "Retype pending input", "ssh.pty_term_mode.pendin", | |||
| 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_opost, | |||
| 7128 | { "Enable output processing", "ssh.pty_term_mode.opost", | |||
| 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_olcuc, | |||
| 7133 | { "Convert lowercase to uppercase", "ssh.pty_term_mode.olcuc", | |||
| 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_onlcr, | |||
| 7138 | { "Map NL to CR-NL", "ssh.pty_term_mode.onlcr", | |||
| 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_ocrnl, | |||
| 7143 | { "Translate carriage return to newline (output)", "ssh.pty_term_mode.ocrnl", | |||
| 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_onocr, | |||
| 7148 | { "Translate newline to carriage-return newline (output)", "ssh.pty_term_mode.onocr", | |||
| 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_onlret, | |||
| 7153 | { "Newline performs a carriage return (output)", "ssh.pty_term_mode.onlret", | |||
| 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_cs7, | |||
| 7158 | { "7 bit mode", "ssh.pty_term_mode.cs7", | |||
| 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_cs8, | |||
| 7163 | { "8 bit mode", "ssh.pty_term_mode.cs8", | |||
| 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_parenb, | |||
| 7168 | { "Parity enable", "ssh.pty_term_mode.parenb", | |||
| 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_parodd, | |||
| 7173 | { "Odd parity", "ssh.pty_term_mode.parodd", | |||
| 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_ispeed, | |||
| 7178 | { "Input baud rate", "ssh.pty_term_mode.ispeed", | |||
| 7179 | FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_bit_sec)((0 ? (const struct unit_name_string*)0 : ((&units_bit_sec )))), 0x0, | |||
| 7180 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7181 | ||||
| 7182 | { &hf_ssh_pty_term_mode_ospeed, | |||
| 7183 | { "Output baud rate", "ssh.pty_term_mode.ospeed", | |||
| 7184 | FT_UINT32, BASE_DEC|BASE_UNIT_STRING0x00001000, UNS(&units_bit_sec)((0 ? (const struct unit_name_string*)0 : ((&units_bit_sec )))), 0x0, | |||
| 7185 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7186 | ||||
| 7187 | { &hf_ssh_pty_term_mode_value, | |||
| 7188 | { "Value", "ssh.pty_term_mode.value", | |||
| 7189 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 7190 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7191 | ||||
| 7192 | { &hf_ssh_exit_status, | |||
| 7193 | { "Exit status", "ssh.exit_status", | |||
| 7194 | FT_UINT32, BASE_HEX, NULL((void*)0), 0x0, | |||
| 7195 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7196 | ||||
| 7197 | { &hf_ssh_channel_window_adjust, | |||
| 7198 | { "Bytes to add", "ssh.channel_window_adjust", | |||
| 7199 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 7200 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7201 | ||||
| 7202 | { &hf_ssh_channel_data_len, | |||
| 7203 | { "Data length", "ssh.channel_data_length", | |||
| 7204 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 7205 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7206 | ||||
| 7207 | { &hf_ssh_channel_data_type_code, | |||
| 7208 | { "Data Type Code", "ssh.channel_data_type_code", | |||
| 7209 | FT_UINT32, BASE_DEC, VALS(ssh_channel_data_type_code_vals)((0 ? (const struct _value_string*)0 : ((ssh_channel_data_type_code_vals )))), 0x0, | |||
| 7210 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } }, | |||
| 7211 | ||||
| 7212 | { &hf_ssh_reassembled_in, | |||
| 7213 | { "Reassembled PDU in frame", "ssh.reassembled_in", | |||
| 7214 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7215 | "The PDU that doesn't end in this segment is reassembled in this frame", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7216 | ||||
| 7217 | { &hf_ssh_reassembled_length, | |||
| 7218 | { "Reassembled PDU length", "ssh.reassembled.length", | |||
| 7219 | FT_UINT32, BASE_DEC, NULL((void*)0), 0x0, | |||
| 7220 | "The total length of the reassembled payload", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7221 | ||||
| 7222 | { &hf_ssh_reassembled_data, | |||
| 7223 | { "Reassembled PDU data", "ssh.reassembled.data", | |||
| 7224 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, | |||
| 7225 | "The payload of multiple reassembled SSH segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7226 | ||||
| 7227 | { &hf_ssh_segments, | |||
| 7228 | { "Reassembled SSH segments", "ssh.segments", | |||
| 7229 | FT_NONE, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7230 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7231 | ||||
| 7232 | { &hf_ssh_segment, | |||
| 7233 | { "SSH segment", "ssh.segment", | |||
| 7234 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7235 | NULL((void*)0), HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7236 | ||||
| 7237 | { &hf_ssh_segment_overlap, | |||
| 7238 | { "Segment overlap", "ssh.segment.overlap", | |||
| 7239 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7240 | "Segment overlaps with other segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7241 | ||||
| 7242 | { &hf_ssh_segment_overlap_conflict, | |||
| 7243 | { "Conflicting data in segment overlap", "ssh.segment.overlap.conflict", | |||
| 7244 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7245 | "Overlapping segments contained conflicting data", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7246 | ||||
| 7247 | { &hf_ssh_segment_multiple_tails, | |||
| 7248 | { "Multiple tail segments found", "ssh.segment.multipletails", | |||
| 7249 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7250 | "Several tails were found when reassembling the pdu", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7251 | ||||
| 7252 | { &hf_ssh_segment_too_long_fragment, | |||
| 7253 | { "Segment too long", "ssh.segment.toolongfragment", | |||
| 7254 | FT_BOOLEAN, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7255 | "Segment contained data past end of the pdu", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7256 | ||||
| 7257 | { &hf_ssh_segment_error, | |||
| 7258 | { "Reassembling error", "ssh.segment.error", | |||
| 7259 | FT_FRAMENUM, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7260 | "Reassembling error due to illegal segments", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7261 | ||||
| 7262 | { &hf_ssh_segment_count, | |||
| 7263 | { "Segment count", "ssh.segment.count", | |||
| 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_segment_data, | |||
| 7268 | { "SSH segment data", "ssh.segment.data", | |||
| 7269 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x00, | |||
| 7270 | "The payload of a single SSH segment", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) }}, | |||
| 7271 | ||||
| 7272 | { &hf_ssh_hybrid_blob_client, | |||
| 7273 | { "Hybrid Key Exchange Blob Client", "ssh.kex_hybrid_blob_client", | |||
| 7274 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "Client post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 7275 | }, | |||
| 7276 | ||||
| 7277 | { &hf_ssh_hybrid_blob_client_len, | |||
| 7278 | { "Hybrid Key Exchange Blob Client Length", "ssh.kex_hybrid_blob_client_len", | |||
| 7279 | 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) } | |||
| 7280 | }, | |||
| 7281 | ||||
| 7282 | { &hf_ssh_hybrid_blob_server, | |||
| 7283 | { "Hybrid Key Exchange Blob Server", "ssh.kex_hybrid_blob_server", | |||
| 7284 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, "Server post-quantum hybrid blob", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 7285 | }, | |||
| 7286 | ||||
| 7287 | { &hf_ssh_hybrid_blob_server_len, | |||
| 7288 | { "Hybrid Key Exchange Blob Server Length", "ssh.kex_hybrid_blob_server_len", | |||
| 7289 | 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) } | |||
| 7290 | }, | |||
| 7291 | ||||
| 7292 | { &hf_ssh_pq_kem_client, | |||
| 7293 | { "Client PQ KEM Public Key", "ssh.kex.pq_kem_client", | |||
| 7294 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7295 | "Post-quantum key (client)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 7296 | }, | |||
| 7297 | ||||
| 7298 | { &hf_ssh_pq_kem_server, | |||
| 7299 | { "Server PQ KEM Response", "ssh.kex.pq_kem_server", | |||
| 7300 | FT_BYTES, BASE_NONE, NULL((void*)0), 0x0, | |||
| 7301 | "Post-quantum ciphertext (server response)", HFILL-1, 0, HF_REF_TYPE_NONE, -1, ((void*)0) } | |||
| 7302 | }, | |||
| 7303 | ||||
| 7304 | }; | |||
| 7305 | ||||
| 7306 | static int *ett[] = { | |||
| 7307 | &ett_ssh, | |||
| 7308 | &ett_key_exchange, | |||
| 7309 | &ett_key_exchange_host_key, | |||
| 7310 | &ett_key_exchange_host_sig, | |||
| 7311 | &ett_extension, | |||
| 7312 | &ett_userauth_pk_blob, | |||
| 7313 | &ett_userauth_pk_signature, | |||
| 7314 | &ett_term_modes, | |||
| 7315 | &ett_term_mode, | |||
| 7316 | &ett_ssh1, | |||
| 7317 | &ett_ssh2, | |||
| 7318 | &ett_key_init, | |||
| 7319 | &ett_ssh_segments, | |||
| 7320 | &ett_ssh_pqhybrid_client, // added for PQ hybrid CLIENT dissection | |||
| 7321 | &ett_ssh_pqhybrid_server, // added for PQ hybrid SERVER dissection | |||
| 7322 | &ett_ssh_segment | |||
| 7323 | }; | |||
| 7324 | ||||
| 7325 | static ei_register_info ei[] = { | |||
| 7326 | { &ei_ssh_packet_length, { "ssh.packet_length.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid packet length", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7327 | { &ei_ssh_padding_length, { "ssh.padding_length.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Invalid padding length", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7328 | { &ei_ssh_packet_decode, { "ssh.packet_decode.error", PI_UNDECODED0x05000000, PI_WARN0x00600000, "Packet decoded length not equal to packet length", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7329 | { &ei_ssh_channel_number, { "ssh.channel_number.error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Could not find channel", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7330 | { &ei_ssh_invalid_keylen, { "ssh.key_length.error", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Invalid key length", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7331 | { &ei_ssh_mac_bad, { "ssh.mac_bad.expert", PI_CHECKSUM0x01000000, PI_ERROR0x00800000, "Bad MAC", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7332 | { &ei_ssh2_kex_hybrid_msg_code, { "ssh.kex_hybrid_msg_code", PI_SECURITY0x0a000000, PI_NOTE0x00400000, "Hybrid KEX encountered", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7333 | { &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, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}, | |||
| 7334 | ||||
| 7335 | }; | |||
| 7336 | module_t *ssh_module; | |||
| 7337 | expert_module_t *expert_ssh; | |||
| 7338 | ||||
| 7339 | proto_ssh = proto_register_protocol("SSH Protocol", "SSH", "ssh"); | |||
| 7340 | proto_register_field_array(proto_ssh, hf, array_length(hf)(sizeof (hf) / sizeof (hf)[0])); | |||
| 7341 | proto_register_subtree_array(ett, array_length(ett)(sizeof (ett) / sizeof (ett)[0])); | |||
| 7342 | expert_ssh = expert_register_protocol(proto_ssh); | |||
| 7343 | expert_register_field_array(expert_ssh, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0])); | |||
| 7344 | ||||
| 7345 | #ifdef SSH_DECRYPT_DEBUG | |||
| 7346 | ssh_module = prefs_register_protocol(proto_ssh, ssh_prefs_apply_cb); | |||
| 7347 | #else | |||
| 7348 | ssh_module = prefs_register_protocol(proto_ssh, NULL((void*)0)); | |||
| 7349 | #endif | |||
| 7350 | prefs_register_bool_preference(ssh_module, "desegment_buffers", | |||
| 7351 | "Reassemble SSH buffers spanning multiple TCP segments", | |||
| 7352 | "Whether the SSH dissector should reassemble SSH buffers spanning multiple TCP segments. " | |||
| 7353 | "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", | |||
| 7354 | &ssh_desegment); | |||
| 7355 | prefs_register_bool_preference(ssh_module, "ignore_ssh_mac_failed", | |||
| 7356 | "Ignore Message Authentication Code (MAC) failure", | |||
| 7357 | "For troubleshooting purposes, decrypt even if the " | |||
| 7358 | "Message Authentication Code (MAC) check fails.", | |||
| 7359 | &ssh_ignore_mac_failed); | |||
| 7360 | ||||
| 7361 | ssh_master_key_map = g_hash_table_new_full(ssh_hash, ssh_equal, ssh_free_glib_allocated_bignum, ssh_free_glib_allocated_entry); | |||
| 7362 | prefs_register_filename_preference(ssh_module, "keylog_file", "Key log filename", | |||
| 7363 | "The path to the file which contains a list of key exchange secrets in the following format:\n" | |||
| 7364 | "\"<hex-encoded-cookie> <PRIVATE_KEY|SHARED_SECRET> <hex-encoded-key>\" (without quotes or leading spaces).\n", | |||
| 7365 | &pref_keylog_file, false0); | |||
| 7366 | ||||
| 7367 | prefs_register_filename_preference(ssh_module, "debug_file", "SSH debug file", | |||
| 7368 | "Redirect SSH debug to the file specified. Leave empty to disable debugging " | |||
| 7369 | "or use \"" SSH_DEBUG_USE_STDERR"-" "\" to redirect output to stderr.", | |||
| 7370 | &ssh_debug_file_name, true1); | |||
| 7371 | ||||
| 7372 | secrets_register_type(SECRETS_TYPE_SSH0x5353484b, ssh_secrets_block_callback); | |||
| 7373 | ||||
| 7374 | ssh_handle = register_dissector("ssh", dissect_ssh, proto_ssh); | |||
| 7375 | reassembly_table_register(&ssh_reassembly_table, &tcp_reassembly_table_functions); | |||
| 7376 | register_shutdown_routine(ssh_shutdown); | |||
| 7377 | } | |||
| 7378 | ||||
| 7379 | void | |||
| 7380 | proto_reg_handoff_ssh(void) | |||
| 7381 | { | |||
| 7382 | #ifdef SSH_DECRYPT_DEBUG | |||
| 7383 | ssh_set_debug(ssh_debug_file_name); | |||
| 7384 | #endif | |||
| 7385 | dissector_add_uint_range_with_preference("tcp.port", TCP_RANGE_SSH"22", ssh_handle); | |||
| 7386 | dissector_add_uint("sctp.port", SCTP_PORT_SSH22, ssh_handle); | |||
| 7387 | dissector_add_uint("sctp.ppi", SSH_PAYLOAD_PROTOCOL_ID45, ssh_handle); | |||
| 7388 | sftp_handle = find_dissector_add_dependency("sftp", proto_ssh); | |||
| 7389 | data_text_lines_handle = find_dissector_add_dependency("data-text-lines", proto_ssh); | |||
| 7390 | ||||
| 7391 | heur_dissector_add("tcp", dissect_ssh_heur, "SSH over TCP", "ssh_tcp", proto_ssh, HEURISTIC_ENABLE); | |||
| 7392 | } | |||
| 7393 | ||||
| 7394 | /* | |||
| 7395 | * Editor modelines - https://www.wireshark.org/tools/modelines.html | |||
| 7396 | * | |||
| 7397 | * Local variables: | |||
| 7398 | * c-basic-offset: 4 | |||
| 7399 | * tab-width: 8 | |||
| 7400 | * indent-tabs-mode: nil | |||
| 7401 | * End: | |||
| 7402 | * | |||
| 7403 | * vi: set shiftwidth=4 tabstop=8 expandtab: | |||
| 7404 | * :indentSize=4:tabSize=8:noTabs=true: | |||
| 7405 | */ |