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