2 * Routines for EAP Extensible Authentication Protocol dissection
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
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.
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.
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.
31 #include <epan/packet.h>
32 #include <epan/conversation.h>
34 #include "reassemble.h"
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;
43 static gint ett_eap = -1;
45 static dissector_handle_t ssl_handle;
48 #define EAP_RESPONSE 2
52 static const value_string eap_code_vals[] = {
53 { EAP_REQUEST, "Request" },
54 { EAP_RESPONSE, "Response" },
55 { EAP_SUCCESS, "Success" },
56 { EAP_FAILURE, "Failure" },
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
67 5) http://www.iana.org/assignments/eap-numbers EAP registry
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
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]" },
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]" },
134 * State information for EAP-TLS (RFC2716) and Lightweight EAP:
136 * http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
138 * Attach to all conversations:
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;
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;
150 * an indication of the current state of LEAP negotiation,
151 * with -1 meaning no LEAP negotiation is in progress.
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.
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.
161 * Attach to all conversations both pieces of information, to keep
162 * track of EAP-TLS reassembly and the LEAP state machine.
164 static GMemChunk *conv_state_chunk = NULL;
168 guint32 eap_reass_cookie;
172 static GMemChunk *frame_state_chunk = NULL;
175 int info; /* interpretation depends on EAP message type */
178 /*********************************************************************
181 **********************************************************************/
197 Vers = PEAP version (Reserved for TLS and TTLS)
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 */
206 * reassembly of EAP-TLS
208 static GHashTable *eaptls_fragment_table = NULL;
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;
221 static const fragment_items eaptls_frag_items = {
222 &ett_eaptls_fragment,
223 &ett_eaptls_fragments,
224 &hf_eaptls_fragments,
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,
235 /*********************************************************************
236 **********************************************************************/
239 test_flag(unsigned char flag, unsigned char mask)
241 return ( ( flag & mask ) != 0 );
245 eaptls_defragment_init(void)
247 fragment_table_init(&eaptls_fragment_table);
251 eap_init_protocol(void)
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);
258 conv_state_chunk = g_mem_chunk_new("conv_state_chunk",
259 sizeof (conv_state_t),
260 10 * sizeof (conv_state_t),
263 frame_state_chunk = g_mem_chunk_new("frame_state_chunk",
264 sizeof (frame_state_t),
265 100 * sizeof (frame_state_t),
270 dissect_eap_mschapv2(proto_tree *eap_tree, tvbuff_t *tvb, int offset,
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
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" },
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,
296 opcode, val_to_str(opcode, opcodes, "Unknown"));
302 proto_tree_add_text(eap_tree, tvb, offset, 1, "MS-CHAPv2-ID: %d",
303 tvb_get_guint8(tvb, offset));
309 ms_len = tvb_get_ntohs(tvb, offset);
310 proto_tree_add_text(eap_tree, tvb, offset, 2, "MS-Length: %d%s",
312 ms_len != size ? " (invalid len)" : "");
317 case MS_CHAPv2_CHALLENGE:
320 value_size = tvb_get_guint8(tvb, offset);
321 proto_tree_add_text(eap_tree, tvb, offset, 1,
322 "Value-Size: %d", value_size);
325 proto_tree_add_text(eap_tree, tvb, offset, value_size,
327 tvb_bytes_to_str(tvb, offset, value_size));
328 offset += value_size;
332 proto_tree_add_text(eap_tree, tvb, offset, left,
334 tvb_format_text(tvb, offset, left));
336 case MS_CHAPv2_RESPONSE:
339 value_size = tvb_get_guint8(tvb, offset);
340 proto_tree_add_text(eap_tree, tvb, offset, 1,
341 "Value-Size: %d", value_size);
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));
349 proto_tree_add_text(eap_tree, tvb, offset, 8,
350 "Reserved, must be zero: %s",
351 tvb_bytes_to_str(tvb, offset, 8));
353 proto_tree_add_text(eap_tree, tvb, offset, 24,
355 tvb_bytes_to_str(tvb, offset, 24));
357 proto_tree_add_text(eap_tree, tvb, offset, 1,
359 tvb_get_guint8(tvb, offset));
363 proto_tree_add_text(eap_tree, tvb, offset, value_size,
364 "Response (unknown length): %s",
365 tvb_bytes_to_str(tvb, offset,
367 offset += value_size;
372 proto_tree_add_text(eap_tree, tvb, offset, left,
374 tvb_format_text(tvb, offset, left));
376 case MS_CHAPv2_SUCCESS:
379 proto_tree_add_text(eap_tree, tvb, offset, left,
381 tvb_format_text(tvb, offset, left));
383 case MS_CHAPv2_FAILURE:
386 proto_tree_add_text(eap_tree, tvb, offset, left,
387 "Failure Request: %s",
388 tvb_format_text(tvb, offset, left));
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));
400 dissect_eap_sim(proto_tree *eap_tree, tvbuff_t *tvb, int offset, gint size)
406 SIM_NOTIFICATION = 12,
407 SIM_RE_AUTHENTICATION = 13,
408 SIM_CLIENT_ERROR = 14
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" },
418 static const value_string attributes[] = {
421 { 7, "AT_NONCE_MT" },
422 { 10, "AT_PERMANENT_ID_REQ" },
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" },
435 { 130, "AT_ENCR_DATA" },
436 { 132, "AT_NEXT_PSEUDONYM" },
437 { 133, "AT_NEXT_REAUTH_ID" },
441 subtype = tvb_get_guint8(tvb, offset);
442 proto_tree_add_text(eap_tree, tvb, offset, 1,
444 subtype, val_to_str(subtype, subtypes, "Unknown"));
451 proto_tree_add_text(eap_tree, tvb, offset, 2, "Reserved: %d",
452 tvb_get_ntohs(tvb, offset));
456 /* Rest of EAP-SIM data is in Type-Len-Value format. */
460 proto_tree *attr_tree;
464 type = tvb_get_guint8(tvb, aoffset);
465 length = tvb_get_guint8(tvb, aoffset + 1);
468 pi = proto_tree_add_text(eap_tree, tvb, aoffset, aleft,
470 val_to_str(type, attributes,
472 attr_tree = proto_item_add_subtree(pi, ett_eap_sim_attr);
473 proto_tree_add_text(attr_tree, tvb, aoffset, 1,
480 proto_tree_add_text(attr_tree, tvb, aoffset, 1,
481 "Length: %d (%d bytes)",
485 proto_tree_add_text(attr_tree, tvb, aoffset, aleft,
487 tvb_bytes_to_str(tvb, aoffset, aleft));
489 offset += 4 * length;
495 dissect_eap_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
503 conversation_t *conversation;
504 conv_state_t *conversation_state;
505 frame_state_t *packet_state;
508 proto_tree *eap_tree = NULL;
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);
515 eap_code = tvb_get_guint8(tvb, 0);
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)"));
522 * Find a conversation to which we belong; create one if we don't find
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.
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
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?
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?)
544 if (pinfo->destport == pinfo->match_port) {
545 conversation = find_conversation(&pinfo->dst, &pinfo->src,
546 pinfo->ptype, pinfo->destport,
549 conversation = find_conversation(&pinfo->src, &pinfo->dst,
550 pinfo->ptype, pinfo->srcport,
553 if (conversation == NULL) {
554 if (pinfo->destport == pinfo->match_port) {
555 conversation = conversation_new(&pinfo->dst, &pinfo->src,
556 pinfo->ptype, pinfo->destport,
559 conversation = conversation_new(&pinfo->src, &pinfo->dst,
560 pinfo->ptype, pinfo->srcport,
566 * Get the state information for the conversation; attach some if
569 conversation_state = conversation_get_proto_data(conversation, proto_eap);
570 if (conversation_state == NULL) {
572 * Attach state information to the conversation.
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);
582 * Set this now, so that it gets remembered even if we throw an exception
585 if (eap_code == EAP_FAILURE)
586 conversation_state->leap_state = -1;
588 eap_id = tvb_get_guint8(tvb, 1);
590 eap_len = tvb_get_ntohs(tvb, 2);
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.
599 int reported_len = tvb_reported_length_remaining(tvb, 0);
601 if (reported_len < len)
602 return -(len - reported_len);
606 ti = proto_tree_add_item(tree, proto_eap, tvb, 0, len, FALSE);
607 eap_tree = proto_item_add_subtree(ti, ett_eap);
609 proto_tree_add_uint(eap_tree, hf_eap_code, tvb, 0, 1, eap_code);
613 proto_tree_add_item(eap_tree, hf_eap_identifier, tvb, 1, 1, FALSE);
616 proto_tree_add_uint(eap_tree, hf_eap_len, tvb, 2, 2, eap_len);
626 eap_type = tvb_get_guint8(tvb, 4);
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)"));
633 proto_tree_add_uint(eap_tree, hf_eap_type, tvb, 4, 1, eap_type);
637 gint size = len - offset;
640 /*********************************************************************
641 **********************************************************************/
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));
649 if(!pinfo->fd->flags.visited)
650 conversation_state->leap_state = 0;
653 /*********************************************************************
654 **********************************************************************/
655 case EAP_TYPE_NOTIFY:
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));
663 /*********************************************************************
664 **********************************************************************/
667 proto_tree_add_item(eap_tree, hf_eap_type_nak, tvb,
671 /*********************************************************************
672 **********************************************************************/
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",
679 value_size > size - 1 ? " (overflow)": "");
680 if (value_size > size - 1)
681 value_size = size - 1;
683 proto_tree_add_text(eap_tree, tvb, offset, value_size,
685 tvb_bytes_to_str(tvb, offset, value_size));
686 offset += value_size;
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));
695 /*********************************************************************
697 **********************************************************************/
702 guint8 flags = tvb_get_guint8(tvb, offset);
703 gboolean more_fragments;
706 int eap_tls_seq = -1;
707 guint32 eap_reass_cookie = 0;
708 gboolean needs_reassembly = FALSE;
710 more_fragments = test_flag(flags,EAP_TLS_FLAG_M);
711 has_length = test_flag(flags,EAP_TLS_FLAG_L);
713 /* Flags field, 1 byte */
715 proto_tree_add_text(eap_tree, tvb, offset, 1, "Flags(0x%X): %s%s%s",
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,
723 flags & EAP_PEAP_FLAG_VERSION);
729 /* Length field, 4 bytes, OPTIONAL. */
731 length = tvb_get_ntohl(tvb, offset);
733 proto_tree_add_text(eap_tree, tvb, offset, 4, "Length: %i",length);
742 gboolean save_fragmented;
744 tvb_len = tvb_length_remaining(tvb, offset);
749 EAP/TLS is weird protocol (it comes from
750 Microsoft after all).
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.
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.)
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
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.
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) {
783 * We haven't - does this message require reassembly?
785 if (!pinfo->fd->flags.visited) {
787 * This is the first time we've looked at this frame,
788 * so it wouldn't have any remembered information.
790 * Therefore, we check whether this conversation has
791 * a reassembly operation in progress, or whether
792 * this frame has the Fragment flag set.
794 if (conversation_state->eap_tls_seq != -1) {
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".
801 * We must include this frame in the reassembly.
802 * We advance the sequence number, giving us the
803 * sequence number for this fragment.
805 needs_reassembly = TRUE;
806 conversation_state->eap_tls_seq++;
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) {
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).
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;
824 needs_reassembly = TRUE;
825 conversation_state->eap_reass_cookie = pinfo->fd->num;
828 * Start the reassembly sequence number at 0.
830 conversation_state->eap_tls_seq = 0;
832 eap_tls_seq = conversation_state->eap_tls_seq;
833 eap_reass_cookie = conversation_state->eap_reass_cookie;
836 if (needs_reassembly) {
838 * This frame requires reassembly; remember the reassembly
839 * ID for subsequent accesses to it.
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);
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.
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
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.
867 needs_reassembly = TRUE;
868 eap_reass_cookie = packet_state->info;
873 We test here to see whether EAP-TLS packet
874 carry fragmented of TLS data.
876 If this is the case, we do reasembly below,
877 otherwise we just call dissector.
879 if (needs_reassembly) {
880 fragment_data *fd_head = NULL;
883 * Yes, this frame contains a fragment that requires
886 save_fragmented = pinfo->fragmented;
887 pinfo->fragmented = TRUE;
888 fd_head = fragment_add_seq(tvb, offset, pinfo,
890 eaptls_fragment_table,
895 if (fd_head != NULL) /* Reassembled */
898 next_tvb = tvb_new_real_data(fd_head->data,
901 tvb_set_child_real_data_tvbuff(tvb, next_tvb);
902 add_new_data_source(pinfo, next_tvb, "Reassembled EAP-TLS");
904 show_fragment_seq_tree(fd_head, &eaptls_frag_items,
905 eap_tree, pinfo, next_tvb);
907 call_dissector(ssl_handle, next_tvb, pinfo, eap_tree);
910 * We're finished reassembing this frame.
911 * Reinitialize the reassembly state.
913 if (!pinfo->fd->flags.visited)
914 conversation_state->eap_tls_seq = -1;
917 pinfo->fragmented = save_fragmented;
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);
925 break; /* EAP_TYPE_TLS */
926 /*********************************************************************
927 Cisco's Lightweight EAP (LEAP)
928 http://www.missl.cs.umd.edu/wireless/ethereal/leap.txt
929 **********************************************************************/
932 guint8 field,count,namesize;
936 field = tvb_get_guint8(tvb, offset);
937 proto_tree_add_text(eap_tree, tvb, offset, 1,
938 "Version: %i",field);
945 field = tvb_get_guint8(tvb, offset);
946 proto_tree_add_text(eap_tree, tvb, offset, 1,
947 "Reserved: %i",field);
953 count = tvb_get_guint8(tvb, offset);
955 proto_tree_add_text(eap_tree, tvb, offset, 1,
961 /* Data (byte*Count) */
962 /* This part is state-dependent. */
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) {
968 * We haven't - compute the state based on the current
969 * state in the conversation.
971 leap_state = conversation_state->leap_state;
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;
981 * Remember the state for subsequent accesses to this
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);
989 * Update the conversation's state.
991 conversation_state->leap_state = leap_state;
994 /* Get the remembered state. */
995 leap_state = packet_state->info;
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));
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));
1022 } /* END: if (tree) */
1028 /* Name (Length-(8+Count)) */
1029 namesize = eap_len - (8+count);
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));
1040 break; /* EAP_TYPE_LEAP */
1041 /*********************************************************************
1042 EAP-MSCHAPv2 - draft-kamath-pppext-eap-mschapv2-00.txt
1043 **********************************************************************/
1044 case EAP_TYPE_MSCHAPV2:
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 **********************************************************************/
1053 dissect_eap_sim(eap_tree, tvb, offset, size);
1054 break; /* EAP_TYPE_SIM */
1055 /*********************************************************************
1056 **********************************************************************/
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));
1065 /*********************************************************************
1066 **********************************************************************/
1067 } /* switch (eap_type) */
1071 } /* switch (eap_code) */
1073 return tvb_length(tvb);
1077 dissect_eap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1079 return dissect_eap_data(tvb, pinfo, tree, FALSE);
1083 dissect_eap_fragment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1085 return dissect_eap_data(tvb, pinfo, tree, TRUE);
1089 proto_register_eap(void)
1091 static hf_register_info hf[] = {
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 }},
1099 "Length", "eap.len", FT_UINT16, BASE_DEC,
1100 NULL, 0x0, "", HFILL }},
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 }},
1136 static gint *ett[] = {
1138 &ett_eaptls_fragment,
1139 &ett_eaptls_fragments,
1143 proto_eap = proto_register_protocol("Extensible Authentication Protocol",
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);
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);
1155 proto_reg_handoff_eap(void)
1157 dissector_handle_t eap_handle;
1160 * Get a handle for the SSL/TLS dissector.
1162 ssl_handle = find_dissector("ssl");
1164 eap_handle = find_dissector("eap");
1165 dissector_add("ppp.protocol", PPP_EAP, eap_handle);