As the gtk2 directory is no longer needed (GTK1 and 2 are using the same sources...
[obnox/wireshark/wip.git] / epan / dissectors / packet-eap.c
1 /* packet-eap.c
2  * Routines for EAP Extensible Authentication Protocol dissection
3  * RFC 2284, RFC 3748
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/conversation.h>
33 #include "ppptypes.h"
34 #include "reassemble.h"
35
36 static int proto_eap = -1;
37 static int hf_eap_code = -1;
38 static int hf_eap_identifier = -1;
39 static int hf_eap_len = -1;
40 static int hf_eap_type = -1;
41 static int hf_eap_type_nak = -1;
42
43 static gint ett_eap = -1;
44
45 static dissector_handle_t ssl_handle;
46
47 #define EAP_REQUEST     1
48 #define EAP_RESPONSE    2
49 #define EAP_SUCCESS     3
50 #define EAP_FAILURE     4
51
52 static const value_string eap_code_vals[] = {
53     { EAP_REQUEST,  "Request" },
54     { EAP_RESPONSE, "Response" },
55     { EAP_SUCCESS,  "Success" },
56     { EAP_FAILURE,  "Failure" },
57     { 0,            NULL }
58 };
59
60 /*
61 References:
62   1) http://www.iana.org/assignments/ppp-numbers
63                         PPP EAP REQUEST/RESPONSE TYPES
64   2) http://www.ietf.org/internet-drafts/draft-ietf-pppext-rfc2284bis-02.txt
65   3) RFC2284
66   4) RFC3748
67   5) http://www.iana.org/assignments/eap-numbers        EAP registry
68 */
69
70 #define EAP_TYPE_ID     1
71 #define EAP_TYPE_NOTIFY 2
72 #define EAP_TYPE_NAK    3
73 #define EAP_TYPE_MD5    4
74 #define EAP_TYPE_TLS    13
75 #define EAP_TYPE_LEAP   17
76 #define EAP_TYPE_SIM    18
77 #define EAP_TYPE_TTLS   21
78 #define EAP_TYPE_PEAP   25
79 #define EAP_TYPE_MSCHAPV2 26
80
81 static const value_string eap_type_vals[] = {
82   {EAP_TYPE_ID,  "Identity [RFC3748]" },
83   {EAP_TYPE_NOTIFY,"Notification [RFC3748]" },
84   {EAP_TYPE_NAK, "Nak (Response only) [RFC3748]" },
85   {EAP_TYPE_MD5, "MD5-Challenge [RFC3748]" },
86   {  5,          "One Time Password (OTP) [RFC2289]" },
87   {  6,          "Generic Token Card [RFC3748]" },
88   {  7,          "?? RESERVED ?? " }, /* ??? */
89   {  8,          "?? RESERVED ?? " }, /* ??? */
90   {  9,          "RSA Public Key Authentication [Whelan]" },
91   { 10,          "DSS Unilateral [Nace]" },
92   { 11,          "KEA [Nace]" },
93   { 12,          "KEA-VALIDATE [Nace]" },
94   {EAP_TYPE_TLS, "EAP-TLS [RFC2716] [Aboba]" },
95   { 14,          "Defender Token (AXENT) [Rosselli]" },
96   { 15,          "RSA Security SecurID EAP [Asnes, Liberman]" },
97   { 16,          "Arcot Systems EAP [Jerdonek]" },
98   {EAP_TYPE_LEAP,"EAP-Cisco Wireless (LEAP) [Norman]" },
99   {EAP_TYPE_SIM, "EAP-SIM Nokia IP smart card authentication [Haverinen]" },
100   { 19,          "SRP-SHA1 Part 1 [Carlson]" },
101   { 20,          "SRP-SHA1 Part 2 [Carlson]" },
102   {EAP_TYPE_TTLS,"EAP-TTLS [Funk]" },
103   { 22,          "Remote Access Service [Fields]" },
104   { 23,          "UMTS Authentication and Key Agreement [Haverinen]" },
105   { 24,          "EAP-3Com Wireless [Young]" },
106   {EAP_TYPE_PEAP,"PEAP [Palekar]" },
107   {EAP_TYPE_MSCHAPV2,"MS-EAP-Authentication [Palekar]" },
108   { 27,          "Mutual Authentication w/Key Exchange (MAKE)[Berrendonner]" },
109   { 28,          "CRYPTOCard [Webb]" },
110   { 29,          "EAP-MSCHAP-V2 [Potter]" },
111   { 30,          "DynamID [Merlin]" },
112   { 31,          "Rob EAP [Ullah]" },
113   { 32,          "SecurID EAP [Josefsson]" },
114   { 33,          "MS-Authentication-TLV [Palekar]" },
115   { 34,          "SentriNET [Kelleher]" },
116   { 35,          "EAP-Actiontec Wireless [Chang]" },
117   { 36,          "Cogent Systems Biometrics Authentication EAP [Xiong]" },
118   { 37,          "AirFortress EAP [Hibbard]" },
119   { 38,          "EAP-HTTP Digest [Tavakoli]" },
120   { 39,          "SecureSuite EAP [Clements]" },
121   { 40,          "DeviceConnect EAP [Pitard]" },
122   { 41,          "EAP-SPEKE [Zick]" },
123   { 42,          "EAP-MOBAC [Rixom]" },
124   { 43,          "EAP-FAST [Cam-Winget]" },
125   { 44,          "ZoneLabs EAP (ZLXEAP) [Bogue]" },
126   { 45,          "EAP-Link [Zick]" },
127   { 254,         "RESERVED for the Expanded Type [RFC3748]" },
128   { 255,         "EXPERIMENTAL [RFC3748]" },
129   { 0,          NULL }
130
131 };
132
133 /*
134  * State information for EAP-TLS (RFC2716) and Lightweight EAP:
135  *
136  *      http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
137  *
138  * Attach to all conversations:
139  *
140  *      a sequence number to be handed to "fragment_add_seq()" as
141  *      the fragment sequence number - if it's -1, no reassembly
142  *      is in progress, but if it's not, it's the sequence number
143  *      to use for the current fragment;
144  *
145  *      a value to be handed to "fragment_add_seq()" as the
146  *      reassembly ID - when a reassembly is started, it's set to
147  *      the frame number of the current frame, i.e. the frame
148  *      that starts the reassembly;
149  *
150  *      an indication of the current state of LEAP negotiation,
151  *      with -1 meaning no LEAP negotiation is in progress.
152  *
153  * Attach to frames containing fragments of EAP-TLS messages the
154  * reassembly ID for those fragments, so we can find the reassembled
155  * data after the first pass through the packets.
156  *
157  * Attach to LEAP frames the state of the LEAP negotiation when the
158  * frame was processed, so we can properly dissect
159  * the LEAP message after the first pass through the packets.
160  *
161  * Attach to all conversations both pieces of information, to keep
162  * track of EAP-TLS reassembly and the LEAP state machine.
163  */
164 static GMemChunk *conv_state_chunk = NULL;
165
166 typedef struct {
167         int     eap_tls_seq;
168         guint32 eap_reass_cookie;
169         int     leap_state;
170 } conv_state_t;
171
172 static GMemChunk *frame_state_chunk = NULL;
173
174 typedef struct {
175         int     info;   /* interpretation depends on EAP message type */
176 } frame_state_t;
177
178 /*********************************************************************
179                            EAP-TLS
180 RFC2716
181 **********************************************************************/
182
183 /*
184 from RFC2716, pg 17
185
186    Flags
187
188       0 1 2 3 4 5 6 7 8
189       +-+-+-+-+-+-+-+-+
190       |L M S R R Vers |
191       +-+-+-+-+-+-+-+-+
192
193       L = Length included
194       M = More fragments
195       S = EAP-TLS start
196       R = Reserved
197       Vers = PEAP version (Reserved for TLS and TTLS)
198 */
199
200 #define EAP_TLS_FLAG_L 0x80 /* Length included */
201 #define EAP_TLS_FLAG_M 0x40 /* More fragments  */
202 #define EAP_TLS_FLAG_S 0x20 /* EAP-TLS start   */
203 #define EAP_PEAP_FLAG_VERSION 0x07 /* EAP-PEAP version */
204
205 /*
206  * reassembly of EAP-TLS
207  */
208 static GHashTable *eaptls_fragment_table = NULL;
209
210 static int   hf_eaptls_fragment  = -1;
211 static int   hf_eaptls_fragments = -1;
212 static int   hf_eaptls_fragment_overlap = -1;
213 static int   hf_eaptls_fragment_overlap_conflict = -1;
214 static int   hf_eaptls_fragment_multiple_tails = -1;
215 static int   hf_eaptls_fragment_too_long_fragment = -1;
216 static int   hf_eaptls_fragment_error = -1;
217 static gint ett_eaptls_fragment  = -1;
218 static gint ett_eaptls_fragments = -1;
219 static gint ett_eap_sim_attr = -1;
220
221 static const fragment_items eaptls_frag_items = {
222         &ett_eaptls_fragment,
223         &ett_eaptls_fragments,
224         &hf_eaptls_fragments,
225         &hf_eaptls_fragment,
226         &hf_eaptls_fragment_overlap,
227         &hf_eaptls_fragment_overlap_conflict,
228         &hf_eaptls_fragment_multiple_tails,
229         &hf_eaptls_fragment_too_long_fragment,
230         &hf_eaptls_fragment_error,
231         NULL,
232         "fragments"
233 };
234
235 /*********************************************************************
236 **********************************************************************/
237
238 static gboolean
239 test_flag(unsigned char flag, unsigned char mask)
240 {
241   return ( ( flag & mask ) != 0 );
242 }
243
244 static void
245 eaptls_defragment_init(void)
246 {
247   fragment_table_init(&eaptls_fragment_table);
248 }
249
250 static void
251 eap_init_protocol(void)
252 {
253   if (conv_state_chunk != NULL)
254     g_mem_chunk_destroy(conv_state_chunk);
255   if (frame_state_chunk != NULL)
256     g_mem_chunk_destroy(frame_state_chunk);
257
258   conv_state_chunk = g_mem_chunk_new("conv_state_chunk",
259                                      sizeof (conv_state_t),
260                                      10 * sizeof (conv_state_t),
261                                      G_ALLOC_ONLY);
262
263   frame_state_chunk = g_mem_chunk_new("frame_state_chunk",
264                                       sizeof (frame_state_t),
265                                      100 * sizeof (frame_state_t),
266                                      G_ALLOC_ONLY);
267 }
268
269 static void
270 dissect_eap_mschapv2(proto_tree *eap_tree, tvbuff_t *tvb, int offset,
271                      gint size)
272 {
273         gint left = size;
274         gint ms_len;
275         guint8 value_size;
276         enum {
277                 MS_CHAPv2_CHALLENGE = 1,
278                 MS_CHAPv2_RESPONSE = 2,
279                 MS_CHAPv2_SUCCESS = 3,
280                 MS_CHAPv2_FAILURE = 4,
281                 MS_CHAPv2_CHANGE_PASSWORD = 5
282         } opcode;
283         static const value_string opcodes[] = {
284                 { MS_CHAPv2_CHALLENGE, "Challenge" },
285                 { MS_CHAPv2_RESPONSE, "Response" },
286                 { MS_CHAPv2_SUCCESS, "Success" },
287                 { MS_CHAPv2_FAILURE, "Failure" },
288                 { MS_CHAPv2_CHANGE_PASSWORD, "Change-Password" },
289                 { 0, NULL }
290         };
291
292         /* OpCode (1 byte), MS-CHAPv2-ID (1 byte), MS-Length (2 bytes), Data */
293         opcode = tvb_get_guint8(tvb, offset);
294         proto_tree_add_text(eap_tree, tvb, offset, 1,
295                             "OpCode: %d (%s)", 
296                             opcode, val_to_str(opcode, opcodes, "Unknown"));
297         offset++;
298         left--;
299         if (left <= 0)
300                 return;
301
302         proto_tree_add_text(eap_tree, tvb, offset, 1, "MS-CHAPv2-ID: %d",
303                             tvb_get_guint8(tvb, offset));
304         offset++;
305         left--;
306         if (left <= 0)
307                 return;
308
309         ms_len = tvb_get_ntohs(tvb, offset);
310         proto_tree_add_text(eap_tree, tvb, offset, 2, "MS-Length: %d%s",
311                             ms_len,
312                             ms_len != size ? " (invalid len)" : "");
313         offset += 2;
314         left -= 2;
315
316         switch (opcode) {
317         case MS_CHAPv2_CHALLENGE:
318                 if (left <= 0)
319                         break;
320                 value_size = tvb_get_guint8(tvb, offset);
321                 proto_tree_add_text(eap_tree, tvb, offset, 1,
322                                     "Value-Size: %d", value_size);
323                 offset++;
324                 left--;
325                 proto_tree_add_text(eap_tree, tvb, offset, value_size,
326                                     "Challenge: %s",
327                                     tvb_bytes_to_str(tvb, offset, value_size));
328                 offset += value_size;
329                 left -= value_size;
330                 if (left <= 0)
331                         break;
332                 proto_tree_add_text(eap_tree, tvb, offset, left,
333                                     "Name: %s",
334                                     tvb_format_text(tvb, offset, left));
335                 break;
336         case MS_CHAPv2_RESPONSE:
337                 if (left <= 0)
338                         break;
339                 value_size = tvb_get_guint8(tvb, offset);
340                 proto_tree_add_text(eap_tree, tvb, offset, 1,
341                                     "Value-Size: %d", value_size);
342                 offset++;
343                 left--;
344                 if (value_size == 49) {
345                         proto_tree_add_text(eap_tree, tvb, offset, 16,
346                                             "Peer-Challenge: %s",
347                                             tvb_bytes_to_str(tvb, offset, 16));
348                         offset += 16;
349                         proto_tree_add_text(eap_tree, tvb, offset, 8,
350                                             "Reserved, must be zero: %s",
351                                             tvb_bytes_to_str(tvb, offset, 8));
352                         offset += 8;
353                         proto_tree_add_text(eap_tree, tvb, offset, 24,
354                                             "NT-Response: %s",
355                                             tvb_bytes_to_str(tvb, offset, 24));
356                         offset += 24;
357                         proto_tree_add_text(eap_tree, tvb, offset, 1,
358                                             "Flags: %d",
359                                             tvb_get_guint8(tvb, offset));
360                         offset++;
361                         left -= value_size;
362                 } else {
363                         proto_tree_add_text(eap_tree, tvb, offset, value_size,
364                                             "Response (unknown length): %s",
365                                             tvb_bytes_to_str(tvb, offset,
366                                                              value_size));
367                         offset += value_size;
368                         left -= value_size;
369                 }
370                 if (left <= 0)
371                         break;
372                 proto_tree_add_text(eap_tree, tvb, offset, left,
373                                     "Name: %s",
374                                     tvb_format_text(tvb, offset, left));
375                 break;
376         case MS_CHAPv2_SUCCESS:
377                 if (left <= 0)
378                         break;
379                 proto_tree_add_text(eap_tree, tvb, offset, left,
380                                     "Message: %s",
381                                     tvb_format_text(tvb, offset, left));
382                 break;
383         case MS_CHAPv2_FAILURE:
384                 if (left <= 0)
385                         break;
386                 proto_tree_add_text(eap_tree, tvb, offset, left,
387                                     "Failure Request: %s",
388                                     tvb_format_text(tvb, offset, left));
389                 break;
390         default:
391                 proto_tree_add_text(eap_tree, tvb, offset, left,
392                                     "Data (%d byte%s) Value: %s",
393                                     left, plurality(left, "", "s"),
394                                     tvb_bytes_to_str(tvb, offset, left));
395                 break;
396         }
397 }
398
399 static void
400 dissect_eap_sim(proto_tree *eap_tree, tvbuff_t *tvb, int offset, gint size)
401 {
402         gint left = size;
403         enum {
404                 SIM_START = 10,
405                 SIM_CHALLENGE = 11,
406                 SIM_NOTIFICATION = 12,
407                 SIM_RE_AUTHENTICATION = 13,
408                 SIM_CLIENT_ERROR = 14
409         } subtype;
410         static const value_string subtypes[] = {
411                 { SIM_START, "Start" },
412                 { SIM_CHALLENGE, "Challenge" },
413                 { SIM_NOTIFICATION, "Notification" },
414                 { SIM_RE_AUTHENTICATION, "Re-authentication" },
415                 { SIM_CLIENT_ERROR, "Client-Error" },
416                 { 0, NULL }
417         };
418         static const value_string attributes[] = {
419                 { 1, "AT_RAND" },
420                 { 6, "AT_PADDING" },
421                 { 7, "AT_NONCE_MT" },
422                 { 10, "AT_PERMANENT_ID_REQ" },
423                 { 11, "AT_MAC" },
424                 { 12, "AT_NOTIFICATION" },
425                 { 13, "AT_ANY_ID_REQ" },
426                 { 14, "AT_IDENTITY" },
427                 { 15, "AT_VERSION_LIST" },
428                 { 16, "AT_SELECTED_VERSION" },
429                 { 17, "AT_FULLAUTH_ID_REQ" },
430                 { 18, "AT_COUNTER" },
431                 { 19, "AT_COUNTER_TOO_SMALL" },
432                 { 20, "AT_NONCE_S" },
433                 { 21, "AT_CLIENT_ERROR_CODE" },
434                 { 129, "AT_IV" },
435                 { 130, "AT_ENCR_DATA" },
436                 { 132, "AT_NEXT_PSEUDONYM" },
437                 { 133, "AT_NEXT_REAUTH_ID" },
438                 { 0, NULL }
439         };
440
441         subtype = tvb_get_guint8(tvb, offset);
442         proto_tree_add_text(eap_tree, tvb, offset, 1,
443                             "subtype: %d (%s)", 
444                             subtype, val_to_str(subtype, subtypes, "Unknown"));
445
446         offset++;
447         left--;
448
449         if (left < 2)
450                 return;
451         proto_tree_add_text(eap_tree, tvb, offset, 2, "Reserved: %d",
452                             tvb_get_ntohs(tvb, offset));
453         offset += 2;
454         left -= 2;
455
456         /* Rest of EAP-SIM data is in Type-Len-Value format. */
457         while (left >= 2) {
458                 guint8 type, length;
459                 proto_item *pi;
460                 proto_tree *attr_tree;
461                 int aoffset;
462                 gint aleft;
463                 aoffset = offset;
464                 type = tvb_get_guint8(tvb, aoffset);
465                 length = tvb_get_guint8(tvb, aoffset + 1);
466                 aleft = 4 * length;
467
468                 pi = proto_tree_add_text(eap_tree, tvb, aoffset, aleft,
469                                          "Attribute: %s", 
470                                          val_to_str(type, attributes,
471                                                     "Unknown %u"));
472                 attr_tree = proto_item_add_subtree(pi, ett_eap_sim_attr);
473                 proto_tree_add_text(attr_tree, tvb, aoffset, 1,
474                                     "Type: %u", type);
475                 aoffset++;
476                 aleft--;
477
478                 if (aleft <= 0)
479                         break;
480                 proto_tree_add_text(attr_tree, tvb, aoffset, 1,
481                                     "Length: %d (%d bytes)",
482                                     length, 4 * length);
483                 aoffset++;
484                 aleft--;
485                 proto_tree_add_text(attr_tree, tvb, aoffset, aleft,
486                                     "Value: %s",
487                                     tvb_bytes_to_str(tvb, aoffset, aleft));
488
489                 offset += 4 * length;
490                 left -= 4 * length;
491         }
492 }
493
494 static int
495 dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
496                  gboolean fragmented)
497 {
498   guint8      eap_code;
499   guint8      eap_id;
500   guint16     eap_len;
501   guint8      eap_type;
502   gint        len;
503   conversation_t *conversation;
504   conv_state_t *conversation_state;
505   frame_state_t *packet_state;
506   int leap_state;
507   proto_tree *ti;
508   proto_tree *eap_tree = NULL;
509
510   if (check_col(pinfo->cinfo, COL_PROTOCOL))
511     col_set_str(pinfo->cinfo, COL_PROTOCOL, "EAP");
512   if (check_col(pinfo->cinfo, COL_INFO))
513     col_clear(pinfo->cinfo, COL_INFO);
514
515   eap_code = tvb_get_guint8(tvb, 0);
516
517   if (check_col(pinfo->cinfo, COL_INFO))
518     col_add_str(pinfo->cinfo, COL_INFO,
519                 val_to_str(eap_code, eap_code_vals, "Unknown code (0x%02X)"));
520
521   /*
522    * Find a conversation to which we belong; create one if we don't find
523    * it.
524    *
525    * We use the source and destination addresses, and the *matched* port
526    * number, because if this is running over RADIUS, there's no guarantee
527    * that the source port number for request and the destination port
528    * number for replies will be the same in all messages - the client
529    * may use different port numbers for each request.
530    *
531    * We have to pair up the matched port number with the corresponding
532    * address; we determine which that is by comparing it with the
533    * destination port - if it matches, we matched on the destination
534    * port (this is a request), otherwise we matched on the source port
535    * (this is a reply).
536    *
537    * XXX - what if we're running over a TCP or UDP protocol with a
538    * heuristic dissector, meaning the matched port number won't be set?
539    *
540    * XXX - what if we have a capture file with captures on multiple
541    * PPP interfaces, with LEAP traffic on all of them?  How can we
542    * keep them separate?  (Or is that not going to happen?)
543    */
544   if (pinfo->destport == pinfo->match_port) {
545     conversation = find_conversation(&pinfo->dst, &pinfo->src,
546                                      pinfo->ptype, pinfo->destport,
547                                      0, NO_PORT_B);
548   } else {
549     conversation = find_conversation(&pinfo->src, &pinfo->dst,
550                                      pinfo->ptype, pinfo->srcport,
551                                      0, NO_PORT_B);
552   }
553   if (conversation == NULL) {
554     if (pinfo->destport == pinfo->match_port) {
555       conversation = conversation_new(&pinfo->dst, &pinfo->src,
556                                       pinfo->ptype, pinfo->destport,
557                                       0, NO_PORT2);
558     } else {
559       conversation = conversation_new(&pinfo->src, &pinfo->dst,
560                                       pinfo->ptype, pinfo->srcport,
561                                       0, NO_PORT2);
562     }
563   }
564
565   /*
566    * Get the state information for the conversation; attach some if
567    * we don't find it.
568    */
569   conversation_state = conversation_get_proto_data(conversation, proto_eap);
570   if (conversation_state == NULL) {
571     /*
572      * Attach state information to the conversation.
573      */
574     conversation_state = g_mem_chunk_alloc(conv_state_chunk);
575     conversation_state->eap_tls_seq = -1;
576     conversation_state->eap_reass_cookie = 0;
577     conversation_state->leap_state = -1;
578     conversation_add_proto_data(conversation, proto_eap, conversation_state);
579   }
580
581   /*
582    * Set this now, so that it gets remembered even if we throw an exception
583    * later.
584    */
585   if (eap_code == EAP_FAILURE)
586     conversation_state->leap_state = -1;
587
588   eap_id = tvb_get_guint8(tvb, 1);
589
590   eap_len = tvb_get_ntohs(tvb, 2);
591   len = eap_len;
592
593   if (fragmented) {
594     /*
595      * This is an EAP fragment inside, for example, RADIUS.  If we don't
596      * have all of the packet data, return the negative of the amount of
597      * additional data we need.
598      */
599     int reported_len = tvb_reported_length_remaining(tvb, 0);
600
601     if (reported_len < len)
602       return -(len - reported_len);
603   }
604
605   if (tree) {
606     ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE);
607     eap_tree = proto_item_add_subtree(ti, ett_eap);
608
609     proto_tree_add_uint(eap_tree, hf_eap_code, tvb, 0, 1, eap_code);
610   }
611
612   if (tree)
613     proto_tree_add_item(eap_tree, hf_eap_identifier, tvb, 1, 1, FALSE);
614
615   if (tree)
616     proto_tree_add_uint(eap_tree, hf_eap_len, tvb, 2, 2, eap_len);
617
618   switch (eap_code) {
619
620   case EAP_SUCCESS:
621   case EAP_FAILURE:
622     break;
623
624   case EAP_REQUEST:
625   case EAP_RESPONSE:
626     eap_type = tvb_get_guint8(tvb, 4);
627
628     if (check_col(pinfo->cinfo, COL_INFO))
629       col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
630                       val_to_str(eap_type, eap_type_vals,
631                                  "Unknown type (0x%02X)"));
632     if (tree)
633       proto_tree_add_uint(eap_tree, hf_eap_type, tvb, 4, 1, eap_type);
634
635     if (len > 5) {
636       int     offset = 5;
637       gint    size   = len - offset;
638
639       switch (eap_type) {
640       /*********************************************************************
641       **********************************************************************/
642       case EAP_TYPE_ID:
643         if (tree) {
644           proto_tree_add_text(eap_tree, tvb, offset, size,
645                               "Identity (%d byte%s): %s",
646                               size, plurality(size, "", "s"),
647                               tvb_format_text(tvb, offset, size));
648          }
649         if(!pinfo->fd->flags.visited)
650           conversation_state->leap_state = 0;
651         break;
652
653       /*********************************************************************
654       **********************************************************************/
655       case EAP_TYPE_NOTIFY:
656         if (tree) {
657           proto_tree_add_text(eap_tree, tvb, offset, size,
658                               "Notification (%d byte%s): %s",
659                               size, plurality(size, "", "s"),
660                               tvb_format_text(tvb, offset, size));
661         }
662         break;
663       /*********************************************************************
664       **********************************************************************/
665       case EAP_TYPE_NAK:
666         if (tree) {
667           proto_tree_add_item(eap_tree, hf_eap_type_nak, tvb,
668                               offset, 1, FALSE);
669         }
670         break;
671       /*********************************************************************
672       **********************************************************************/
673       case EAP_TYPE_MD5:
674         if (tree) {
675           guint8 value_size = tvb_get_guint8(tvb, offset);
676           gint extra_len = size - 1 - value_size;
677           proto_tree_add_text(eap_tree, tvb, offset, 1, "Value-Size: %d%s",
678                               value_size,
679                               value_size > size - 1 ? " (overflow)": "");
680           if (value_size > size - 1)
681             value_size = size - 1;
682           offset++;
683           proto_tree_add_text(eap_tree, tvb, offset, value_size,
684                               "Value: %s",
685                               tvb_bytes_to_str(tvb, offset, value_size));
686           offset += value_size;
687           if (extra_len > 0) {
688             proto_tree_add_text(eap_tree, tvb, offset, extra_len,
689                                 "Extra data (%d byte%s): %s", extra_len,
690                                 plurality(extra_len, "", "s"),
691                                 tvb_bytes_to_str(tvb, offset, extra_len));
692           }
693         }
694         break;
695       /*********************************************************************
696                                   EAP-TLS
697       **********************************************************************/
698       case EAP_TYPE_PEAP:
699       case EAP_TYPE_TTLS:
700       case EAP_TYPE_TLS:
701         {
702         guint8 flags   = tvb_get_guint8(tvb, offset);
703         gboolean more_fragments;
704         gboolean has_length;
705         guint32 length;
706         int eap_tls_seq = -1;
707         guint32 eap_reass_cookie = 0;
708         gboolean needs_reassembly = FALSE;
709
710         more_fragments = test_flag(flags,EAP_TLS_FLAG_M);
711         has_length = test_flag(flags,EAP_TLS_FLAG_L);
712
713         /* Flags field, 1 byte */
714         if (tree) {
715           proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(0x%X): %s%s%s",
716                               flags,
717                               has_length                      ? "Length ":"",
718                               more_fragments                  ? "More "  :"",
719                               test_flag(flags,EAP_TLS_FLAG_S) ? "Start " :"");
720           if (eap_type == EAP_TYPE_PEAP) {
721             proto_tree_add_text(eap_tree, tvb, offset, 1,
722                                 "PEAP version %d",
723                                 flags & EAP_PEAP_FLAG_VERSION);
724           }
725         }
726         size--;
727         offset++;
728
729         /* Length field, 4 bytes, OPTIONAL. */
730         if ( has_length ) {
731           length = tvb_get_ntohl(tvb, offset);
732           if (tree)
733             proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",length);
734           size   -= 4;
735           offset += 4;
736         }
737
738         if (size>0) {
739
740           tvbuff_t *next_tvb;
741           gint tvb_len;
742           gboolean save_fragmented;
743
744           tvb_len = tvb_length_remaining(tvb, offset);
745           if (size < tvb_len)
746             tvb_len = size;
747
748             /*
749                EAP/TLS is weird protocol (it comes from
750                Microsoft after all).
751
752                If we have series of fragmented packets,
753                then there's no way of knowing that from
754                the packet itself, if it is the last packet
755                in series, that is that the packet part of
756                bigger fragmented set of data.
757
758                The only way to know is, by knowing
759                that we are already in defragmentation
760                "mode" and we are expecing packet
761                carrying fragment of data. (either
762                because we have not received expected
763                amount of data, or because the packet before
764                had "F"ragment flag set.)
765
766                The situation is alleviated by fact that it
767                is simple ack/nack protcol so there's no
768                place for out-of-order packets like it is
769                possible with IP.
770
771                Anyway, point of this lengthy essay is that
772                we have to keep state information in the
773                conversation, so that we can put ourselves in
774                defragmenting mode and wait for the last packet,
775                and have to attach state to frames as well, so
776                that we can handle defragmentation after the
777                first pass through the capture.
778             */
779           /* See if we have a remembered defragmentation EAP ID. */
780           packet_state = p_get_proto_data(pinfo->fd, proto_eap);
781           if (packet_state == NULL) {
782             /*
783              * We haven't - does this message require reassembly?
784              */
785             if (!pinfo->fd->flags.visited) {
786               /*
787                * This is the first time we've looked at this frame,
788                * so it wouldn't have any remembered information.
789                *
790                * Therefore, we check whether this conversation has
791                * a reassembly operation in progress, or whether
792                * this frame has the Fragment flag set.
793                */
794               if (conversation_state->eap_tls_seq != -1) {
795                 /*
796                  * There's a reassembly in progress; the sequence number
797                  * of the previous fragment is
798                  * "conversation_state->eap_tls_seq", and the reassembly
799                  * ID is "conversation_state->eap_reass_cookie".
800                  *
801                  * We must include this frame in the reassembly.
802                  * We advance the sequence number, giving us the
803                  * sequence number for this fragment.
804                  */
805                 needs_reassembly = TRUE;
806                 conversation_state->eap_tls_seq++;
807
808                 eap_reass_cookie = conversation_state->eap_reass_cookie;
809                 eap_tls_seq = conversation_state->eap_tls_seq;
810               } else if (more_fragments && has_length) {
811                 /*
812                  * This message has the Fragment flag set, so it requires
813                  * reassembly.  It's the message containing the first
814                  * fragment (if it's a later fragment, the sequence
815                  * number in the conversation state would not be -1).
816                  *
817                  * If it doesn't include a length, however, we can't
818                  * do reassembly (either the message is in error, as
819                  * the first fragment *must* contain a length, or we
820                  * didn't capture the first fragment, and this just
821                  * happens to be the first fragment we saw), so we
822                  * also check that we have a length;
823                  */
824                 needs_reassembly = TRUE;
825                 conversation_state->eap_reass_cookie = pinfo->fd->num;
826
827                 /*
828                  * Start the reassembly sequence number at 0.
829                  */
830                 conversation_state->eap_tls_seq = 0;
831
832                 eap_tls_seq = conversation_state->eap_tls_seq;
833                 eap_reass_cookie = conversation_state->eap_reass_cookie;
834               }
835
836               if (needs_reassembly) {
837                 /*
838                  * This frame requires reassembly; remember the reassembly
839                  * ID for subsequent accesses to it.
840                  */
841                 packet_state = g_mem_chunk_alloc(frame_state_chunk);
842                 packet_state->info = eap_reass_cookie;
843                 p_add_proto_data(pinfo->fd, proto_eap, packet_state);
844               }
845             }
846           } else {
847             /*
848              * This frame has a reassembly cookie associated with it, so
849              * it requires reassembly.  We've already done the
850              * reassembly in the first pass, so "fragment_add_seq()"
851              * won't look at the sequence number; set it to 0.
852              *
853              * XXX - a frame isn't supposed to have more than one
854              * EAP message in it, but if it includes both an EAP-TLS
855              * message and a LEAP message, we might be mistakenly
856              * concluding it requires reassembly because the "info"
857              * field isn't -1.  We could, I guess, pack both EAP-TLS
858              * ID and LEAP state into the structure, but that doesn't
859              * work if you have multiple EAP-TLS or LEAP messages in
860              * the frame.
861              *
862              * But it's not clear how much work we should do to handle
863              * a bogus message such as that; as long as we don't crash
864              * or do something else equally horrible, we may not
865              * have to worry about this at all.
866              */
867             needs_reassembly = TRUE;
868             eap_reass_cookie = packet_state->info;
869             eap_tls_seq = 0;
870           }
871
872           /*
873              We test here to see whether EAP-TLS packet
874              carry fragmented of TLS data.
875
876              If this is the case, we do reasembly below,
877              otherwise we just call dissector.
878           */
879           if (needs_reassembly) {
880             fragment_data   *fd_head = NULL;
881
882             /*
883              * Yes, this frame contains a fragment that requires
884              * reassembly.
885              */
886             save_fragmented = pinfo->fragmented;
887             pinfo->fragmented = TRUE;
888             fd_head = fragment_add_seq(tvb, offset, pinfo,
889                                    eap_reass_cookie,
890                                    eaptls_fragment_table,
891                                    eap_tls_seq,
892                                    size,
893                                    more_fragments);
894
895             if (fd_head != NULL)            /* Reassembled  */
896               {
897
898                 next_tvb = tvb_new_real_data(fd_head->data,
899                                              fd_head->len,
900                                              fd_head->len);
901                 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
902                 add_new_data_source(pinfo, next_tvb, "Reassembled EAP-TLS");
903
904                 show_fragment_seq_tree(fd_head, &eaptls_frag_items,
905                     eap_tree, pinfo, next_tvb);
906
907                 call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
908
909                 /*
910                  * We're finished reassembing this frame.
911                  * Reinitialize the reassembly state.
912                  */
913                 if (!pinfo->fd->flags.visited)
914                   conversation_state->eap_tls_seq = -1;
915               }
916
917             pinfo->fragmented = save_fragmented;
918
919           } else { /* this data is NOT fragmented */
920             next_tvb = tvb_new_subset(tvb, offset, tvb_len, size);
921             call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
922           }
923         }
924         }
925         break; /*  EAP_TYPE_TLS */
926       /*********************************************************************
927                                   Cisco's Lightweight EAP (LEAP)
928       http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
929       **********************************************************************/
930       case EAP_TYPE_LEAP:
931         {
932           guint8  field,count,namesize;
933
934           /* Version (byte) */
935           if (tree) {
936             field = tvb_get_guint8(tvb, offset);
937             proto_tree_add_text(eap_tree, tvb, offset, 1,
938                                 "Version: %i",field);
939           }
940           size--;
941           offset++;
942
943           /* Unused  (byte) */
944           if (tree) {
945             field = tvb_get_guint8(tvb, offset);
946             proto_tree_add_text(eap_tree, tvb, offset, 1,
947                                 "Reserved: %i",field);
948           }
949           size--;
950           offset++;
951
952           /* Count   (byte) */
953           count = tvb_get_guint8(tvb, offset);
954           if (tree) {
955             proto_tree_add_text(eap_tree, tvb, offset, 1,
956                                 "Count: %i",count);
957           }
958           size--;
959           offset++;
960
961           /* Data    (byte*Count) */
962           /* This part is state-dependent. */
963
964           /* See if we've already remembered the state. */
965           packet_state = p_get_proto_data(pinfo->fd, proto_eap);
966           if (packet_state == NULL) {
967             /*
968              * We haven't - compute the state based on the current
969              * state in the conversation.
970              */
971             leap_state = conversation_state->leap_state;
972
973             /* Advance the state machine. */
974             if (leap_state==0) leap_state =  1; else
975             if (leap_state==1) leap_state =  2; else
976             if (leap_state==2) leap_state =  3; else
977             if (leap_state==3) leap_state =  4; else
978             if (leap_state==4) leap_state = -1;
979
980             /*
981              * Remember the state for subsequent accesses to this
982              * frame.
983              */
984             packet_state = g_mem_chunk_alloc(frame_state_chunk);
985             packet_state->info = leap_state;
986             p_add_proto_data(pinfo->fd, proto_eap, packet_state);
987
988             /*
989              * Update the conversation's state.
990              */
991             conversation_state->leap_state = leap_state;
992           }
993
994           /* Get the remembered state. */
995           leap_state = packet_state->info;
996
997           if (tree) {
998
999             if        (leap_state==1) {
1000               proto_tree_add_text(eap_tree, tvb, offset, count,
1001                                   "Peer Challenge [8] Random Value:\"%s\"",
1002                                   tvb_bytes_to_str(tvb, offset, count));
1003             } else if (leap_state==2) {
1004               proto_tree_add_text(eap_tree, tvb, offset, count,
1005                                   "Peer Response [24] NtChallengeResponse(%s)",
1006                                   tvb_bytes_to_str(tvb, offset, count));
1007             } else if (leap_state==3) {
1008               proto_tree_add_text(eap_tree, tvb, offset, count,
1009                                   "AP Challenge [8] Random Value:\"%s\"",
1010                                   tvb_bytes_to_str(tvb, offset, count));
1011             } else if (leap_state==4) {
1012               proto_tree_add_text(eap_tree, tvb, offset, count,
1013                                   "AP Response [24] ChallengeResponse(%s)",
1014                                   tvb_bytes_to_str(tvb, offset, count));
1015             } else {
1016               proto_tree_add_text(eap_tree, tvb, offset, count,
1017                                 "Data (%d byte%s): \"%s\"",
1018                                 count, plurality(count, "", "s"),
1019                                 tvb_bytes_to_str(tvb, offset, count));
1020             }
1021
1022           } /* END: if (tree) */
1023
1024
1025           size   -= count;
1026           offset += count;
1027
1028           /* Name    (Length-(8+Count)) */
1029           namesize = eap_len - (8+count);
1030           if (tree) {
1031             proto_tree_add_text(eap_tree, tvb, offset, namesize,
1032                                 "Name (%d byte%s): %s",
1033                                 namesize, plurality(count, "", "s"),
1034                                 tvb_format_text(tvb, offset, namesize));
1035           }
1036           size   -= namesize;
1037           offset += namesize;
1038         }
1039
1040         break; /* EAP_TYPE_LEAP */
1041       /*********************************************************************
1042               EAP-MSCHAPv2 - draft-kamath-pppext-eap-mschapv2-00.txt
1043       **********************************************************************/
1044       case EAP_TYPE_MSCHAPV2:
1045         if (tree)
1046           dissect_eap_mschapv2(eap_tree, tvb, offset, size);
1047         break; /* EAP_TYPE_MSCHAPV2 */
1048       /*********************************************************************
1049               EAP-SIM - draft-haverinen-pppext-eap-sim-12.txt
1050       **********************************************************************/
1051       case EAP_TYPE_SIM:
1052         if (tree)
1053           dissect_eap_sim(eap_tree, tvb, offset, size);
1054         break; /* EAP_TYPE_SIM */
1055       /*********************************************************************
1056       **********************************************************************/
1057       default:
1058         if (tree) {
1059           proto_tree_add_text(eap_tree, tvb, offset, size,
1060                               "Type-Data (%d byte%s) Value: %s",
1061                               size, plurality(size, "", "s"),
1062                               tvb_bytes_to_str(tvb, offset, size));
1063         }
1064         break;
1065       /*********************************************************************
1066       **********************************************************************/
1067       } /* switch (eap_type) */
1068
1069     }
1070
1071   } /* switch (eap_code) */
1072
1073   return tvb_length(tvb);
1074 }
1075
1076 static int
1077 dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1078 {
1079   return dissect_eap_data(tvb, pinfo, tree, FALSE);
1080 }
1081
1082 static int
1083 dissect_eap_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1084 {
1085   return dissect_eap_data(tvb, pinfo, tree, TRUE);
1086 }
1087
1088 void
1089 proto_register_eap(void)
1090 {
1091   static hf_register_info hf[] = {
1092         { &hf_eap_code, {
1093                 "Code", "eap.code", FT_UINT8, BASE_DEC,
1094                 VALS(eap_code_vals), 0x0, "", HFILL }},
1095         { &hf_eap_identifier, {
1096                 "Id", "eap.id", FT_UINT8, BASE_DEC,
1097                 NULL, 0x0, "", HFILL }},
1098         { &hf_eap_len, {
1099                 "Length", "eap.len", FT_UINT16, BASE_DEC,
1100                 NULL, 0x0, "", HFILL }},
1101         { &hf_eap_type, {
1102                 "Type", "eap.type", FT_UINT8, BASE_DEC,
1103                 VALS(eap_type_vals), 0x0, "", HFILL }},
1104         { &hf_eap_type_nak, {
1105                 "Desired Auth Type", "eap.desired_type", FT_UINT8, BASE_DEC,
1106                 VALS(eap_type_vals), 0x0, "", HFILL }},
1107         { &hf_eaptls_fragment,
1108           { "EAP-TLS Fragment", "eaptls.fragment",
1109                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1110                 "EAP-TLS Fragment", HFILL }},
1111         { &hf_eaptls_fragments,
1112           { "EAP-TLS Fragments", "eaptls.fragments",
1113                 FT_NONE, BASE_NONE, NULL, 0x0,
1114                 "EAP-TLS Fragments", HFILL }},
1115         { &hf_eaptls_fragment_overlap,
1116           { "Fragment overlap", "eaptls.fragment.overlap",
1117                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1118                 "Fragment overlaps with other fragments", HFILL }},
1119         { &hf_eaptls_fragment_overlap_conflict,
1120           { "Conflicting data in fragment overlap",     "eaptls.fragment.overlap.conflict",
1121                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1122                 "Overlapping fragments contained conflicting data", HFILL }},
1123         { &hf_eaptls_fragment_multiple_tails,
1124           { "Multiple tail fragments found",    "eaptls.fragment.multipletails",
1125                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1126                 "Several tails were found when defragmenting the packet", HFILL }},
1127         { &hf_eaptls_fragment_too_long_fragment,
1128           { "Fragment too long",        "eaptls.fragment.toolongfragment",
1129                 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1130                 "Fragment contained data past end of packet", HFILL }},
1131         { &hf_eaptls_fragment_error,
1132           { "Defragmentation error", "eaptls.fragment.error",
1133                 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
1134                 "Defragmentation error due to illegal fragments", HFILL }},
1135   };
1136   static gint *ett[] = {
1137         &ett_eap,
1138         &ett_eaptls_fragment,
1139         &ett_eaptls_fragments,
1140         &ett_eap_sim_attr,
1141   };
1142
1143   proto_eap = proto_register_protocol("Extensible Authentication Protocol",
1144                                       "EAP", "eap");
1145   proto_register_field_array(proto_eap, hf, array_length(hf));
1146   proto_register_subtree_array(ett, array_length(ett));
1147   register_init_routine(&eap_init_protocol);
1148
1149   new_register_dissector("eap", dissect_eap, proto_eap);
1150   new_register_dissector("eap_fragment", dissect_eap_fragment, proto_eap);
1151   register_init_routine(eaptls_defragment_init);
1152 }
1153
1154 void
1155 proto_reg_handoff_eap(void)
1156 {
1157   dissector_handle_t eap_handle;
1158
1159   /*
1160    * Get a handle for the SSL/TLS dissector.
1161    */
1162   ssl_handle = find_dissector("ssl");
1163
1164   eap_handle = find_dissector("eap");
1165   dissector_add("ppp.protocol", PPP_EAP, eap_handle);
1166 }