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