xref: /netbsd-src/external/bsd/tcpdump/dist/print-eap.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
10f74e101Schristos /*
20f74e101Schristos  * Copyright (c) 2004 - Michael Richardson <mcr@xelerance.com>
30f74e101Schristos  *
40f74e101Schristos  * Redistribution and use in source and binary forms, with or without
50f74e101Schristos  * modification, are permitted provided that: (1) source code distributions
60f74e101Schristos  * retain the above copyright notice and this paragraph in its entirety, (2)
70f74e101Schristos  * distributions including binary code include the above copyright notice and
80f74e101Schristos  * this paragraph in its entirety in the documentation or other materials
90f74e101Schristos  * provided with the distribution, and (3) all advertising materials mentioning
100f74e101Schristos  * features or use of this software display the following acknowledgement:
110f74e101Schristos  * ``This product includes software developed by the University of California,
120f74e101Schristos  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
130f74e101Schristos  * the University nor the names of its contributors may be used to endorse
140f74e101Schristos  * or promote products derived from this software without specific prior
150f74e101Schristos  * written permission.
160f74e101Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
170f74e101Schristos  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
180f74e101Schristos  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
190f74e101Schristos  */
200f74e101Schristos 
21dc860a36Sspz /* \summary: Extensible Authentication Protocol (EAP) printer */
22dc860a36Sspz 
2311b3aaa1Schristos #include <sys/cdefs.h>
240f74e101Schristos #ifndef lint
25*26ba0b50Schristos __RCSID("$NetBSD: print-eap.c,v 1.9 2024/09/02 16:15:31 christos Exp $");
260f74e101Schristos #endif
270f74e101Schristos 
28c74ad251Schristos #include <config.h>
290f74e101Schristos 
30c74ad251Schristos #include "netdissect-stdinc.h"
310f74e101Schristos 
32fdccd7e4Schristos #include "netdissect.h"
330f74e101Schristos #include "extract.h"
340f74e101Schristos 
350f74e101Schristos #define	EAP_FRAME_TYPE_PACKET		0
360f74e101Schristos #define	EAP_FRAME_TYPE_START		1
370f74e101Schristos #define	EAP_FRAME_TYPE_LOGOFF		2
380f74e101Schristos #define	EAP_FRAME_TYPE_KEY		3
390f74e101Schristos #define	EAP_FRAME_TYPE_ENCAP_ASF_ALERT	4
400f74e101Schristos 
410f74e101Schristos struct eap_frame_t {
42c74ad251Schristos     nd_uint8_t  version;
43c74ad251Schristos     nd_uint8_t  type;
44c74ad251Schristos     nd_uint16_t length;
450f74e101Schristos };
460f74e101Schristos 
470f74e101Schristos static const struct tok eap_frame_type_values[] = {
480f74e101Schristos     { EAP_FRAME_TYPE_PACKET,		"EAP packet" },
490f74e101Schristos     { EAP_FRAME_TYPE_START,		"EAPOL start" },
500f74e101Schristos     { EAP_FRAME_TYPE_LOGOFF,		"EAPOL logoff" },
510f74e101Schristos     { EAP_FRAME_TYPE_KEY,		"EAPOL key" },
520f74e101Schristos     { EAP_FRAME_TYPE_ENCAP_ASF_ALERT,	"Encapsulated ASF alert" },
530f74e101Schristos     { 0, NULL}
540f74e101Schristos };
550f74e101Schristos 
560f74e101Schristos /* RFC 3748 */
570f74e101Schristos struct eap_packet_t {
58c74ad251Schristos     nd_uint8_t  code;
59c74ad251Schristos     nd_uint8_t  id;
60c74ad251Schristos     nd_uint16_t length;
610f74e101Schristos };
620f74e101Schristos 
630f74e101Schristos #define		EAP_REQUEST	1
640f74e101Schristos #define		EAP_RESPONSE	2
650f74e101Schristos #define		EAP_SUCCESS	3
660f74e101Schristos #define		EAP_FAILURE	4
670f74e101Schristos 
680f74e101Schristos static const struct tok eap_code_values[] = {
690f74e101Schristos     { EAP_REQUEST,	"Request" },
700f74e101Schristos     { EAP_RESPONSE,	"Response" },
710f74e101Schristos     { EAP_SUCCESS,	"Success" },
720f74e101Schristos     { EAP_FAILURE,	"Failure" },
730f74e101Schristos     { 0, NULL}
740f74e101Schristos };
750f74e101Schristos 
760f74e101Schristos #define		EAP_TYPE_NO_PROPOSED	0
770f74e101Schristos #define		EAP_TYPE_IDENTITY	1
780f74e101Schristos #define		EAP_TYPE_NOTIFICATION	2
790f74e101Schristos #define		EAP_TYPE_NAK		3
800f74e101Schristos #define		EAP_TYPE_MD5_CHALLENGE	4
810f74e101Schristos #define		EAP_TYPE_OTP		5
820f74e101Schristos #define		EAP_TYPE_GTC		6
83c74ad251Schristos #define		EAP_TYPE_TLS		13		/* RFC 5216 */
840f74e101Schristos #define		EAP_TYPE_SIM		18		/* RFC 4186 */
85c74ad251Schristos #define		EAP_TYPE_TTLS		21		/* RFC 5281, draft-funk-eap-ttls-v0-01.txt */
860f74e101Schristos #define		EAP_TYPE_AKA		23		/* RFC 4187 */
870f74e101Schristos #define		EAP_TYPE_FAST		43		/* RFC 4851 */
880f74e101Schristos #define		EAP_TYPE_EXPANDED_TYPES	254
890f74e101Schristos #define		EAP_TYPE_EXPERIMENTAL	255
900f74e101Schristos 
910f74e101Schristos static const struct tok eap_type_values[] = {
920f74e101Schristos     { EAP_TYPE_NO_PROPOSED,	"No proposed" },
930f74e101Schristos     { EAP_TYPE_IDENTITY,	"Identity" },
940f74e101Schristos     { EAP_TYPE_NOTIFICATION,    "Notification" },
950f74e101Schristos     { EAP_TYPE_NAK,		"Nak" },
960f74e101Schristos     { EAP_TYPE_MD5_CHALLENGE,   "MD5-challenge" },
970f74e101Schristos     { EAP_TYPE_OTP,		"OTP" },
980f74e101Schristos     { EAP_TYPE_GTC,		"GTC" },
990f74e101Schristos     { EAP_TYPE_TLS,		"TLS" },
1000f74e101Schristos     { EAP_TYPE_SIM,		"SIM" },
1010f74e101Schristos     { EAP_TYPE_TTLS,		"TTLS" },
1020f74e101Schristos     { EAP_TYPE_AKA,		"AKA" },
1030f74e101Schristos     { EAP_TYPE_FAST,		"FAST" },
1040f74e101Schristos     { EAP_TYPE_EXPANDED_TYPES,  "Expanded types" },
1050f74e101Schristos     { EAP_TYPE_EXPERIMENTAL,    "Experimental" },
1060f74e101Schristos     { 0, NULL}
1070f74e101Schristos };
1080f74e101Schristos 
1090f74e101Schristos #define EAP_TLS_EXTRACT_BIT_L(x)	(((x)&0x80)>>7)
1100f74e101Schristos 
111c74ad251Schristos /* RFC 5216 - EAP TLS bits */
1120f74e101Schristos #define EAP_TLS_FLAGS_LEN_INCLUDED		(1 << 7)
1130f74e101Schristos #define EAP_TLS_FLAGS_MORE_FRAGMENTS		(1 << 6)
1140f74e101Schristos #define EAP_TLS_FLAGS_START			(1 << 5)
1150f74e101Schristos 
1160f74e101Schristos static const struct tok eap_tls_flags_values[] = {
1170f74e101Schristos 	{ EAP_TLS_FLAGS_LEN_INCLUDED, "L bit" },
1180f74e101Schristos 	{ EAP_TLS_FLAGS_MORE_FRAGMENTS, "More fragments bit"},
1190f74e101Schristos 	{ EAP_TLS_FLAGS_START, "Start bit"},
1200f74e101Schristos 	{ 0, NULL}
1210f74e101Schristos };
1220f74e101Schristos 
1230f74e101Schristos #define EAP_TTLS_VERSION(x)		((x)&0x07)
1240f74e101Schristos 
1250f74e101Schristos /* EAP-AKA and EAP-SIM - RFC 4187 */
1260f74e101Schristos #define EAP_AKA_CHALLENGE		1
1270f74e101Schristos #define EAP_AKA_AUTH_REJECT		2
1280f74e101Schristos #define EAP_AKA_SYNC_FAILURE		4
1290f74e101Schristos #define EAP_AKA_IDENTITY		5
1300f74e101Schristos #define EAP_SIM_START			10
1310f74e101Schristos #define EAP_SIM_CHALLENGE		11
1320f74e101Schristos #define EAP_AKA_NOTIFICATION		12
1330f74e101Schristos #define EAP_AKA_REAUTH			13
1340f74e101Schristos #define EAP_AKA_CLIENT_ERROR		14
1350f74e101Schristos 
1360f74e101Schristos static const struct tok eap_aka_subtype_values[] = {
1370f74e101Schristos     { EAP_AKA_CHALLENGE,	"Challenge" },
1380f74e101Schristos     { EAP_AKA_AUTH_REJECT,	"Auth reject" },
1390f74e101Schristos     { EAP_AKA_SYNC_FAILURE,	"Sync failure" },
1400f74e101Schristos     { EAP_AKA_IDENTITY,		"Identity" },
1410f74e101Schristos     { EAP_SIM_START,		"Start" },
1420f74e101Schristos     { EAP_SIM_CHALLENGE,	"Challenge" },
1430f74e101Schristos     { EAP_AKA_NOTIFICATION,	"Notification" },
1440f74e101Schristos     { EAP_AKA_REAUTH,		"Reauth" },
1450f74e101Schristos     { EAP_AKA_CLIENT_ERROR,	"Client error" },
1460f74e101Schristos     { 0, NULL}
1470f74e101Schristos };
1480f74e101Schristos 
1490f74e101Schristos /*
1500f74e101Schristos  * Print EAP requests / responses
1510f74e101Schristos  */
1520f74e101Schristos void
153b3a00663Schristos eap_print(netdissect_options *ndo,
154c74ad251Schristos           const u_char *cp,
155dc860a36Sspz           u_int length)
1560f74e101Schristos {
157c74ad251Schristos     u_int type, subtype, len;
158c74ad251Schristos     u_int count;
159c74ad251Schristos     const char *sep;
1600f74e101Schristos 
161*26ba0b50Schristos     ndo->ndo_protocol = "eap";
162c74ad251Schristos     type = GET_U_1(cp);
163c74ad251Schristos     len = GET_BE_U_2(cp + 2);
164c74ad251Schristos     if (len != length) {
165c74ad251Schristos         /*
166c74ad251Schristos          * Probably a fragment; in some cases the fragmentation might
167c74ad251Schristos          * not put an EAP header on every packet, if reassembly can
168c74ad251Schristos          * be done without that (e.g., fragmentation to make a message
169c74ad251Schristos          * fit in multiple TLVs in a RADIUS packet).
170c74ad251Schristos          */
171c74ad251Schristos         ND_PRINT("EAP fragment?");
172c74ad251Schristos         return;
173c74ad251Schristos     }
174c74ad251Schristos     ND_PRINT("%s (%u), id %u, len %u",
175c74ad251Schristos             tok2str(eap_code_values, "unknown", type),
176c74ad251Schristos             type,
177c74ad251Schristos             GET_U_1((cp + 1)),
178c74ad251Schristos             len);
179c74ad251Schristos     if (len < 4) {
180c74ad251Schristos         ND_PRINT(" (too short for EAP header)");
1810f74e101Schristos         return;
1820f74e101Schristos     }
1830f74e101Schristos 
184c74ad251Schristos     ND_TCHECK_LEN(cp, len);
1850f74e101Schristos 
186c74ad251Schristos     if (type == EAP_REQUEST || type == EAP_RESPONSE) {
187c74ad251Schristos         /* RFC 3748 Section 4.1 */
188c74ad251Schristos         if (len < 5) {
189c74ad251Schristos             ND_PRINT(" (too short for EAP request/response)");
190c74ad251Schristos             return;
191c74ad251Schristos         }
192c74ad251Schristos         subtype = GET_U_1(cp + 4);
193c74ad251Schristos         ND_PRINT("\n\t\t Type %s (%u)",
19472c96ff3Schristos                 tok2str(eap_type_values, "unknown", subtype),
195c74ad251Schristos                 subtype);
1960f74e101Schristos 
1970f74e101Schristos         switch (subtype) {
1980f74e101Schristos             case EAP_TYPE_IDENTITY:
199c74ad251Schristos                 /* According to RFC 3748, the message is optional */
200c74ad251Schristos                 if (len > 5) {
201c74ad251Schristos                     ND_PRINT(", Identity: ");
202c74ad251Schristos                     nd_printjnp(ndo, cp + 5, len - 5);
2030f74e101Schristos                 }
2040f74e101Schristos                 break;
2050f74e101Schristos 
2060f74e101Schristos             case EAP_TYPE_NOTIFICATION:
207c74ad251Schristos                 /* According to RFC 3748, there must be at least one octet of message */
208c74ad251Schristos                 if (len < 6) {
209c74ad251Schristos                     ND_PRINT(" (too short for EAP Notification request/response)");
210c74ad251Schristos                     return;
2110f74e101Schristos                 }
212c74ad251Schristos                 ND_PRINT(", Notification: ");
213c74ad251Schristos                 nd_printjnp(ndo, cp + 5, len - 5);
2140f74e101Schristos                 break;
2150f74e101Schristos 
2160f74e101Schristos             case EAP_TYPE_NAK:
2170f74e101Schristos                 /*
2180f74e101Schristos                  * one or more octets indicating
2190f74e101Schristos                  * the desired authentication
2200f74e101Schristos                  * type one octet per type
2210f74e101Schristos                  */
222c74ad251Schristos                 if (len < 6) {
223c74ad251Schristos                     ND_PRINT(" (too short for EAP Legacy NAK request/response)");
224c74ad251Schristos                     return;
225c74ad251Schristos                 }
226c74ad251Schristos                 sep = "";
227c74ad251Schristos                 for (count = 5; count < len; count++) {
228c74ad251Schristos                     ND_PRINT("%s %s (%u)", sep,
229c74ad251Schristos                            tok2str(eap_type_values, "unknown", GET_U_1((cp + count))),
230c74ad251Schristos                            GET_U_1(cp + count));
231c74ad251Schristos                     sep = ",";
2320f74e101Schristos                 }
2330f74e101Schristos                 break;
2340f74e101Schristos 
2350f74e101Schristos             case EAP_TYPE_TTLS:
2360f74e101Schristos             case EAP_TYPE_TLS:
237c74ad251Schristos                 if (len < 6) {
238c74ad251Schristos                     ND_PRINT(" (too short for EAP TLS/TTLS request/response)");
239c74ad251Schristos                     return;
240c74ad251Schristos                 }
24172c96ff3Schristos                 if (subtype == EAP_TYPE_TTLS)
242c74ad251Schristos                     ND_PRINT(" TTLSv%u",
243c74ad251Schristos                            EAP_TTLS_VERSION(GET_U_1((cp + 5))));
244c74ad251Schristos                 ND_PRINT(" flags [%s] 0x%02x",
245c74ad251Schristos                        bittok2str(eap_tls_flags_values, "none", GET_U_1((cp + 5))),
246c74ad251Schristos                        GET_U_1(cp + 5));
2470f74e101Schristos 
248c74ad251Schristos                 if (EAP_TLS_EXTRACT_BIT_L(GET_U_1(cp + 5))) {
249c74ad251Schristos                     if (len < 10) {
250c74ad251Schristos                         ND_PRINT(" (too short for EAP TLS/TTLS request/response with length)");
251c74ad251Schristos                         return;
252c74ad251Schristos                     }
253c74ad251Schristos                     ND_PRINT(", len %u", GET_BE_U_4(cp + 6));
2540f74e101Schristos                 }
2550f74e101Schristos                 break;
2560f74e101Schristos 
2570f74e101Schristos             case EAP_TYPE_FAST:
258c74ad251Schristos                 if (len < 6) {
259c74ad251Schristos                     ND_PRINT(" (too short for EAP FAST request/response)");
260c74ad251Schristos                     return;
261c74ad251Schristos                 }
262c74ad251Schristos                 ND_PRINT(" FASTv%u",
263c74ad251Schristos                        EAP_TTLS_VERSION(GET_U_1((cp + 5))));
264c74ad251Schristos                 ND_PRINT(" flags [%s] 0x%02x",
265c74ad251Schristos                        bittok2str(eap_tls_flags_values, "none", GET_U_1((cp + 5))),
266c74ad251Schristos                        GET_U_1(cp + 5));
2670f74e101Schristos 
268c74ad251Schristos                 if (EAP_TLS_EXTRACT_BIT_L(GET_U_1(cp + 5))) {
269c74ad251Schristos                     if (len < 10) {
270c74ad251Schristos                         ND_PRINT(" (too short for EAP FAST request/response with length)");
271c74ad251Schristos                         return;
272c74ad251Schristos                     }
273c74ad251Schristos                     ND_PRINT(", len %u", GET_BE_U_4(cp + 6));
2740f74e101Schristos                 }
2750f74e101Schristos 
2760f74e101Schristos                 /* FIXME - TLV attributes follow */
2770f74e101Schristos                 break;
2780f74e101Schristos 
2790f74e101Schristos             case EAP_TYPE_AKA:
2800f74e101Schristos             case EAP_TYPE_SIM:
281c74ad251Schristos                 if (len < 6) {
282c74ad251Schristos                     ND_PRINT(" (too short for EAP SIM/AKA request/response)");
283c74ad251Schristos                     return;
284c74ad251Schristos                 }
285c74ad251Schristos                 ND_PRINT(" subtype [%s] 0x%02x",
286c74ad251Schristos                        tok2str(eap_aka_subtype_values, "unknown", GET_U_1((cp + 5))),
287c74ad251Schristos                        GET_U_1(cp + 5));
2880f74e101Schristos 
2890f74e101Schristos                 /* FIXME - TLV attributes follow */
2900f74e101Schristos                 break;
2910f74e101Schristos 
2920f74e101Schristos             case EAP_TYPE_MD5_CHALLENGE:
2930f74e101Schristos             case EAP_TYPE_OTP:
2940f74e101Schristos             case EAP_TYPE_GTC:
2950f74e101Schristos             case EAP_TYPE_EXPANDED_TYPES:
2960f74e101Schristos             case EAP_TYPE_EXPERIMENTAL:
2970f74e101Schristos             default:
2980f74e101Schristos                 break;
2990f74e101Schristos         }
3000f74e101Schristos     }
301c74ad251Schristos     return;
302c74ad251Schristos trunc:
303c74ad251Schristos     nd_print_trunc(ndo);
304c74ad251Schristos }
3050f74e101Schristos 
306c74ad251Schristos void
307c74ad251Schristos eapol_print(netdissect_options *ndo,
308c74ad251Schristos             const u_char *cp)
309c74ad251Schristos {
310c74ad251Schristos     const struct eap_frame_t *eap;
311c74ad251Schristos     u_int eap_type, eap_len;
312c74ad251Schristos 
313c74ad251Schristos     ndo->ndo_protocol = "eap";
314c74ad251Schristos     eap = (const struct eap_frame_t *)cp;
315c74ad251Schristos     ND_TCHECK_SIZE(eap);
316c74ad251Schristos     eap_type = GET_U_1(eap->type);
317c74ad251Schristos 
318c74ad251Schristos     ND_PRINT("%s (%u) v%u, len %u",
319c74ad251Schristos            tok2str(eap_frame_type_values, "unknown", eap_type),
320c74ad251Schristos            eap_type,
321c74ad251Schristos            GET_U_1(eap->version),
322c74ad251Schristos            GET_BE_U_2(eap->length));
323c74ad251Schristos     if (ndo->ndo_vflag < 1)
324c74ad251Schristos         return;
325c74ad251Schristos 
326c74ad251Schristos     cp += sizeof(struct eap_frame_t);
327c74ad251Schristos     eap_len = GET_BE_U_2(eap->length);
328c74ad251Schristos 
329c74ad251Schristos     switch (eap_type) {
330c74ad251Schristos     case EAP_FRAME_TYPE_PACKET:
331c74ad251Schristos         if (eap_len == 0)
332c74ad251Schristos             goto trunc;
333c74ad251Schristos         ND_PRINT(", ");
334c74ad251Schristos         eap_print(ndo, cp, eap_len);
335c74ad251Schristos         return;
3360f74e101Schristos     case EAP_FRAME_TYPE_LOGOFF:
3370f74e101Schristos     case EAP_FRAME_TYPE_ENCAP_ASF_ALERT:
3380f74e101Schristos     default:
3390f74e101Schristos         break;
3400f74e101Schristos     }
3410f74e101Schristos     return;
3420f74e101Schristos 
3430f74e101Schristos  trunc:
344c74ad251Schristos     nd_print_trunc(ndo);
3450f74e101Schristos }
346