2 * Routines for ssh packet dissection
4 * Huagang XIE <huagang@intruvert.com>
5 * Kees Cook <kees@outflux.net>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * Copied from packet-mysql.c
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 * Note: support SSH v1 and v2 now.
43 #include <epan/packet.h>
44 #include <epan/conversation.h>
45 #include <epan/emem.h>
47 #include "packet-tcp.h"
48 #include <epan/reassemble.h>
49 #include <epan/prefs.h>
51 /* get from openssh ssh2.h */
52 #define SSH2_MSG_DISCONNECT 1
53 #define SSH2_MSG_IGNORE 2
54 #define SSH2_MSG_UNIMPLEMENTED 3
55 #define SSH2_MSG_DEBUG 4
56 #define SSH2_MSG_SERVICE_REQUEST 5
57 #define SSH2_MSG_SERVICE_ACCEPT 6
59 /* transport layer: alg negotiation */
61 #define SSH2_MSG_KEXINIT 20
62 #define SSH2_MSG_NEWKEYS 21
64 /* transport layer: kex specific messages, can be reused */
66 #define SSH2_MSG_KEXDH_INIT 30
67 #define SSH2_MSG_KEXDH_REPLY 31
70 #define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
71 #define SSH2_MSG_KEX_DH_GEX_GROUP 31
73 #define SSH2_MSG_KEX_DH_GEX_INIT 32
74 #define SSH2_MSG_KEX_DH_GEX_REPLY 33
75 #define SSH2_MSG_KEX_DH_GEX_REQUEST 34
77 /* SSH Version 1 definition , from openssh ssh1.h */
79 #define SSH_MSG_NONE 0 /* no message */
80 #define SSH_MSG_DISCONNECT 1 /* cause (string) */
81 #define SSH_SMSG_PUBLIC_KEY 2 /* ck,msk,srvk,hostk */
82 #define SSH_CMSG_SESSION_KEY 3 /* key (BIGNUM) */
83 #define SSH_CMSG_USER 4 /* user (string) */
86 #define SSH_VERSION_UNKNOWN 0
87 #define SSH_VERSION_1 1
88 #define SSH_VERSION_2 2
97 struct ssh_flow_data {
102 gchar* mac_client_request;
103 gchar* mac_server_offer;
107 gchar* enc_client_request;
108 gchar* enc_server_offer;
111 gchar* comp_client_request;
112 gchar* comp_server_offer;
116 static int proto_ssh = -1;
117 static int hf_ssh_packet_length= -1;
118 static int hf_ssh_padding_length= -1;
119 static int hf_ssh_payload= -1;
120 static int hf_ssh_protocol= -1;
121 static int hf_ssh_dh_gex_min= -1;
122 static int hf_ssh_dh_gex_nbits= -1;
123 static int hf_ssh_dh_gex_max= -1;
124 static int hf_ssh_encrypted_packet= -1;
125 static int hf_ssh_padding_string= -1;
126 static int hf_ssh_mac_string= -1;
127 static int hf_ssh_msg_code = -1;
128 static int hf_ssh_cookie = -1;
129 static int hf_ssh_mpint_g= -1;
130 static int hf_ssh_mpint_p= -1;
131 static int hf_ssh_mpint_e= -1;
132 static int hf_ssh_mpint_f= -1;
133 static int hf_ssh_mpint_length= -1;
134 static int hf_ssh_kexdh_host_key= -1;
135 static int hf_ssh_kexdh_host_key_length= -1;
136 static int hf_ssh_kexdh_h_sig= -1;
137 static int hf_ssh_kexdh_h_sig_length= -1;
138 static int hf_ssh_kex_algorithms = -1;
139 static int hf_ssh_server_host_key_algorithms = -1;
140 static int hf_ssh_encryption_algorithms_client_to_server = -1;
141 static int hf_ssh_encryption_algorithms_server_to_client = -1;
142 static int hf_ssh_mac_algorithms_client_to_server=-1;
143 static int hf_ssh_mac_algorithms_server_to_client=-1;
144 static int hf_ssh_compression_algorithms_client_to_server=-1;
145 static int hf_ssh_compression_algorithms_server_to_client=-1;
146 static int hf_ssh_languages_client_to_server=-1;
147 static int hf_ssh_languages_server_to_client=-1;
148 static int hf_ssh_kex_algorithms_length= -1;
149 static int hf_ssh_server_host_key_algorithms_length= -1;
150 static int hf_ssh_encryption_algorithms_client_to_server_length= -1;
151 static int hf_ssh_encryption_algorithms_server_to_client_length= -1;
152 static int hf_ssh_mac_algorithms_client_to_server_length= -1;
153 static int hf_ssh_mac_algorithms_server_to_client_length= -1;
154 static int hf_ssh_compression_algorithms_client_to_server_length= -1;
155 static int hf_ssh_compression_algorithms_server_to_client_length= -1;
156 static int hf_ssh_languages_client_to_server_length= -1;
157 static int hf_ssh_languages_server_to_client_length= -1;
158 static int hf_ssh_kex_first_packet_follows = -1;
159 static int hf_ssh_kex_reserved = -1;
161 static gint ett_ssh = -1;
162 static gint ett_key_exchange= -1;
163 static gint ett_key_init= -1;
164 static gint ett_ssh1= -1;
165 static gint ett_ssh2= -1;
167 static gboolean ssh_desegment = TRUE;
169 #define TCP_PORT_SSH 22
171 static const value_string ssh2_msg_vals[] = {
172 {SSH2_MSG_DISCONNECT, "Disconnect"},
173 {SSH2_MSG_IGNORE, "Ignore"},
174 {SSH2_MSG_UNIMPLEMENTED, "Unimplemented"},
175 {SSH2_MSG_DEBUG, "Debug"},
176 {SSH2_MSG_SERVICE_REQUEST, "Service Request"},
177 {SSH2_MSG_SERVICE_ACCEPT, "Service Accept"},
178 {SSH2_MSG_KEXINIT, "Key Exchange Init"},
179 {SSH2_MSG_NEWKEYS, "New Keys"},
180 {SSH2_MSG_KEXDH_INIT, "Diffie-Hellman Key Exchange Init"},
181 {SSH2_MSG_KEXDH_REPLY, "Diffie-Hellman Key Exchange Reply"},
182 {SSH2_MSG_KEX_DH_GEX_INIT, "Diffie-Hellman GEX Init"},
183 {SSH2_MSG_KEX_DH_GEX_REPLY, "Diffie-Hellman GEX Reply"},
184 {SSH2_MSG_KEX_DH_GEX_REQUEST, "Diffie-Hellman GEX Request"},
188 static const value_string ssh1_msg_vals[] = {
189 {SSH_MSG_NONE,"No Message"},
190 {SSH_MSG_DISCONNECT, "Disconnect"},
191 {SSH_SMSG_PUBLIC_KEY,"Public Key"},
192 {SSH_CMSG_SESSION_KEY,"Session Key"},
193 {SSH_CMSG_USER,"User"},
198 static const value_string ssh_opcode_vals[] _U_ = {
202 static int ssh_dissect_key_init(tvbuff_t *tvb, int offset, proto_tree *tree,
204 struct ssh_flow_data *global_data);
206 static int ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
207 struct ssh_flow_data *global_data,
208 int offset, proto_tree *tree,int is_response,
209 int number, gboolean *need_desegmentation);
210 static int ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
211 struct ssh_flow_data *global_data,
212 int offset, proto_tree *tree,int is_response,
213 int number, gboolean *need_desegmentation );
214 static int ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
215 struct ssh_flow_data *global_data,
216 int offset, proto_tree *tree,int is_response,
217 int number, gboolean *need_desegmentation );
218 static int ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
219 struct ssh_flow_data *global_data,
220 int offset, proto_tree *tree,int is_response,guint *version,
221 gboolean *need_desegmentation);
222 static int ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
223 struct ssh_flow_data *global_data,
224 int offset, proto_tree *tree,int is_response);
225 proto_item * ssh_proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
226 gint start, gint length, gboolean little_endian);
231 dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
234 proto_tree *ssh_tree = NULL;
236 conversation_t *conversation=NULL;
239 guint this_number,number;
243 gboolean is_response;
245 gboolean need_desegmentation;
248 struct ssh_pdu_data *this_data=NULL;
249 struct ssh_flow_data *global_data=NULL;
252 this_data = p_get_proto_data(pinfo->fd, proto_ssh);
254 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
255 pinfo->srcport, pinfo->destport, 0);
258 /* create a new conversation */
259 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
260 pinfo->srcport, pinfo->destport, 0);
263 global_data = conversation_get_proto_data(conversation,proto_ssh);
265 global_data = se_alloc0(sizeof(struct ssh_flow_data));
266 global_data->version=SSH_VERSION_UNKNOWN;
267 global_data->mac_length=-1;
269 conversation_add_proto_data(conversation,proto_ssh,global_data);
273 * end of attaching data
275 if (pinfo->destport == pinfo->match_port) {
278 this_data = se_alloc(sizeof(struct ssh_pdu_data));
279 this_data->counter = global_data->req_counter++;
280 p_add_proto_data(pinfo->fd, proto_ssh, this_data);
286 this_data = se_alloc(sizeof(struct ssh_flow_data));
287 this_data->counter = global_data->rsp_counter++;
288 p_add_proto_data(pinfo->fd, proto_ssh, this_data);
293 ti = proto_tree_add_item(tree, proto_ssh, tvb, offset, -1, FALSE);
294 ssh_tree = proto_item_add_subtree(ti, ett_ssh);
298 version = global_data->version;
300 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
302 case SSH_VERSION_UNKNOWN:
303 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSH");
306 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv1");
309 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv2");
315 if(this_data->counter != 0 && version == SSH_VERSION_UNKNOWN) {
316 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
318 offset,ssh_tree,is_response);
322 while((remain_length = tvb_reported_length_remaining(tvb,offset))> 0 ) {
323 need_desegmentation = FALSE;
324 last_offset = offset;
325 this_number = this_data->counter+number;
327 if(number > 1 && is_newdata) {
328 /* update the this_data and flow_data */
330 global_data->rsp_counter++;
332 global_data->req_counter++;
337 if(this_number == 0) {
338 offset = ssh_dissect_protocol(tvb, pinfo,
340 offset,ssh_tree, is_response,
341 &version, &need_desegmentation);
343 global_data->version= version;
348 case SSH_VERSION_UNKNOWN:
350 * We use "tvb_ensure_length_remaining()"
351 * to make sure there actually *is* data
354 * This means we're guaranteed that
355 * "remain_length" is positive.
357 remain_length = tvb_ensure_length_remaining(tvb,
359 proto_tree_add_text(ssh_tree, tvb, offset,
361 "Unknown SSH version data");
362 offset += remain_length;
366 offset = ssh_dissect_ssh1(tvb, pinfo, global_data,
367 offset,ssh_tree,is_response,this_number,
368 &need_desegmentation);
372 offset = ssh_dissect_ssh2(tvb, pinfo, global_data,
373 offset,ssh_tree,is_response,this_number,
374 &need_desegmentation);
379 if(offset <= last_offset)
380 THROW(ReportedBoundsError);
381 if(need_desegmentation) return;
386 ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
387 struct ssh_flow_data *global_data,
388 int offset, proto_tree *tree,int is_response, int this_number,
389 gboolean *need_desegmentation)
392 proto_item *ssh2_tree=NULL;
395 GString *title=g_string_new("SSH Version 2");
397 if (global_data->enc || global_data->mac || global_data->comp) {
398 g_string_append_printf(title," (");
399 if (global_data->enc)
400 g_string_append_printf(title,"encryption:%s%s",
402 global_data->mac || global_data->comp
404 if (global_data->mac)
405 g_string_append_printf(title,"mac:%s%s",
407 global_data->comp ? " " : "");
408 if (global_data->comp)
409 g_string_append_printf(title,"compression:%s",
411 g_string_append_printf(title,")");
414 ti=proto_tree_add_text(tree,tvb,offset,-1,title->str);
415 ssh2_tree = proto_item_add_subtree(ti ,ett_ssh2);
416 if (title) g_string_free(title,TRUE);
419 if((is_response && this_number > 3) || (!is_response && this_number>4)) {
420 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
422 offset,ssh2_tree,is_response);
424 offset = ssh_dissect_key_exchange(tvb,pinfo, global_data,
425 offset,ssh2_tree,is_response,this_number,
426 need_desegmentation);
432 ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
433 struct ssh_flow_data *global_data _U_,
434 int offset, proto_tree *tree,int is_response,
435 int number, gboolean *need_desegmentation)
437 guint plen, padding_length,len;
442 proto_item *ssh1_tree =NULL;
445 ti=proto_tree_add_text(tree,tvb,offset,-1,"SSH Version 1");
446 ssh1_tree = proto_item_add_subtree(ti ,ett_ssh1);
450 * We use "tvb_ensure_length_remaining()" to make sure there
451 * actually *is* data remaining.
453 * This means we're guaranteed that "remain_length" is positive.
455 remain_length = tvb_ensure_length_remaining(tvb,offset);
456 if (ssh_desegment && pinfo->can_desegment) {
457 if(remain_length < 4) {
458 pinfo->desegment_offset = offset;
459 pinfo->desegment_len = 4-remain_length;
460 *need_desegmentation = TRUE;
464 plen = tvb_get_ntohl(tvb, offset) ;
465 padding_length = 8 - plen%8;
468 if (ssh_desegment && pinfo->can_desegment) {
469 if(plen+4+padding_length > remain_length ) {
470 pinfo->desegment_offset = offset;
471 pinfo->desegment_len = plen+padding_length - remain_length;
472 *need_desegmentation = TRUE;
477 if (check_col(pinfo->cinfo, COL_INFO)) {
478 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: ",
479 is_response?"Server":"Client");
483 if (ssh1_tree && plen > 0) {
484 proto_tree_add_uint_format(ssh1_tree, hf_ssh_packet_length, tvb,
485 offset, 4, plen,"Overly large length %x",plen);
487 plen = remain_length-4-padding_length;
489 if (ssh1_tree && plen > 0) {
490 proto_tree_add_uint(ssh1_tree, hf_ssh_packet_length, tvb,
498 proto_tree_add_uint(ssh1_tree, hf_ssh_padding_length, tvb,
499 offset, padding_length, padding_length);
501 offset += padding_length;
504 tf=proto_tree_add_text(tree,tvb,offset,-1,"SSH Version 1");
505 ssh1_tree = proto_item_add_subtree(tf ,ett_ssh1);
510 msg_code = tvb_get_guint8(tvb, offset);
512 proto_tree_add_uint_format(ssh1_tree, hf_ssh_msg_code, tvb,
513 offset, 1, msg_code,"Msg code: %s (%u)",
514 val_to_str(msg_code, ssh1_msg_vals, "Unknown (%u)"),
517 if (check_col(pinfo->cinfo, COL_INFO)) {
518 col_append_str(pinfo->cinfo, COL_INFO,
519 val_to_str(msg_code, ssh1_msg_vals, "Unknown (%u)"));
525 if (check_col(pinfo->cinfo, COL_INFO)) {
526 col_append_fstr(pinfo->cinfo, COL_INFO, "Encrypted packet len=%d", len);
531 ssh_proto_tree_add_item(ssh1_tree, hf_ssh_payload,
532 tvb, offset, len, FALSE);
540 ssh_tree_add_mpint(tvbuff_t *tvb, int offset, proto_tree *tree,
541 int hf_ssh_mpint_selection)
543 guint len = tvb_get_ntohl(tvb, offset);
545 proto_tree_add_uint(tree, hf_ssh_mpint_length, tvb,
550 ssh_proto_tree_add_item(tree, hf_ssh_mpint_selection,
551 tvb, offset, len, FALSE);
557 ssh_tree_add_string(tvbuff_t *tvb, int offset, proto_tree *tree,
558 int hf_ssh_string, int hf_ssh_string_length)
560 guint len = tvb_get_ntohl(tvb, offset);
562 proto_tree_add_uint(tree, hf_ssh_string_length, tvb,
567 ssh_proto_tree_add_item(tree, hf_ssh_string,
568 tvb, offset, len, FALSE);
574 ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
575 struct ssh_flow_data *global_data,
576 int offset, proto_tree *tree,int is_response,int number,
577 gboolean *need_desegmentation)
580 guint8 padding_length;
582 int last_offset=offset;
586 proto_item *key_ex_tree =NULL;
589 * We use "tvb_ensure_length_remaining()" to make sure there
590 * actually *is* data remaining.
592 * This means we're guaranteed that "remain_length" is positive.
594 remain_length = tvb_ensure_length_remaining(tvb,offset);
595 if (ssh_desegment && pinfo->can_desegment) {
596 if(remain_length < 4) {
597 pinfo->desegment_offset = offset;
598 pinfo->desegment_len = 4-remain_length;
599 *need_desegmentation = TRUE;
603 plen = tvb_get_ntohl(tvb, offset) ;
605 if (ssh_desegment && pinfo->can_desegment) {
606 if(plen +4 > remain_length ) {
607 pinfo->desegment_offset = offset;
608 pinfo->desegment_len = plen+4 - remain_length;
609 *need_desegmentation = TRUE;
614 * Need to check plen > 0x80000000 here
617 if (check_col(pinfo->cinfo, COL_INFO)) {
618 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: ",
619 is_response?"Server":"Client");
624 proto_tree_add_uint_format(tree, hf_ssh_packet_length, tvb,
625 offset, 4, plen,"Overly large number 0x%x",plen);
627 plen = remain_length-4;
630 proto_tree_add_uint(tree, hf_ssh_packet_length, tvb,
636 padding_length = tvb_get_guint8(tvb, offset);
638 proto_tree_add_uint(tree, hf_ssh_padding_length, tvb,
639 offset, 1, padding_length);
644 tf=proto_tree_add_text(tree,tvb,offset,-1,"Key Exchange");
645 key_ex_tree = proto_item_add_subtree(tf ,ett_key_exchange);
648 msg_code = tvb_get_guint8(tvb, offset);
650 proto_tree_add_uint_format(key_ex_tree, hf_ssh_msg_code, tvb,
651 offset, 1, msg_code,"Msg code: %s (%u)",
652 val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)"),
656 if (check_col(pinfo->cinfo, COL_INFO)) {
657 col_append_str(pinfo->cinfo, COL_INFO,
658 val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)"));
662 /* 16 bytes cookie */
664 offset = ssh_dissect_key_init(tvb, offset, key_ex_tree, is_response, global_data);
667 /* DH GEX Request (min/nbits/max) */
668 if (msg_code == 34) {
669 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_dh_gex_min,
670 tvb, offset, 4, FALSE);
672 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_dh_gex_nbits,
673 tvb, offset, 4, FALSE);
675 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_dh_gex_max,
676 tvb, offset, 4, FALSE);
679 /* DH Key Exchange Reply (g/p) */
680 if (msg_code == 31) {
681 offset+=ssh_tree_add_mpint(tvb,offset,key_ex_tree,hf_ssh_mpint_p);
682 offset+=ssh_tree_add_mpint(tvb,offset,key_ex_tree,hf_ssh_mpint_g);
684 /* DH GEX Init (e) */
685 if (msg_code == 32) {
686 offset+=ssh_tree_add_mpint(tvb,offset,key_ex_tree,hf_ssh_mpint_e);
688 /* DH GEX Reply (f) */
689 if (msg_code == 33) {
690 offset+=ssh_tree_add_string(tvb,offset,key_ex_tree,hf_ssh_kexdh_host_key,hf_ssh_kexdh_host_key_length);
691 offset+=ssh_tree_add_mpint(tvb,offset,key_ex_tree,hf_ssh_mpint_f);
692 offset+=ssh_tree_add_string(tvb,offset,key_ex_tree,hf_ssh_kexdh_h_sig,hf_ssh_kexdh_h_sig_length);
696 len = plen+4-padding_length-(offset-last_offset);
698 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_payload,
699 tvb, offset, len, FALSE);
705 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_padding_string,
706 tvb, offset, padding_length, FALSE);
708 offset+= padding_length;
710 /* MAC , if there is still bytes, treat it as 16bytes MAC*/
711 if(msg_code == SSH2_MSG_KEX_DH_GEX_REPLY) {
712 len = tvb_reported_length_remaining(tvb,offset);
715 proto_tree_add_item(key_ex_tree, hf_ssh_mac_string,
716 tvb, offset, len , FALSE);
725 ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
726 struct ssh_flow_data *global_data,
727 int offset, proto_tree *tree,int is_response)
731 len = tvb_reported_length_remaining(tvb,offset);
732 if (check_col(pinfo->cinfo, COL_INFO)) {
733 col_add_fstr(pinfo->cinfo, COL_INFO, "Encrypted %s packet len=%d",
734 is_response?"response":"request",len);
737 gint encrypted_len = len;
739 if (global_data && global_data->mac_length>0)
740 encrypted_len -= global_data->mac_length;
742 ssh_proto_tree_add_item(tree, hf_ssh_encrypted_packet,
743 tvb, offset, encrypted_len, FALSE);
745 if (global_data && global_data->mac_length>0)
746 ssh_proto_tree_add_item(tree, hf_ssh_mac_string,
747 tvb, offset+encrypted_len,
748 global_data->mac_length , FALSE);
755 ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
756 struct ssh_flow_data *global_data,
757 int offset, proto_tree *tree, int is_response, guint * version,
758 gboolean *need_desegmentation)
761 gint linelen, protolen;
764 * If the first packet do not contain the banner,
765 * it is dump in the middle of a flow or not a ssh at all
767 if(tvb_strncaseeql(tvb,offset,"SSH-",4) != 0 ) {
768 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
770 offset,tree,is_response);
775 if(tvb_strncaseeql(tvb,offset,"SSH-2.",6) == 0 ) {
776 *(version) = SSH_VERSION_2;
777 }else if(tvb_strncaseeql(tvb,offset,"SSH-1.99-",9) == 0 ) {
778 *(version) = SSH_VERSION_2;
779 }else if(tvb_strncaseeql(tvb,offset,"SSH-1.",6) == 0 ) {
780 *(version) = SSH_VERSION_1;
785 * We use "tvb_ensure_length_remaining()" to make sure there
786 * actually *is* data remaining.
788 * This means we're guaranteed that "remain_length" is positive.
790 remain_length = tvb_ensure_length_remaining(tvb,offset);
791 /*linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
793 linelen = tvb_find_guint8(tvb, offset, -1, '\n');
795 if (ssh_desegment && pinfo->can_desegment) {
796 if(linelen == -1 || remain_length < (guint)linelen-offset ) {
797 pinfo->desegment_offset = offset;
798 pinfo->desegment_len = linelen-remain_length;
799 *need_desegmentation = TRUE;
804 /* XXX - reassemble across segment boundaries? */
805 linelen = remain_length;
808 linelen = linelen - offset + 1;
809 protolen = linelen - 1;
812 if (check_col(pinfo->cinfo, COL_INFO)) {
813 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Protocol: %s",
814 is_response?"Server":"Client",
815 tvb_format_text(tvb,offset,protolen));
818 ssh_proto_tree_add_item(tree, hf_ssh_protocol,
819 tvb, offset, linelen, FALSE);
825 #define SSH_PROPOSAL(item)\
826 { &hf_ssh_ ## item, &hf_ssh_ ## item ## _length }
830 } ssh_proposals[] = {
831 SSH_PROPOSAL(kex_algorithms),
832 SSH_PROPOSAL(server_host_key_algorithms),
833 SSH_PROPOSAL(encryption_algorithms_client_to_server),
834 SSH_PROPOSAL(encryption_algorithms_server_to_client),
835 SSH_PROPOSAL(mac_algorithms_client_to_server),
836 SSH_PROPOSAL(mac_algorithms_server_to_client),
837 SSH_PROPOSAL(compression_algorithms_client_to_server),
838 SSH_PROPOSAL(compression_algorithms_server_to_client),
839 SSH_PROPOSAL(languages_client_to_server),
840 SSH_PROPOSAL(languages_server_to_client),
845 ssh_set_mac_length(struct ssh_flow_data *global_data, gchar *mac_name)
850 if (!global_data || !mac_name) return;
852 if ((size_str=g_strrstr(mac_name,"-")) && ((size=atoi(size_str+1)))) {
853 global_data->mac_length = size;
855 else if (strcmp(mac_name,"hmac-sha1") == 0) {
856 global_data->mac_length = 20;
858 else if (strcmp(mac_name,"hmac-md5") == 0) {
859 global_data->mac_length = 12;
861 else if (strcmp(mac_name,"none") == 0) {
862 global_data->mac_length = 0;
867 ssh_gslist_compare_strings(gconstpointer a, gconstpointer b)
869 if (a == NULL && b == NULL)
875 return strcmp((char*)a,(char*)b);
878 /* expects that *result is NULL */
880 ssh_choose_algo(gchar *client, gchar *server, gchar **result)
882 gchar **server_strings=NULL;
883 gchar **client_strings=NULL;
885 GSList* server_list = NULL;
887 if (!client || !server || !result || *result)
890 server_strings = g_strsplit(server,",",0);
891 for (step = server_strings; *step; step++) {
892 server_list = g_slist_append(server_list, *step);
895 client_strings = g_strsplit(client,",",0);
896 for (step = client_strings; *step; step++) {
898 if ((agreed=g_slist_find_custom(server_list, *step, ssh_gslist_compare_strings))) {
899 *result = se_strdup(agreed->data);
904 g_strfreev(client_strings);
905 g_slist_free(server_list);
906 g_strfreev(server_strings);
910 ssh_evaluate_negotiation(tvbuff_t *tvb, int offset, int len,
911 int hf_value, int hf_client, int hf_server,
912 gchar **client, gchar **server, gchar **agreed)
914 if (!tvb || !client || !server || !agreed) return;
916 if (hf_value == hf_client && !*client) {
917 *client = se_strdup(tvb_get_ephemeral_string(tvb, offset, len));
920 if (hf_value == hf_server && !*server) {
921 *server = se_strdup(tvb_get_ephemeral_string(tvb, offset, len));
924 if (*client && *server && !*agreed) {
925 ssh_choose_algo(*client, *server, agreed);
930 ssh_dissect_key_init(tvbuff_t *tvb, int offset, proto_tree *tree,
932 struct ssh_flow_data *global_data )
936 int start_offset = offset;
938 proto_item *tf = NULL;
939 proto_item *key_init_tree=NULL;
942 tf=proto_tree_add_text(tree,tvb,offset,-1,"Algorithms");
943 key_init_tree = proto_item_add_subtree(tf, ett_key_init);
944 proto_tree_add_item(key_init_tree, hf_ssh_cookie,
945 tvb, offset, 16, FALSE);
949 for (i = 0; ssh_proposals[i].value; i++) {
950 len = tvb_get_ntohl(tvb, offset);
952 proto_tree_add_uint(key_init_tree,
953 *ssh_proposals[i].length, tvb, offset, 4, len);
957 ssh_proto_tree_add_item(key_init_tree,
958 *ssh_proposals[i].value, tvb, offset, len, FALSE);
960 /* record negotiations */
963 ssh_evaluate_negotiation(tvb, offset, len,
964 *ssh_proposals[i].value,
965 hf_ssh_mac_algorithms_client_to_server,
966 hf_ssh_mac_algorithms_server_to_client,
967 &global_data->mac_client_request,
968 &global_data->mac_server_offer,
970 if (global_data->mac && global_data->mac_length<0)
971 ssh_set_mac_length(global_data, global_data->mac);
973 /* figure out Encryption */
974 ssh_evaluate_negotiation(tvb, offset, len,
975 *ssh_proposals[i].value,
976 hf_ssh_encryption_algorithms_client_to_server,
977 hf_ssh_encryption_algorithms_server_to_client,
978 &global_data->enc_client_request,
979 &global_data->enc_server_offer,
982 /* figure out Compression */
983 ssh_evaluate_negotiation(tvb, offset, len,
984 *ssh_proposals[i].value,
985 hf_ssh_compression_algorithms_client_to_server,
986 hf_ssh_compression_algorithms_server_to_client,
987 &global_data->comp_client_request,
988 &global_data->comp_server_offer,
995 ssh_proto_tree_add_item(key_init_tree, hf_ssh_kex_first_packet_follows,
996 tvb, offset, 1, FALSE);
999 ssh_proto_tree_add_item(key_init_tree, hf_ssh_kex_reserved,
1000 tvb, offset, 4, FALSE);
1004 proto_item_set_len(tf, offset-start_offset);
1010 ssh_proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
1011 gint start, gint length, gboolean little_endian)
1013 if (tree && length <0xffff && length > 0) {
1014 return proto_tree_add_item(tree, hfindex, tvb, start, length,little_endian);
1020 proto_register_ssh(void)
1022 static hf_register_info hf[] = {
1023 { &hf_ssh_packet_length,
1024 { "Packet Length", "ssh.packet_length",
1025 FT_UINT32, BASE_DEC, NULL, 0x0,
1026 "SSH packet length", HFILL }},
1028 { &hf_ssh_padding_length,
1029 { "Padding Length", "ssh.padding_length",
1030 FT_UINT8, BASE_DEC, NULL, 0x0,
1031 "SSH Packet Number", HFILL }},
1034 { "Message Code", "ssh.message_code",
1035 FT_UINT8, BASE_DEC, NULL, 0x0,
1036 "SSH Message Code", HFILL }},
1039 { "DH base (G)", "ssh.dh.g",
1040 FT_BYTES, BASE_NONE, NULL, 0x0,
1041 "SSH DH base (G)", HFILL }},
1044 { "DH modulus (P)", "ssh.dh.p",
1045 FT_BYTES, BASE_NONE, NULL, 0x0,
1046 "SSH DH modulus (P)", HFILL }},
1049 { "DH client e", "ssh.dh.e",
1050 FT_BYTES, BASE_NONE, NULL, 0x0,
1051 "SSH DH client e", HFILL }},
1054 { "DH server f", "ssh.dh.f",
1055 FT_BYTES, BASE_NONE, NULL, 0x0,
1056 "SSH DH server f", HFILL }},
1058 { &hf_ssh_mpint_length,
1059 { "Multi Precision Integer Length", "ssh.mpint_length",
1060 FT_UINT32, BASE_DEC, NULL, 0x0,
1061 "SSH mpint length", HFILL }},
1063 { &hf_ssh_kexdh_host_key,
1064 { "KEX DH host key", "ssh.kexdh.host_key",
1065 FT_BYTES, BASE_NONE, NULL, 0x0,
1066 "SSH KEX DH host key", HFILL }},
1068 { &hf_ssh_kexdh_h_sig,
1069 { "KEX DH H signature", "ssh.kexdh.h_sig",
1070 FT_BYTES, BASE_NONE, NULL, 0x0,
1071 "SSH KEX DH H signature", HFILL }},
1073 { &hf_ssh_kexdh_host_key_length,
1074 { "KEX DH host key length", "ssh.kexdh.host_key_length",
1075 FT_UINT32, BASE_DEC, NULL, 0x0,
1076 "SSH KEX DH host key length", HFILL }},
1078 { &hf_ssh_kexdh_h_sig_length,
1079 { "KEX DH H signature length", "ssh.kexdh.h_sig_length",
1080 FT_UINT32, BASE_DEC, NULL, 0x0,
1081 "SSH KEX DH H signature length", HFILL }},
1083 { &hf_ssh_encrypted_packet,
1084 { "Encrypted Packet", "ssh.encrypted_packet",
1085 FT_BYTES, BASE_NONE, NULL, 0x0,
1086 "SSH Protocol Packet", HFILL }},
1089 { "Protocol", "ssh.protocol",
1090 FT_STRING, BASE_NONE, NULL, 0x0,
1091 "SSH Protocol", HFILL }},
1094 { "Cookie", "ssh.cookie",
1095 FT_BYTES, BASE_NONE, NULL, 0x0,
1096 "SSH Cookie", HFILL }},
1098 { &hf_ssh_kex_first_packet_follows,
1099 { "KEX First Packet Follows", "ssh.kex.first_packet_follows",
1100 FT_UINT8, BASE_DEC, NULL, 0x0,
1101 "SSH KEX Fist Packet Follows", HFILL }},
1103 { &hf_ssh_kex_reserved,
1104 { "Reserved", "ssh.kex.reserved",
1105 FT_BYTES, BASE_NONE, NULL, 0x0,
1106 "SSH Protocol KEX Reserved", HFILL }},
1108 { &hf_ssh_dh_gex_min,
1109 { "DH GEX Min", "ssh.dh_gex.min",
1110 FT_BYTES, BASE_NONE, NULL, 0x0,
1111 "SSH DH GEX Minimum", HFILL }},
1113 { &hf_ssh_dh_gex_nbits,
1114 { "DH GEX Numbers of Bits", "ssh.dh_gex.nbits",
1115 FT_BYTES, BASE_NONE, NULL, 0x0,
1116 "SSH DH GEX Number of Bits", HFILL }},
1118 { &hf_ssh_dh_gex_max,
1119 { "DH GEX Max", "ssh.dh_gex.max",
1120 FT_BYTES, BASE_NONE, NULL, 0x0,
1121 "SSH DH GEX Maximum", HFILL }},
1124 { "Payload", "ssh.payload",
1125 FT_BYTES, BASE_NONE, NULL, 0x0,
1126 "SSH Payload", HFILL }},
1128 { &hf_ssh_padding_string,
1129 { "Padding String", "ssh.padding_string",
1130 FT_BYTES, BASE_NONE, NULL, 0x0,
1131 "SSH Padding String", HFILL }},
1133 { &hf_ssh_mac_string,
1135 FT_BYTES, BASE_NONE, NULL, 0x0,
1136 "SSH Protocol Packet MAC", HFILL }},
1138 { &hf_ssh_kex_algorithms,
1139 { "kex_algorithms string", "ssh.kex_algorithms",
1140 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1141 "SSH kex_algorithms string", HFILL }},
1143 { &hf_ssh_server_host_key_algorithms,
1144 { "server_host_key_algorithms string", "ssh.server_host_key_algorithms",
1145 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1146 "SSH server_host_key_algorithms string", HFILL }},
1148 { &hf_ssh_encryption_algorithms_client_to_server,
1149 { "encryption_algorithms_client_to_server string", "ssh.encryption_algorithms_client_to_server",
1150 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1151 "SSH encryption_algorithms_client_to_server string", HFILL }},
1153 { &hf_ssh_encryption_algorithms_server_to_client,
1154 { "encryption_algorithms_server_to_client string", "ssh.encryption_algorithms_server_to_client",
1155 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1156 "SSH encryption_algorithms_server_to_client string", HFILL }},
1158 { &hf_ssh_mac_algorithms_client_to_server,
1159 { "mac_algorithms_client_to_server string", "ssh.mac_algorithms_client_to_server",
1160 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1161 "SSH mac_algorithms_client_to_server string", HFILL }},
1163 { &hf_ssh_mac_algorithms_server_to_client,
1164 { "mac_algorithms_server_to_client string", "ssh.mac_algorithms_server_to_client",
1165 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1166 "SSH mac_algorithms_server_to_client string", HFILL }},
1168 { &hf_ssh_compression_algorithms_client_to_server,
1169 { "compression_algorithms_client_to_server string", "ssh.compression_algorithms_client_to_server",
1170 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1171 "SSH compression_algorithms_client_to_server string", HFILL }},
1173 { &hf_ssh_compression_algorithms_server_to_client,
1174 { "compression_algorithms_server_to_client string", "ssh.compression_algorithms_server_to_client",
1175 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1176 "SSH compression_algorithms_server_to_client string", HFILL }},
1178 { &hf_ssh_languages_client_to_server,
1179 { "languages_client_to_server string", "ssh.languages_client_to_server",
1180 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1181 "SSH languages_client_to_server string", HFILL }},
1183 { &hf_ssh_languages_server_to_client,
1184 { "languages_server_to_client string", "ssh.languages_server_to_client",
1185 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1186 "SSH languages_server_to_client string", HFILL }},
1188 { &hf_ssh_kex_algorithms_length,
1189 { "kex_algorithms length", "ssh.kex_algorithms_length",
1190 FT_UINT32, BASE_DEC, NULL, 0x0,
1191 "SSH kex_algorithms length", HFILL }},
1193 { &hf_ssh_server_host_key_algorithms_length,
1194 { "server_host_key_algorithms length", "ssh.server_host_key_algorithms_length",
1195 FT_UINT32, BASE_DEC, NULL, 0x0,
1196 "SSH server_host_key_algorithms length", HFILL }},
1198 { &hf_ssh_encryption_algorithms_client_to_server_length,
1199 { "encryption_algorithms_client_to_server length", "ssh.encryption_algorithms_client_to_server_length",
1200 FT_UINT32, BASE_DEC, NULL, 0x0,
1201 "SSH encryption_algorithms_client_to_server length", HFILL }},
1203 { &hf_ssh_encryption_algorithms_server_to_client_length,
1204 { "encryption_algorithms_server_to_client length", "ssh.encryption_algorithms_server_to_client_length",
1205 FT_UINT32, BASE_DEC, NULL, 0x0,
1206 "SSH encryption_algorithms_server_to_client length", HFILL }},
1208 { &hf_ssh_mac_algorithms_client_to_server_length,
1209 { "mac_algorithms_client_to_server length", "ssh.mac_algorithms_client_to_server_length",
1210 FT_UINT32, BASE_DEC, NULL, 0x0,
1211 "SSH mac_algorithms_client_to_server length", HFILL }},
1213 { &hf_ssh_mac_algorithms_server_to_client_length,
1214 { "mac_algorithms_server_to_client length", "ssh.mac_algorithms_server_to_client_length",
1215 FT_UINT32, BASE_DEC, NULL, 0x0,
1216 "SSH mac_algorithms_server_to_client length", HFILL }},
1218 { &hf_ssh_compression_algorithms_client_to_server_length,
1219 { "compression_algorithms_client_to_server length", "ssh.compression_algorithms_client_to_server_length",
1220 FT_UINT32, BASE_DEC, NULL, 0x0,
1221 "SSH compression_algorithms_client_to_server length", HFILL }},
1223 { &hf_ssh_compression_algorithms_server_to_client_length,
1224 { "compression_algorithms_server_to_client length", "ssh.compression_algorithms_server_to_client_length",
1225 FT_UINT32, BASE_DEC, NULL, 0x0,
1226 "SSH compression_algorithms_server_to_client length", HFILL }},
1228 { &hf_ssh_languages_client_to_server_length,
1229 { "languages_client_to_server length", "ssh.languages_client_to_server_length",
1230 FT_UINT32, BASE_DEC, NULL, 0x0,
1231 "SSH languages_client_to_server length", HFILL }},
1233 { &hf_ssh_languages_server_to_client_length,
1234 { "languages_server_to_client length", "ssh.languages_server_to_client_length",
1235 FT_UINT32, BASE_DEC, NULL, 0x0,
1236 "SSH languages_server_to_client length", HFILL }},
1240 static gint *ett[] = {
1247 module_t *ssh_module;
1249 proto_ssh = proto_register_protocol("SSH Protocol",
1251 proto_register_field_array(proto_ssh, hf, array_length(hf));
1252 proto_register_subtree_array(ett, array_length(ett));
1254 ssh_module = prefs_register_protocol(proto_ssh, NULL);
1255 prefs_register_bool_preference(ssh_module, "desegment_buffers",
1256 "Reassemble SSH buffers spanning multiple TCP segments",
1257 "Whether the SSH dissector should reassemble SSH buffers spanning multiple TCP segments. "
1258 "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
1263 proto_reg_handoff_ssh(void)
1265 dissector_handle_t ssh_handle;
1267 ssh_handle = create_dissector_handle(dissect_ssh, proto_ssh);
1269 dissector_add("tcp.port", TCP_PORT_SSH, ssh_handle);