1146773Ssam/*
2146773Ssam * Copyright (c) 2004 - Michael Richardson <mcr@xelerance.com>
3146773Ssam *
4146773Ssam * Redistribution and use in source and binary forms, with or without
5146773Ssam * modification, are permitted provided that: (1) source code distributions
6146773Ssam * retain the above copyright notice and this paragraph in its entirety, (2)
7146773Ssam * distributions including binary code include the above copyright notice and
8146773Ssam * this paragraph in its entirety in the documentation or other materials
9146773Ssam * provided with the distribution, and (3) all advertising materials mentioning
10146773Ssam * features or use of this software display the following acknowledgement:
11146773Ssam * ``This product includes software developed by the University of California,
12146773Ssam * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
13146773Ssam * the University nor the names of its contributors may be used to endorse
14146773Ssam * or promote products derived from this software without specific prior
15146773Ssam * written permission.
16146773Ssam * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17146773Ssam * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18146773Ssam * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19146773Ssam *
20190207Srpaulo * Format and print EAP packets.
21190207Srpaulo *
22146773Ssam */
23146773Ssam
24146773Ssam#ifndef lint
25146773Ssamstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-eap.c,v 1.5 2007-10-04 16:41:33 hannes Exp $";
27146773Ssam#endif
28146773Ssam
29146773Ssam#ifdef HAVE_CONFIG_H
30146773Ssam#include "config.h"
31146773Ssam#endif
32146773Ssam
33146773Ssam#include <tcpdump-stdinc.h>
34146773Ssam
35146773Ssam#include <stdio.h>
36146773Ssam#include <string.h>
37146773Ssam
38146773Ssam#include "netdissect.h"
39190207Srpaulo#include "interface.h"
40146773Ssam#include "addrtoname.h"
41146773Ssam#include "extract.h"
42146773Ssam#include "ether.h"
43146773Ssam
44190207Srpaulo#define	EAP_FRAME_TYPE_PACKET		0
45190207Srpaulo#define	EAP_FRAME_TYPE_START		1
46190207Srpaulo#define	EAP_FRAME_TYPE_LOGOFF		2
47190207Srpaulo#define	EAP_FRAME_TYPE_KEY		3
48190207Srpaulo#define	EAP_FRAME_TYPE_ENCAP_ASF_ALERT	4
49190207Srpaulo
50190207Srpaulostruct eap_frame_t {
51190207Srpaulo    unsigned char   version;
52190207Srpaulo    unsigned char   type;
53190207Srpaulo    unsigned char   length[2];
54190207Srpaulo};
55190207Srpaulo
56190207Srpaulostatic const struct tok eap_frame_type_values[] = {
57190207Srpaulo    { EAP_FRAME_TYPE_PACKET,      	"EAP packet" },
58190207Srpaulo    { EAP_FRAME_TYPE_START,    		"EAPOL start" },
59190207Srpaulo    { EAP_FRAME_TYPE_LOGOFF,      	"EAPOL logoff" },
60190207Srpaulo    { EAP_FRAME_TYPE_KEY,      		"EAPOL key" },
61190207Srpaulo    { EAP_FRAME_TYPE_ENCAP_ASF_ALERT, 	"Encapsulated ASF alert" },
62190207Srpaulo    { 0, NULL}
63190207Srpaulo};
64190207Srpaulo
65190207Srpaulo/* RFC 3748 */
66146773Ssamstruct eap_packet_t {
67190207Srpaulo    unsigned char	code;
68190207Srpaulo    unsigned char	id;
69190207Srpaulo    unsigned char	length[2];
70146773Ssam};
71146773Ssam
72190207Srpaulo#define		EAP_REQUEST	1
73190207Srpaulo#define		EAP_RESPONSE	2
74190207Srpaulo#define		EAP_SUCCESS	3
75190207Srpaulo#define		EAP_FAILURE	4
76190207Srpaulo
77190207Srpaulostatic const struct tok eap_code_values[] = {
78190207Srpaulo    { EAP_REQUEST,	"Request" },
79190207Srpaulo    { EAP_RESPONSE,	"Response" },
80190207Srpaulo    { EAP_SUCCESS,	"Success" },
81190207Srpaulo    { EAP_FAILURE,	"Failure" },
82190207Srpaulo    { 0, NULL}
83190207Srpaulo};
84190207Srpaulo
85190207Srpaulo#define		EAP_TYPE_NO_PROPOSED	0
86190207Srpaulo#define		EAP_TYPE_IDENTITY	1
87190207Srpaulo#define		EAP_TYPE_NOTIFICATION	2
88190207Srpaulo#define		EAP_TYPE_NAK		3
89190207Srpaulo#define		EAP_TYPE_MD5_CHALLENGE	4
90190207Srpaulo#define		EAP_TYPE_OTP		5
91190207Srpaulo#define		EAP_TYPE_GTC		6
92190207Srpaulo#define		EAP_TYPE_TLS		13		/* RFC 2716 */
93190207Srpaulo#define		EAP_TYPE_SIM		18		/* RFC 4186 */
94190207Srpaulo#define		EAP_TYPE_TTLS		21		/* draft-funk-eap-ttls-v0-01.txt */
95190207Srpaulo#define		EAP_TYPE_AKA		23		/* RFC 4187 */
96190207Srpaulo#define		EAP_TYPE_FAST		43		/* RFC 4851 */
97190207Srpaulo#define		EAP_TYPE_EXPANDED_TYPES	254
98190207Srpaulo#define		EAP_TYPE_EXPERIMENTAL	255
99190207Srpaulo
100190207Srpaulostatic const struct tok eap_type_values[] = {
101190207Srpaulo    { EAP_TYPE_NO_PROPOSED,	"No proposed" },
102190207Srpaulo    { EAP_TYPE_IDENTITY,	"Identity" },
103190207Srpaulo    { EAP_TYPE_NOTIFICATION,    "Notification" },
104190207Srpaulo    { EAP_TYPE_NAK,      	"Nak" },
105190207Srpaulo    { EAP_TYPE_MD5_CHALLENGE,   "MD5-challenge" },
106190207Srpaulo    { EAP_TYPE_OTP,      	"OTP" },
107190207Srpaulo    { EAP_TYPE_GTC,      	"GTC" },
108190207Srpaulo    { EAP_TYPE_TLS,      	"TLS" },
109190207Srpaulo    { EAP_TYPE_SIM,      	"SIM" },
110190207Srpaulo    { EAP_TYPE_TTLS,      	"TTLS" },
111190207Srpaulo    { EAP_TYPE_AKA,      	"AKA" },
112190207Srpaulo    { EAP_TYPE_FAST,      	"FAST" },
113190207Srpaulo    { EAP_TYPE_EXPANDED_TYPES,  "Expanded types" },
114190207Srpaulo    { EAP_TYPE_EXPERIMENTAL,    "Experimental" },
115190207Srpaulo    { 0, NULL}
116190207Srpaulo};
117190207Srpaulo
118190207Srpaulo#define EAP_TLS_EXTRACT_BIT_L(x) 	(((x)&0x80)>>7)
119190207Srpaulo
120190207Srpaulo/* RFC 2716 - EAP TLS bits */
121190207Srpaulo#define EAP_TLS_FLAGS_LEN_INCLUDED		(1 << 7)
122190207Srpaulo#define EAP_TLS_FLAGS_MORE_FRAGMENTS		(1 << 6)
123190207Srpaulo#define EAP_TLS_FLAGS_START			(1 << 5)
124190207Srpaulo
125190207Srpaulostatic const struct tok eap_tls_flags_values[] = {
126190207Srpaulo	{ EAP_TLS_FLAGS_LEN_INCLUDED, "L bit" },
127190207Srpaulo	{ EAP_TLS_FLAGS_MORE_FRAGMENTS, "More fragments bit"},
128190207Srpaulo	{ EAP_TLS_FLAGS_START, "Start bit"},
129190207Srpaulo	{ 0, NULL}
130190207Srpaulo};
131190207Srpaulo
132190207Srpaulo#define EAP_TTLS_VERSION(x)		((x)&0x07)
133190207Srpaulo
134190207Srpaulo/* EAP-AKA and EAP-SIM - RFC 4187 */
135190207Srpaulo#define EAP_AKA_CHALLENGE		1
136190207Srpaulo#define EAP_AKA_AUTH_REJECT		2
137190207Srpaulo#define EAP_AKA_SYNC_FAILURE		4
138190207Srpaulo#define EAP_AKA_IDENTITY		5
139190207Srpaulo#define EAP_SIM_START			10
140190207Srpaulo#define EAP_SIM_CHALLENGE		11
141190207Srpaulo#define EAP_AKA_NOTIFICATION		12
142190207Srpaulo#define EAP_AKA_REAUTH			13
143190207Srpaulo#define EAP_AKA_CLIENT_ERROR		14
144190207Srpaulo
145190207Srpaulostatic const struct tok eap_aka_subtype_values[] = {
146190207Srpaulo    { EAP_AKA_CHALLENGE,	"Challenge" },
147190207Srpaulo    { EAP_AKA_AUTH_REJECT,	"Auth reject" },
148190207Srpaulo    { EAP_AKA_SYNC_FAILURE,	"Sync failure" },
149190207Srpaulo    { EAP_AKA_IDENTITY,		"Identity" },
150190207Srpaulo    { EAP_SIM_START,		"Start" },
151190207Srpaulo    { EAP_SIM_CHALLENGE,	"Challenge" },
152190207Srpaulo    { EAP_AKA_NOTIFICATION,	"Notification" },
153190207Srpaulo    { EAP_AKA_REAUTH,		"Reauth" },
154190207Srpaulo    { EAP_AKA_CLIENT_ERROR,	"Client error" },
155190207Srpaulo    { 0, NULL}
156190207Srpaulo};
157190207Srpaulo
158146773Ssam/*
159190207Srpaulo * Print EAP requests / responses
160146773Ssam */
161146773Ssamvoid
162190207Srpauloeap_print(netdissect_options *ndo _U_,
163190207Srpaulo          register const u_char *cp,
164190207Srpaulo          u_int length _U_)
165146773Ssam{
166190207Srpaulo    const struct eap_frame_t *eap;
167190207Srpaulo    const u_char *tptr;
168190207Srpaulo    u_int tlen, type, subtype;
169190207Srpaulo    int count=0, len;
170190207Srpaulo
171190207Srpaulo    tptr = cp;
172190207Srpaulo    tlen = length;
173190207Srpaulo    eap = (const struct eap_frame_t *)cp;
174190207Srpaulo    TCHECK(*eap);
175146773Ssam
176190207Srpaulo    /* in non-verbose mode just lets print the basic info */
177190207Srpaulo    if (vflag < 1) {
178190207Srpaulo	printf("%s (%u) v%u, len %u",
179190207Srpaulo               tok2str(eap_frame_type_values, "unknown", eap->type),
180190207Srpaulo               eap->type,
181190207Srpaulo               eap->version,
182190207Srpaulo               EXTRACT_16BITS(eap->length));
183190207Srpaulo	return;
184190207Srpaulo    }
185190207Srpaulo
186190207Srpaulo    printf("%s (%u) v%u, len %u",
187190207Srpaulo           tok2str(eap_frame_type_values, "unknown", eap->type),
188190207Srpaulo           eap->type,
189190207Srpaulo           eap->version,
190190207Srpaulo           EXTRACT_16BITS(eap->length));
191146773Ssam
192190207Srpaulo    tptr += sizeof(const struct eap_frame_t);
193190207Srpaulo    tlen -= sizeof(const struct eap_frame_t);
194146773Ssam
195190207Srpaulo    switch (eap->type) {
196190207Srpaulo    case EAP_FRAME_TYPE_PACKET:
197190207Srpaulo        type = *(tptr);
198190207Srpaulo        len = EXTRACT_16BITS(tptr+2);
199190207Srpaulo        printf(", %s (%u), id %u, len %u",
200190207Srpaulo               tok2str(eap_code_values, "unknown", type),
201190207Srpaulo               type,
202190207Srpaulo               *(tptr+1),
203190207Srpaulo               len);
204146773Ssam
205190207Srpaulo        if (!TTEST2(*tptr, len))
206190207Srpaulo            goto trunc;
207190207Srpaulo
208190207Srpaulo        if (type <= 2) { /* For EAP_REQUEST and EAP_RESPONSE only */
209190207Srpaulo            subtype = *(tptr+4);
210190207Srpaulo            printf("\n\t\t Type %s (%u)",
211190207Srpaulo                   tok2str(eap_type_values, "unknown", *(tptr+4)),
212190207Srpaulo                   *(tptr+4));
213190207Srpaulo
214190207Srpaulo            switch (subtype) {
215190207Srpaulo            case EAP_TYPE_IDENTITY:
216190207Srpaulo                if (len - 5 > 0) {
217190207Srpaulo                    printf(", Identity: ");
218190207Srpaulo                    safeputs((const char *)tptr+5, len-5);
219190207Srpaulo                }
220190207Srpaulo                break;
221190207Srpaulo
222190207Srpaulo            case EAP_TYPE_NOTIFICATION:
223190207Srpaulo                if (len - 5 > 0) {
224190207Srpaulo                    printf(", Notification: ");
225190207Srpaulo                    safeputs((const char *)tptr+5, len-5);
226190207Srpaulo                }
227190207Srpaulo                break;
228190207Srpaulo
229190207Srpaulo            case EAP_TYPE_NAK:
230190207Srpaulo                count = 5;
231190207Srpaulo
232190207Srpaulo                /*
233190207Srpaulo                 * one or more octets indicating
234190207Srpaulo                 * the desired authentication
235190207Srpaulo                 * type one octet per type
236190207Srpaulo                 */
237190207Srpaulo                while (count < len) {
238190207Srpaulo                    printf(" %s (%u),",
239190207Srpaulo                           tok2str(eap_type_values, "unknown", *(tptr+count)),
240190207Srpaulo                           *(tptr+count));
241190207Srpaulo                    count++;
242190207Srpaulo                }
243190207Srpaulo                break;
244190207Srpaulo
245190207Srpaulo            case EAP_TYPE_TTLS:
246190207Srpaulo                printf(" TTLSv%u",
247190207Srpaulo                       EAP_TTLS_VERSION(*(tptr+5))); /* fall through */
248190207Srpaulo            case EAP_TYPE_TLS:
249190207Srpaulo                printf(" flags [%s] 0x%02x,",
250190207Srpaulo                       bittok2str(eap_tls_flags_values, "none", *(tptr+5)),
251190207Srpaulo                       *(tptr+5));
252190207Srpaulo
253190207Srpaulo                if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) {
254190207Srpaulo		    printf(" len %u", EXTRACT_32BITS(tptr+6));
255190207Srpaulo                }
256190207Srpaulo                break;
257190207Srpaulo
258190207Srpaulo            case EAP_TYPE_FAST:
259190207Srpaulo                printf(" FASTv%u",
260190207Srpaulo                       EAP_TTLS_VERSION(*(tptr+5)));
261190207Srpaulo                printf(" flags [%s] 0x%02x,",
262190207Srpaulo                       bittok2str(eap_tls_flags_values, "none", *(tptr+5)),
263190207Srpaulo                       *(tptr+5));
264190207Srpaulo
265190207Srpaulo                if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) {
266190207Srpaulo                    printf(" len %u", EXTRACT_32BITS(tptr+6));
267190207Srpaulo                }
268190207Srpaulo
269190207Srpaulo                /* FIXME - TLV attributes follow */
270190207Srpaulo                break;
271190207Srpaulo
272190207Srpaulo            case EAP_TYPE_AKA:
273190207Srpaulo            case EAP_TYPE_SIM:
274190207Srpaulo                printf(" subtype [%s] 0x%02x,",
275190207Srpaulo                       tok2str(eap_aka_subtype_values, "unknown", *(tptr+5)),
276190207Srpaulo                       *(tptr+5));
277190207Srpaulo
278190207Srpaulo                /* FIXME - TLV attributes follow */
279190207Srpaulo                break;
280190207Srpaulo
281190207Srpaulo            case EAP_TYPE_MD5_CHALLENGE:
282190207Srpaulo            case EAP_TYPE_OTP:
283190207Srpaulo            case EAP_TYPE_GTC:
284190207Srpaulo            case EAP_TYPE_EXPANDED_TYPES:
285190207Srpaulo            case EAP_TYPE_EXPERIMENTAL:
286190207Srpaulo            default:
287190207Srpaulo                break;
288190207Srpaulo            }
289190207Srpaulo        }
290190207Srpaulo        break;
291190207Srpaulo
292190207Srpaulo    case EAP_FRAME_TYPE_LOGOFF:
293190207Srpaulo    case EAP_FRAME_TYPE_ENCAP_ASF_ALERT:
294190207Srpaulo    default:
295190207Srpaulo        break;
296190207Srpaulo    }
297190207Srpaulo    return;
298190207Srpaulo
299190207Srpaulo trunc:
300190207Srpaulo    printf("\n\t[|EAP]");
301146773Ssam}
302146773Ssam
303190207Srpaulo/*
304190207Srpaulo * Local Variables:
305190207Srpaulo * c-basic-offset: 4
306190207Srpaulo * End:
307190207Srpaulo */
308