some compilers dont like unnamed unions and structs
[obnox/wireshark/wip.git] / epan / dissectors / packet-ssh.c
1 /* packet-ssh.c
2  * Routines for ssh packet dissection
3  *
4  * Huagang XIE <huagang@intruvert.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
12  * Copied from packet-mysql.c
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  *
28  *
29  * Note:  support SSH v1 and v2  now.
30  *
31  */
32
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/conversation.h>
40 #include <epan/emem.h>
41
42 #include "packet-tcp.h"
43 #include <epan/reassemble.h>
44 #include <epan/prefs.h>
45
46 /* get from openssh ssh2.h */
47 #define SSH2_MSG_DISCONNECT                             1
48 #define SSH2_MSG_IGNORE                                 2
49 #define SSH2_MSG_UNIMPLEMENTED                          3
50 #define SSH2_MSG_DEBUG                                  4
51 #define SSH2_MSG_SERVICE_REQUEST                        5
52 #define SSH2_MSG_SERVICE_ACCEPT                         6
53
54 /* transport layer: alg negotiation */
55
56 #define SSH2_MSG_KEXINIT                                20
57 #define SSH2_MSG_NEWKEYS                                21
58
59 /* transport layer: kex specific messages, can be reused */
60
61 #define SSH2_MSG_KEXDH_INIT                             30
62 #define SSH2_MSG_KEXDH_REPLY                            31
63
64 /*
65 #define SSH2_MSG_KEX_DH_GEX_REQUEST_OLD                 30
66 #define SSH2_MSG_KEX_DH_GEX_GROUP                       31
67 */
68 #define SSH2_MSG_KEX_DH_GEX_INIT                        32
69 #define SSH2_MSG_KEX_DH_GEX_REPLY                       33
70 #define SSH2_MSG_KEX_DH_GEX_REQUEST                     34
71
72 /* SSH Version 1 definition , from openssh ssh1.h */
73
74 #define SSH_MSG_NONE                            0       /* no message */
75 #define SSH_MSG_DISCONNECT                      1       /* cause (string) */
76 #define SSH_SMSG_PUBLIC_KEY                     2       /* ck,msk,srvk,hostk */
77 #define SSH_CMSG_SESSION_KEY                    3       /* key (BIGNUM) */
78 #define SSH_CMSG_USER                           4       /* user (string) */
79
80
81 #define SSH_VERSION_UNKNOWN     0
82 #define SSH_VERSION_1           1
83 #define SSH_VERSION_2           2
84
85 /* proto data */
86
87 struct ssh_pdu_data{
88         guint   counter;
89         guint   number;
90 };
91
92 struct ssh_flow_data {
93         guint   req_counter;
94         guint   rsp_counter;
95         guint   version;
96 };
97
98 static int proto_ssh = -1;
99 static int hf_ssh_packet_length= -1;
100 static int hf_ssh_padding_length= -1;
101 static int hf_ssh_payload= -1;
102 static int hf_ssh_protocol= -1;
103 static int hf_ssh_encrypted_packet= -1;
104 static int hf_ssh_padding_string= -1;
105 static int hf_ssh_mac_string= -1;
106 static int hf_ssh_msg_code = -1;
107 static int hf_ssh_cookie = -1;
108 static int hf_ssh_kex_algorithms = -1;
109 static int hf_ssh_server_host_key_algorithms = -1;
110 static int hf_ssh_encryption_algorithms_client_to_server = -1;
111 static int hf_ssh_encryption_algorithms_server_to_client = -1;
112 static int hf_ssh_mac_algorithms_client_to_server=-1;
113 static int hf_ssh_mac_algorithms_server_to_client=-1;
114 static int hf_ssh_compression_algorithms_client_to_server=-1;
115 static int hf_ssh_compression_algorithms_server_to_client=-1;
116 static int hf_ssh_languages_client_to_server=-1;
117 static int hf_ssh_languages_server_to_client=-1;
118 static int hf_ssh_kex_algorithms_length= -1;
119 static int hf_ssh_server_host_key_algorithms_length= -1;
120 static int hf_ssh_encryption_algorithms_client_to_server_length= -1;
121 static int hf_ssh_encryption_algorithms_server_to_client_length= -1;
122 static int hf_ssh_mac_algorithms_client_to_server_length= -1;
123 static int hf_ssh_mac_algorithms_server_to_client_length= -1;
124 static int hf_ssh_compression_algorithms_client_to_server_length= -1;
125 static int hf_ssh_compression_algorithms_server_to_client_length= -1;
126 static int hf_ssh_languages_client_to_server_length= -1;
127 static int hf_ssh_languages_server_to_client_length= -1;
128
129 static gint ett_ssh = -1;
130 static gint ett_key_exchange= -1;
131 static gint ett_key_init= -1;
132 static gint ett_ssh1= -1;
133 static gint ett_ssh2= -1;
134
135 static gboolean ssh_desegment = TRUE;
136
137 #define TCP_PORT_SSH  22
138
139 static const value_string ssh2_msg_vals[] = {
140         {SSH2_MSG_DISCONNECT, "Disconnect"},
141         {SSH2_MSG_IGNORE, "Ignore"},
142         {SSH2_MSG_UNIMPLEMENTED, "Unimplemented"},
143         {SSH2_MSG_DEBUG, "Debug"},
144         {SSH2_MSG_SERVICE_REQUEST, "Service Request"},
145         {SSH2_MSG_SERVICE_ACCEPT, "Service Accept"},
146         {SSH2_MSG_KEXINIT, "Key Exchange Init"},
147         {SSH2_MSG_NEWKEYS, "New Keys"},
148         {SSH2_MSG_KEXDH_INIT, "Diffie-Hellman Key Exchange Init"},
149         {SSH2_MSG_KEXDH_REPLY, "Diffie-Hellman Key Exchange Reply"},
150         {SSH2_MSG_KEX_DH_GEX_INIT, "Diffie-Hellman GEX Init"},
151         {SSH2_MSG_KEX_DH_GEX_REPLY, "Diffie-Hellman GEX Reply"},
152         {SSH2_MSG_KEX_DH_GEX_REQUEST, "Diffie-Hellman GEX Request"},
153         { 0,          NULL }
154 };
155
156 static const value_string ssh1_msg_vals[] = {
157         {SSH_MSG_NONE,"No Message"},
158         {SSH_MSG_DISCONNECT, "Disconnect"},
159         {SSH_SMSG_PUBLIC_KEY,"Public Key"},
160         {SSH_CMSG_SESSION_KEY,"Session Key"},
161         {SSH_CMSG_USER,"User"},
162         {0, NULL}
163 };
164
165
166 static const value_string ssh_opcode_vals[] = {
167   { 0,          NULL }
168 };
169
170 static int ssh_dissect_key_init(tvbuff_t *tvb, int offset, proto_tree *tree);
171
172 static int ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
173                 int offset, proto_tree *tree,int is_response,
174                 int number, gboolean *need_desegmentation);
175 static int ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
176                 int offset, proto_tree *tree,int is_response,
177                 int number, gboolean *need_desegmentation );
178 static int ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
179                 int offset, proto_tree *tree,int is_response,
180                 int number, gboolean *need_desegmentation );
181 static int ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
182                 int offset, proto_tree *tree,int is_response,int *version,
183                 gboolean *need_desegmentation);
184 static int ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
185                 int offset, proto_tree *tree,int is_response);
186 proto_item * ssh_proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
187     gint start, gint length, gboolean little_endian);
188
189
190 static void
191 dissect_ssh(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
192 {
193
194         proto_tree      *ssh_tree = NULL;
195         proto_item      *ti;
196         conversation_t  *conversation=NULL;
197         gint            remain_length;
198         int             last_offset;
199         guint           this_number,number;
200
201         int             offset = 0;
202
203         gboolean        is_response;
204         gboolean        is_newdata;
205         gboolean        need_desegmentation;
206         guint           version;
207
208         struct ssh_pdu_data *this_data=NULL;
209         struct ssh_flow_data *global_data=NULL;
210
211         is_newdata = FALSE;
212         this_data = p_get_proto_data(pinfo->fd, proto_ssh);
213
214         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
215                 pinfo->srcport, pinfo->destport, 0);
216
217         if (!conversation) {
218                 /* create a new conversation */
219                 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype,
220                         pinfo->srcport, pinfo->destport, 0);
221         }
222
223         global_data = conversation_get_proto_data(conversation,proto_ssh);
224         if(!global_data ) {
225                 global_data = se_alloc(sizeof(struct ssh_flow_data));
226                 global_data->req_counter=0;
227                 global_data->rsp_counter=0;
228                 global_data->version=SSH_VERSION_UNKNOWN;
229                 conversation_add_proto_data(conversation,proto_ssh,global_data);
230         }
231
232 /*
233  *      end of attaching data
234  */
235         if (pinfo->destport == pinfo->match_port) {
236                 is_response=FALSE;
237                 if(!this_data) {
238                         this_data = se_alloc(sizeof(struct ssh_pdu_data));
239                         this_data->counter = global_data->req_counter++;
240                         p_add_proto_data(pinfo->fd, proto_ssh, this_data);
241                         is_newdata = TRUE;
242                 }
243         }else {
244                 is_response=TRUE;
245                 if(!this_data) {
246                         this_data = se_alloc(sizeof(struct ssh_flow_data));
247                         this_data->counter = global_data->rsp_counter++;
248                         p_add_proto_data(pinfo->fd, proto_ssh, this_data);
249                         is_newdata = TRUE;
250                 }
251         }
252         if(tree) {
253                   ti = proto_tree_add_item(tree, proto_ssh, tvb, offset, -1, FALSE);
254                   ssh_tree = proto_item_add_subtree(ti, ett_ssh);
255         }
256         number = 0;
257
258         version = global_data->version;
259
260         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
261                 switch(version) {
262                         case SSH_VERSION_UNKNOWN:
263                                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSH");
264                                 break;
265                         case SSH_VERSION_1:
266                                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv1");
267                                 break;
268                         case SSH_VERSION_2:
269                                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SSHv2");
270                                 break;
271
272                 }
273         }
274
275         if(this_data->counter != 0 && version == SSH_VERSION_UNKNOWN) {
276                 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
277                         offset,ssh_tree,is_response);
278                 return;
279         }
280
281         while((remain_length = tvb_reported_length_remaining(tvb,offset))> 0 ) {
282                 need_desegmentation = FALSE;
283                 last_offset = offset;
284                 this_number = this_data->counter+number;
285
286                 if(number > 1 && is_newdata) {
287                         /* update the this_data and flow_data */
288                         if(is_response) {
289                                 global_data->rsp_counter++;
290                         } else {
291                                 global_data->req_counter++;
292                         }
293                 }
294
295                 number++;
296                 if(this_number == 0)  {
297                         offset = ssh_dissect_protocol(tvb, pinfo,
298                                         offset,ssh_tree, is_response,
299                                         &version, &need_desegmentation);
300                         if(!is_response) {
301                                 global_data->version= version;
302                         }
303                 } else {
304                         switch(version) {
305
306                         case SSH_VERSION_UNKNOWN:
307                                 /*
308                                  * We use "tvb_ensure_length_remaining()"
309                                  * to make sure there actually *is* data
310                                  * remaining.
311                                  *
312                                  * This means we're guaranteed that
313                                  * "remain_length" is positive.
314                                  */
315                                 remain_length = tvb_ensure_length_remaining(tvb,
316                                     offset);
317                                 proto_tree_add_text(ssh_tree, tvb, offset,
318                                                 remain_length,
319                                                 "Unknown SSH version data");
320                                 offset += remain_length;
321                                 break;
322
323                         case SSH_VERSION_1:
324                                 offset = ssh_dissect_ssh1(tvb, pinfo,
325                                                 offset,ssh_tree,is_response,this_number,
326                                                 &need_desegmentation);
327                                 break;
328
329                         case SSH_VERSION_2:
330                                 offset = ssh_dissect_ssh2(tvb, pinfo,
331                                                 offset,ssh_tree,is_response,this_number,
332                                                 &need_desegmentation);
333                                 break;
334                         }
335                 }
336
337                 if(offset <= last_offset)
338                         THROW(ReportedBoundsError);
339                 if(need_desegmentation) return;
340         }
341 }
342
343 static int
344 ssh_dissect_ssh2(tvbuff_t *tvb, packet_info *pinfo,
345                 int offset, proto_tree *tree,int is_response, int this_number,
346                 gboolean *need_desegmentation)
347 {
348         proto_item *ti;
349         proto_item *ssh2_tree=NULL;
350
351         if(tree) {
352                 ti=proto_tree_add_text(tree,tvb,offset,-1,"SSH Version 2");
353                 ssh2_tree = proto_item_add_subtree(ti ,ett_ssh2);
354         }
355
356         if((is_response && this_number > 3) || (!is_response && this_number>4)) {
357                 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
358                                 offset,ssh2_tree,is_response);
359         } else {
360                 offset = ssh_dissect_key_exchange(tvb,pinfo,
361                         offset,ssh2_tree,is_response,this_number,
362                         need_desegmentation);
363         }
364
365         return offset;
366 }
367 static int
368 ssh_dissect_ssh1(tvbuff_t *tvb, packet_info *pinfo,
369                 int offset, proto_tree *tree,int is_response,
370                 int number, gboolean *need_desegmentation)
371 {
372         guint   plen, padding_length,len;
373         guint8  msg_code;
374         guint   remain_length;
375
376         proto_item *ti;
377         proto_item *ssh1_tree =NULL;
378
379         if(tree) {
380                 ti=proto_tree_add_text(tree,tvb,offset,-1,"SSH Version 1");
381                 ssh1_tree = proto_item_add_subtree(ti ,ett_ssh1);
382         }
383
384         /*
385          * We use "tvb_ensure_length_remaining()" to make sure there
386          * actually *is* data remaining.
387          *
388          * This means we're guaranteed that "remain_length" is positive.
389          */
390         remain_length = tvb_ensure_length_remaining(tvb,offset);
391         if (ssh_desegment && pinfo->can_desegment) {
392                 if(remain_length < 4) {
393                         pinfo->desegment_offset = offset;
394                         pinfo->desegment_len = 4-remain_length;
395                         *need_desegmentation = TRUE;
396                         return offset;
397                 }
398         }
399         plen = tvb_get_ntohl(tvb, offset) ;
400         padding_length  = 8 - plen%8;
401
402
403         if (ssh_desegment && pinfo->can_desegment) {
404                 if(plen+4+padding_length >  remain_length ) {
405                         pinfo->desegment_offset = offset;
406                         pinfo->desegment_len = plen+padding_length - remain_length;
407                         *need_desegmentation = TRUE;
408                         return offset;
409                 }
410         }
411
412         if (check_col(pinfo->cinfo, COL_INFO)) {
413                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: ",
414                         is_response?"Server":"Client");
415         }
416
417         if(plen >= 0xffff) {
418                 if (ssh1_tree && plen > 0) {
419                           proto_tree_add_uint_format(ssh1_tree, hf_ssh_packet_length, tvb,
420                             offset, 4, plen,"Overly large length %x",plen);
421                 }
422                 plen = remain_length-4-padding_length;
423         } else {
424                 if (ssh1_tree && plen > 0) {
425                           proto_tree_add_uint(ssh1_tree, hf_ssh_packet_length, tvb,
426                             offset, 4, plen);
427                 }
428         }
429         offset+=4;
430 /* padding length */
431
432         if (tree) {
433                   proto_tree_add_uint(ssh1_tree, hf_ssh_padding_length, tvb,
434                     offset, padding_length, padding_length);
435         }
436         offset += padding_length;
437 /*
438         if(tree) {
439                 tf=proto_tree_add_text(tree,tvb,offset,-1,"SSH Version 1");
440                 ssh1_tree = proto_item_add_subtree(tf ,ett_ssh1);
441         }
442 */
443         /* msg_code */
444         if(number == 1 ) {
445                 msg_code = tvb_get_guint8(tvb, offset);
446                 if (tree) {
447                         proto_tree_add_uint_format(ssh1_tree, hf_ssh_msg_code, tvb,
448                                 offset, 1, msg_code,"Msg code: %s (%u)",
449                                 val_to_str(msg_code, ssh1_msg_vals, "Unknown (%u)"),
450                                 msg_code);
451                 }
452                 if (check_col(pinfo->cinfo, COL_INFO)) {
453                         col_append_fstr(pinfo->cinfo, COL_INFO, "%s",
454                         val_to_str(msg_code, ssh1_msg_vals, "Unknown (%u)"));
455                 }
456                 offset += 1;
457                 len = plen -1;
458         } else {
459                 len = plen;
460                 if (check_col(pinfo->cinfo, COL_INFO)) {
461                         col_append_fstr(pinfo->cinfo, COL_INFO, "Encrypted packet len=%d", len);
462                 }
463         }
464         /* payload */
465         if (ssh1_tree ) {
466                 ssh_proto_tree_add_item(ssh1_tree, hf_ssh_payload,
467                     tvb, offset, len, FALSE);
468         }
469         offset+=len;
470
471         return offset;
472 }
473
474 static int
475 ssh_dissect_key_exchange(tvbuff_t *tvb, packet_info *pinfo,
476                 int offset, proto_tree *tree,int is_response,int number,
477                 gboolean *need_desegmentation)
478 {
479         guint   plen,len;
480         guint8  padding_length;
481         guint   remain_length;
482         int     last_offset=offset;
483         guint   msg_code;
484
485         proto_item *tf;
486         proto_item *key_ex_tree =NULL;
487
488         /*
489          * We use "tvb_ensure_length_remaining()" to make sure there
490          * actually *is* data remaining.
491          *
492          * This means we're guaranteed that "remain_length" is positive.
493          */
494         remain_length = tvb_ensure_length_remaining(tvb,offset);
495         if (ssh_desegment && pinfo->can_desegment) {
496                 if(remain_length < 4) {
497                         pinfo->desegment_offset = offset;
498                         pinfo->desegment_len = 4-remain_length;
499                         *need_desegmentation = TRUE;
500                         return offset;
501                 }
502         }
503         plen = tvb_get_ntohl(tvb, offset) ;
504
505         if (ssh_desegment && pinfo->can_desegment) {
506                 if(plen +4 >  remain_length ) {
507                         pinfo->desegment_offset = offset;
508                         pinfo->desegment_len = plen+4 - remain_length;
509                         *need_desegmentation = TRUE;
510                         return offset;
511                 }
512         }
513         /*
514          * Need to check plen > 0x80000000 here
515          */
516
517         if (check_col(pinfo->cinfo, COL_INFO)) {
518                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s: ",
519                         is_response?"Server":"Client");
520         }
521
522         if(plen >= 0xffff) {
523                 if (tree) {
524                         proto_tree_add_uint_format(tree, hf_ssh_packet_length, tvb,
525                                 offset, 4, plen,"Overly large number 0x%x",plen);
526                 }
527                 plen = remain_length-4;
528         } else {
529                 if (tree) {
530                         proto_tree_add_uint(tree, hf_ssh_packet_length, tvb,
531                                 offset, 4, plen);
532                 }
533         }
534         offset+=4;
535 /* padding length */
536         padding_length = tvb_get_guint8(tvb, offset);
537         if (tree) {
538                   proto_tree_add_uint(tree, hf_ssh_padding_length, tvb,
539                     offset, 1, padding_length);
540         }
541         offset += 1;
542
543         if(tree) {
544                 tf=proto_tree_add_text(tree,tvb,offset,-1,"Key Exchange");
545                 key_ex_tree = proto_item_add_subtree(tf ,ett_key_exchange);
546         }
547         /* msg_code */
548         msg_code = tvb_get_guint8(tvb, offset);
549         if (tree) {
550                   proto_tree_add_uint_format(key_ex_tree, hf_ssh_msg_code, tvb,
551                     offset, 1, msg_code,"Msg code: %s (%u)",
552                         val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)"),
553                         msg_code);
554
555         }
556         if (check_col(pinfo->cinfo, COL_INFO)) {
557                 col_append_fstr(pinfo->cinfo, COL_INFO, "%s",
558                         val_to_str(msg_code, ssh2_msg_vals, "Unknown (%u)"));
559         }
560         offset += 1;
561
562         /* 16 bytes cookie  */
563         if(number == 1) {
564                 offset = ssh_dissect_key_init(tvb, offset,key_ex_tree);
565         }
566
567         len = plen+4-padding_length-(offset-last_offset);
568         if (tree ) {
569                 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_payload,
570                     tvb, offset, len, FALSE);
571         }
572         offset +=len;
573
574         /* padding */
575         if(tree) {
576                 ssh_proto_tree_add_item(key_ex_tree, hf_ssh_padding_string,
577                                 tvb, offset, padding_length, FALSE);
578         }
579         offset+= padding_length;
580
581         /* MAC , if there is still bytes, treat it as 16bytes MAC*/
582         if(msg_code == SSH2_MSG_KEX_DH_GEX_REPLY) {
583                 len = tvb_reported_length_remaining(tvb,offset);
584                 if(len == 16) {
585                         if(tree) {
586                                 proto_tree_add_item(key_ex_tree, hf_ssh_mac_string,
587                                         tvb, offset, len , FALSE);
588                         }
589                         offset+=len;
590                 }
591         }
592
593         return offset;
594 }
595 static int
596 ssh_dissect_encrypted_packet(tvbuff_t *tvb, packet_info *pinfo,
597                 int offset, proto_tree *tree,int is_response)
598 {
599         gint len;
600
601         len = tvb_reported_length_remaining(tvb,offset);
602         if (check_col(pinfo->cinfo, COL_INFO)) {
603                 col_add_fstr(pinfo->cinfo, COL_INFO, "Encrypted %s packet len=%d",
604                         is_response?"response":"request",len);
605         }
606         if (tree ) {
607                 ssh_proto_tree_add_item(tree, hf_ssh_encrypted_packet,
608                                 tvb, offset, len, FALSE);
609         }
610         offset+=len;
611         return offset;
612 }
613
614 static int
615 ssh_dissect_protocol(tvbuff_t *tvb, packet_info *pinfo,
616                 int offset, proto_tree *tree, int is_response, int * version,
617                 gboolean *need_desegmentation)
618 {
619         guint   remain_length;
620         gint    linelen, protolen;
621
622         /*
623          *  If the first packet do not contain the banner,
624          *  it is dump in the middle of a flow or not a ssh at all
625          */
626         if(tvb_strncaseeql(tvb,offset,"SSH-",4) != 0 ) {
627                 offset = ssh_dissect_encrypted_packet(tvb, pinfo,
628                         offset,tree,is_response);
629                 return offset;
630         }
631
632         if(!is_response) {
633                 if(tvb_strncaseeql(tvb,offset,"SSH-2.",6) == 0 ) {
634                         *(version) = SSH_VERSION_2;
635                 }else if(tvb_strncaseeql(tvb,offset,"SSH-1.99-",9) == 0 ) {
636                         *(version) = SSH_VERSION_2;
637                 }else if(tvb_strncaseeql(tvb,offset,"SSH-1.",6) == 0 ) {
638                         *(version) = SSH_VERSION_1;
639                }
640         }
641
642         /*
643          * We use "tvb_ensure_length_remaining()" to make sure there
644          * actually *is* data remaining.
645          *
646          * This means we're guaranteed that "remain_length" is positive.
647          */
648         remain_length = tvb_ensure_length_remaining(tvb,offset);
649         /*linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
650          */
651         linelen = tvb_find_guint8(tvb, offset, -1, '\n');
652
653         if (ssh_desegment && pinfo->can_desegment) {
654                 if(linelen == -1 || remain_length < (guint)linelen-offset ) {
655                         pinfo->desegment_offset = offset;
656                         pinfo->desegment_len = linelen-remain_length;
657                         *need_desegmentation = TRUE;
658                         return offset;
659                 }
660         }
661         if(linelen == -1 ) {
662                 /* XXX - reassemble across segment boundaries? */
663                 linelen = remain_length;
664                 protolen = linelen;
665         } else {
666                 linelen = linelen - offset + 1;
667                 protolen = linelen - 1;
668         }
669
670         if (check_col(pinfo->cinfo, COL_INFO)) {
671                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s Protocol: %s",
672                         is_response?"Server":"Client",
673                         tvb_format_text(tvb,offset,protolen));
674         }
675         if (tree ) {
676                 ssh_proto_tree_add_item(tree, hf_ssh_protocol,
677                                 tvb, offset, linelen, FALSE);
678         }
679         offset+=linelen;
680         return offset;
681 }
682
683 #define SSH_PROPOSAL(item)\
684         { &hf_ssh_ ## item, &hf_ssh_ ## item ## _length }
685
686 static struct {
687         int *value, *length;
688 } ssh_proposals[] = {
689         SSH_PROPOSAL(kex_algorithms),
690         SSH_PROPOSAL(server_host_key_algorithms),
691         SSH_PROPOSAL(encryption_algorithms_client_to_server),
692         SSH_PROPOSAL(encryption_algorithms_server_to_client),
693         SSH_PROPOSAL(mac_algorithms_client_to_server),
694         SSH_PROPOSAL(mac_algorithms_server_to_client),
695         SSH_PROPOSAL(compression_algorithms_client_to_server),
696         SSH_PROPOSAL(compression_algorithms_server_to_client),
697         SSH_PROPOSAL(languages_client_to_server),
698         SSH_PROPOSAL(languages_server_to_client),
699         {NULL, NULL}
700 };
701
702 static int
703 ssh_dissect_key_init(tvbuff_t *tvb, int offset, proto_tree *tree )
704 {
705         guint   len;
706         int     i;
707
708         proto_item *tf;
709         proto_item *key_init_tree=NULL;
710
711         if (tree) {
712                 tf=proto_tree_add_text(tree,tvb,offset,-1,"Algorithms");
713                 key_init_tree = proto_item_add_subtree(tf, ett_key_init);
714                 proto_tree_add_item(key_init_tree, hf_ssh_cookie,
715                     tvb, offset, 16, FALSE);
716         }
717         offset += 16;
718
719         for (i = 0; ssh_proposals[i].value; i++) {
720                 len = tvb_get_ntohl(tvb, offset);
721                 if (key_init_tree) {
722                         proto_tree_add_uint(key_init_tree,
723                                 *ssh_proposals[i].length, tvb, offset, 4, len);
724                 }
725                 offset+=4;
726                 if (key_init_tree) {
727                         ssh_proto_tree_add_item(key_init_tree,
728                                 *ssh_proposals[i].value, tvb, offset, len, FALSE);
729                 }
730                 offset+=len;
731         }
732         return offset;
733 }
734 proto_item *
735 ssh_proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb,
736     gint start, gint length, gboolean little_endian)
737 {
738         if (tree && length <0xffff && length > 0) {
739                 return proto_tree_add_item(tree, hfindex, tvb, start, length,little_endian);
740         }
741         return NULL;
742 }
743
744 void
745 proto_register_ssh(void)
746 {
747   static hf_register_info hf[] = {
748     { &hf_ssh_packet_length,
749       { "Packet Length",              "ssh.packet_length",
750         FT_UINT32, BASE_DEC, NULL,  0x0,
751         "SSH packet length", HFILL }},
752
753     { &hf_ssh_padding_length,
754       { "Padding Length",         "ssh.padding_length",
755         FT_UINT8, BASE_DEC, NULL, 0x0,
756         "SSH Packet Number", HFILL }},
757
758     { &hf_ssh_msg_code,
759       { "Message Code",   "ssh.message_code",
760         FT_UINT8, BASE_DEC, NULL, 0x0,
761         "SSH Message Code", HFILL }},
762
763     { &hf_ssh_cookie,
764       { "Cookie",         "ssh.cookie",
765         FT_BYTES, BASE_NONE, NULL, 0x0,
766         "SSH Cookie", HFILL }},
767
768     { &hf_ssh_encrypted_packet,
769       { "Encrypted Packet",       "ssh.encrypted_packet",
770         FT_BYTES, BASE_NONE, NULL, 0x0,
771         "SSH Protocol Packet", HFILL }},
772
773     { &hf_ssh_protocol,
774       { "Protocol",       "ssh.protocol",
775         FT_STRING, BASE_NONE, NULL, 0x0,
776         "SSH Protocol", HFILL }},
777
778     { &hf_ssh_payload,
779       { "Payload",        "ssh.payload",
780         FT_BYTES, BASE_NONE, NULL, 0x0,
781         "SSH Payload", HFILL }},
782
783     { &hf_ssh_padding_string,
784       { "Padding String",         "ssh.padding_string",
785         FT_STRING, BASE_NONE, NULL, 0x0,
786         "SSH Padding String", HFILL }},
787
788     { &hf_ssh_mac_string,
789       { "MAC String",     "ssh.mac_string",
790         FT_STRING, BASE_NONE, NULL, 0x0,
791         "SSH MAC String", HFILL }},
792
793   { &hf_ssh_kex_algorithms,
794       { "kex_algorithms string",         "ssh.kex_algorithms",
795         FT_STRINGZ, BASE_NONE, NULL, 0x0,
796         "SSH kex_algorithms string", HFILL }},
797
798   { &hf_ssh_server_host_key_algorithms,
799       { "server_host_key_algorithms string",         "ssh.server_host_key_algorithms",
800         FT_STRINGZ, BASE_NONE, NULL, 0x0,
801         "SSH server_host_key_algorithms string", HFILL }},
802
803   { &hf_ssh_encryption_algorithms_client_to_server,
804       { "encryption_algorithms_client_to_server string",         "ssh.encryption_algorithms_client_to_server",
805         FT_STRINGZ, BASE_NONE, NULL, 0x0,
806         "SSH encryption_algorithms_client_to_server string", HFILL }},
807
808   { &hf_ssh_encryption_algorithms_server_to_client,
809       { "encryption_algorithms_server_to_client string",         "ssh.encryption_algorithms_server_to_client",
810         FT_STRINGZ, BASE_NONE, NULL, 0x0,
811         "SSH encryption_algorithms_server_to_client string", HFILL }},
812
813   { &hf_ssh_mac_algorithms_client_to_server,
814       { "mac_algorithms_client_to_server string",         "ssh.mac_algorithms_client_to_server",
815         FT_STRINGZ, BASE_NONE, NULL, 0x0,
816         "SSH mac_algorithms_client_to_server string", HFILL }},
817
818   { &hf_ssh_mac_algorithms_server_to_client,
819       { "mac_algorithms_server_to_client string",         "ssh.mac_algorithms_server_to_client",
820         FT_STRINGZ, BASE_NONE, NULL, 0x0,
821         "SSH mac_algorithms_server_to_client string", HFILL }},
822
823   { &hf_ssh_compression_algorithms_client_to_server,
824       { "compression_algorithms_client_to_server string",         "ssh.compression_algorithms_client_to_server",
825         FT_STRINGZ, BASE_NONE, NULL, 0x0,
826         "SSH compression_algorithms_client_to_server string", HFILL }},
827
828   { &hf_ssh_compression_algorithms_server_to_client,
829       { "compression_algorithms_server_to_client string",         "ssh.compression_algorithms_server_to_client",
830         FT_STRINGZ, BASE_NONE, NULL, 0x0,
831         "SSH compression_algorithms_server_to_client string", HFILL }},
832
833   { &hf_ssh_languages_client_to_server,
834       { "languages_client_to_server string",         "ssh.languages_client_to_server",
835         FT_STRINGZ, BASE_NONE, NULL, 0x0,
836         "SSH languages_client_to_server string", HFILL }},
837
838   { &hf_ssh_languages_server_to_client,
839       { "languages_server_to_client string",         "ssh.languages_server_to_client",
840         FT_STRINGZ, BASE_NONE, NULL, 0x0,
841         "SSH languages_server_to_client string", HFILL }},
842
843   { &hf_ssh_kex_algorithms_length,
844       { "kex_algorithms length",         "ssh.kex_algorithms_length",
845         FT_UINT32, BASE_DEC, NULL, 0x0,
846         "SSH kex_algorithms length", HFILL }},
847
848   { &hf_ssh_server_host_key_algorithms_length,
849       { "server_host_key_algorithms length",         "ssh.server_host_key_algorithms_length",
850         FT_UINT32, BASE_DEC, NULL, 0x0,
851         "SSH server_host_key_algorithms length", HFILL }},
852
853   { &hf_ssh_encryption_algorithms_client_to_server_length,
854       { "encryption_algorithms_client_to_server length",         "ssh.encryption_algorithms_client_to_server_length",
855         FT_UINT32, BASE_DEC, NULL, 0x0,
856         "SSH encryption_algorithms_client_to_server length", HFILL }},
857
858   { &hf_ssh_encryption_algorithms_server_to_client_length,
859       { "encryption_algorithms_server_to_client length",         "ssh.encryption_algorithms_server_to_client_length",
860         FT_UINT32, BASE_DEC, NULL, 0x0,
861         "SSH encryption_algorithms_server_to_client length", HFILL }},
862
863   { &hf_ssh_mac_algorithms_client_to_server_length,
864       { "mac_algorithms_client_to_server length",         "ssh.mac_algorithms_client_to_server_length",
865         FT_UINT32, BASE_DEC, NULL, 0x0,
866         "SSH mac_algorithms_client_to_server length", HFILL }},
867
868   { &hf_ssh_mac_algorithms_server_to_client_length,
869       { "mac_algorithms_server_to_client length",         "ssh.mac_algorithms_server_to_client_length",
870         FT_UINT32, BASE_DEC, NULL, 0x0,
871         "SSH mac_algorithms_server_to_client length", HFILL }},
872
873   { &hf_ssh_compression_algorithms_client_to_server_length,
874       { "compression_algorithms_client_to_server length",         "ssh.compression_algorithms_client_to_server_length",
875         FT_UINT32, BASE_DEC, NULL, 0x0,
876         "SSH compression_algorithms_client_to_server length", HFILL }},
877
878   { &hf_ssh_compression_algorithms_server_to_client_length,
879       { "compression_algorithms_server_to_client length",         "ssh.compression_algorithms_server_to_client_length",
880         FT_UINT32, BASE_DEC, NULL, 0x0,
881         "SSH compression_algorithms_server_to_client length", HFILL }},
882
883   { &hf_ssh_languages_client_to_server_length,
884       { "languages_client_to_server length",         "ssh.languages_client_to_server_length",
885         FT_UINT32, BASE_DEC, NULL, 0x0,
886         "SSH languages_client_to_server length", HFILL }},
887
888   { &hf_ssh_languages_server_to_client_length,
889       { "languages_server_to_client length",         "ssh.languages_server_to_client_length",
890         FT_UINT32, BASE_DEC, NULL, 0x0,
891         "SSH languages_server_to_client length", HFILL }},
892
893
894         };
895         static gint *ett[] = {
896                 &ett_ssh,
897                 &ett_key_exchange,
898                 &ett_ssh1,
899                 &ett_ssh2,
900                 &ett_key_init
901         };
902         module_t *ssh_module;
903
904         proto_ssh = proto_register_protocol("SSH Protocol",
905                                        "SSH", "ssh");
906          proto_register_field_array(proto_ssh, hf, array_length(hf));
907         proto_register_subtree_array(ett, array_length(ett));
908
909         ssh_module = prefs_register_protocol(proto_ssh, NULL);
910         prefs_register_bool_preference(ssh_module, "desegment_buffers",
911                 "Reassemble SSH buffers spanning multiple TCP segments",
912                 "Whether the SSH dissector should reassemble SSH buffers spanning multiple TCP segments. "
913             "To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
914                 &ssh_desegment);
915 }
916
917 void
918 proto_reg_handoff_ssh(void)
919 {
920         dissector_handle_t ssh_handle;
921
922         ssh_handle = create_dissector_handle(dissect_ssh, proto_ssh);
923
924         dissector_add("tcp.port", TCP_PORT_SSH, ssh_handle);
925 }