1 /* 2 * Copyright (c) 2004 - Michael Richardson <mcr@xelerance.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that: (1) source code distributions 6 * retain the above copyright notice and this paragraph in its entirety, (2) 7 * distributions including binary code include the above copyright notice and 8 * this paragraph in its entirety in the documentation or other materials 9 * provided with the distribution, and (3) all advertising materials mentioning 10 * features or use of this software display the following acknowledgement: 11 * ``This product includes software developed by the University of California, 12 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 13 * the University nor the names of its contributors may be used to endorse 14 * or promote products derived from this software without specific prior 15 * written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 */ 20 21 /* \summary: Extensible Authentication Protocol (EAP) printer */ 22 23 #include <config.h> 24 25 #include "netdissect-stdinc.h" 26 27 #include "netdissect.h" 28 #include "extract.h" 29 30 #define EAP_FRAME_TYPE_PACKET 0 31 #define EAP_FRAME_TYPE_START 1 32 #define EAP_FRAME_TYPE_LOGOFF 2 33 #define EAP_FRAME_TYPE_KEY 3 34 #define EAP_FRAME_TYPE_ENCAP_ASF_ALERT 4 35 36 struct eap_frame_t { 37 nd_uint8_t version; 38 nd_uint8_t type; 39 nd_uint16_t length; 40 }; 41 42 static const struct tok eap_frame_type_values[] = { 43 { EAP_FRAME_TYPE_PACKET, "EAP packet" }, 44 { EAP_FRAME_TYPE_START, "EAPOL start" }, 45 { EAP_FRAME_TYPE_LOGOFF, "EAPOL logoff" }, 46 { EAP_FRAME_TYPE_KEY, "EAPOL key" }, 47 { EAP_FRAME_TYPE_ENCAP_ASF_ALERT, "Encapsulated ASF alert" }, 48 { 0, NULL} 49 }; 50 51 /* RFC 3748 */ 52 struct eap_packet_t { 53 nd_uint8_t code; 54 nd_uint8_t id; 55 nd_uint16_t length; 56 }; 57 58 #define EAP_REQUEST 1 59 #define EAP_RESPONSE 2 60 #define EAP_SUCCESS 3 61 #define EAP_FAILURE 4 62 63 static const struct tok eap_code_values[] = { 64 { EAP_REQUEST, "Request" }, 65 { EAP_RESPONSE, "Response" }, 66 { EAP_SUCCESS, "Success" }, 67 { EAP_FAILURE, "Failure" }, 68 { 0, NULL} 69 }; 70 71 #define EAP_TYPE_NO_PROPOSED 0 72 #define EAP_TYPE_IDENTITY 1 73 #define EAP_TYPE_NOTIFICATION 2 74 #define EAP_TYPE_NAK 3 75 #define EAP_TYPE_MD5_CHALLENGE 4 76 #define EAP_TYPE_OTP 5 77 #define EAP_TYPE_GTC 6 78 #define EAP_TYPE_TLS 13 /* RFC 5216 */ 79 #define EAP_TYPE_SIM 18 /* RFC 4186 */ 80 #define EAP_TYPE_TTLS 21 /* RFC 5281, draft-funk-eap-ttls-v0-01.txt */ 81 #define EAP_TYPE_AKA 23 /* RFC 4187 */ 82 #define EAP_TYPE_FAST 43 /* RFC 4851 */ 83 #define EAP_TYPE_EXPANDED_TYPES 254 84 #define EAP_TYPE_EXPERIMENTAL 255 85 86 static const struct tok eap_type_values[] = { 87 { EAP_TYPE_NO_PROPOSED, "No proposed" }, 88 { EAP_TYPE_IDENTITY, "Identity" }, 89 { EAP_TYPE_NOTIFICATION, "Notification" }, 90 { EAP_TYPE_NAK, "Nak" }, 91 { EAP_TYPE_MD5_CHALLENGE, "MD5-challenge" }, 92 { EAP_TYPE_OTP, "OTP" }, 93 { EAP_TYPE_GTC, "GTC" }, 94 { EAP_TYPE_TLS, "TLS" }, 95 { EAP_TYPE_SIM, "SIM" }, 96 { EAP_TYPE_TTLS, "TTLS" }, 97 { EAP_TYPE_AKA, "AKA" }, 98 { EAP_TYPE_FAST, "FAST" }, 99 { EAP_TYPE_EXPANDED_TYPES, "Expanded types" }, 100 { EAP_TYPE_EXPERIMENTAL, "Experimental" }, 101 { 0, NULL} 102 }; 103 104 #define EAP_TLS_EXTRACT_BIT_L(x) (((x)&0x80)>>7) 105 106 /* RFC 5216 - EAP TLS bits */ 107 #define EAP_TLS_FLAGS_LEN_INCLUDED (1 << 7) 108 #define EAP_TLS_FLAGS_MORE_FRAGMENTS (1 << 6) 109 #define EAP_TLS_FLAGS_START (1 << 5) 110 111 static const struct tok eap_tls_flags_values[] = { 112 { EAP_TLS_FLAGS_LEN_INCLUDED, "L bit" }, 113 { EAP_TLS_FLAGS_MORE_FRAGMENTS, "More fragments bit"}, 114 { EAP_TLS_FLAGS_START, "Start bit"}, 115 { 0, NULL} 116 }; 117 118 #define EAP_TTLS_VERSION(x) ((x)&0x07) 119 120 /* EAP-AKA and EAP-SIM - RFC 4187 */ 121 #define EAP_AKA_CHALLENGE 1 122 #define EAP_AKA_AUTH_REJECT 2 123 #define EAP_AKA_SYNC_FAILURE 4 124 #define EAP_AKA_IDENTITY 5 125 #define EAP_SIM_START 10 126 #define EAP_SIM_CHALLENGE 11 127 #define EAP_AKA_NOTIFICATION 12 128 #define EAP_AKA_REAUTH 13 129 #define EAP_AKA_CLIENT_ERROR 14 130 131 static const struct tok eap_aka_subtype_values[] = { 132 { EAP_AKA_CHALLENGE, "Challenge" }, 133 { EAP_AKA_AUTH_REJECT, "Auth reject" }, 134 { EAP_AKA_SYNC_FAILURE, "Sync failure" }, 135 { EAP_AKA_IDENTITY, "Identity" }, 136 { EAP_SIM_START, "Start" }, 137 { EAP_SIM_CHALLENGE, "Challenge" }, 138 { EAP_AKA_NOTIFICATION, "Notification" }, 139 { EAP_AKA_REAUTH, "Reauth" }, 140 { EAP_AKA_CLIENT_ERROR, "Client error" }, 141 { 0, NULL} 142 }; 143 144 /* 145 * Print EAP requests / responses 146 */ 147 void 148 eap_print(netdissect_options *ndo, 149 const u_char *cp, 150 u_int length) 151 { 152 u_int type, subtype, len; 153 u_int count; 154 const char *sep; 155 156 ndo->ndo_protocol = "eap"; 157 type = GET_U_1(cp); 158 len = GET_BE_U_2(cp + 2); 159 if (len != length) { 160 /* 161 * Probably a fragment; in some cases the fragmentation might 162 * not put an EAP header on every packet, if reassembly can 163 * be done without that (e.g., fragmentation to make a message 164 * fit in multiple TLVs in a RADIUS packet). 165 */ 166 ND_PRINT("EAP fragment?"); 167 return; 168 } 169 ND_PRINT("%s (%u), id %u, len %u", 170 tok2str(eap_code_values, "unknown", type), 171 type, 172 GET_U_1((cp + 1)), 173 len); 174 if (len < 4) { 175 ND_PRINT(" (too short for EAP header)"); 176 return; 177 } 178 179 ND_TCHECK_LEN(cp, len); 180 181 if (type == EAP_REQUEST || type == EAP_RESPONSE) { 182 /* RFC 3748 Section 4.1 */ 183 if (len < 5) { 184 ND_PRINT(" (too short for EAP request/response)"); 185 return; 186 } 187 subtype = GET_U_1(cp + 4); 188 ND_PRINT("\n\t\t Type %s (%u)", 189 tok2str(eap_type_values, "unknown", subtype), 190 subtype); 191 192 switch (subtype) { 193 case EAP_TYPE_IDENTITY: 194 /* According to RFC 3748, the message is optional */ 195 if (len > 5) { 196 ND_PRINT(", Identity: "); 197 nd_printjnp(ndo, cp + 5, len - 5); 198 } 199 break; 200 201 case EAP_TYPE_NOTIFICATION: 202 /* According to RFC 3748, there must be at least one octet of message */ 203 if (len < 6) { 204 ND_PRINT(" (too short for EAP Notification request/response)"); 205 return; 206 } 207 ND_PRINT(", Notification: "); 208 nd_printjnp(ndo, cp + 5, len - 5); 209 break; 210 211 case EAP_TYPE_NAK: 212 /* 213 * one or more octets indicating 214 * the desired authentication 215 * type one octet per type 216 */ 217 if (len < 6) { 218 ND_PRINT(" (too short for EAP Legacy NAK request/response)"); 219 return; 220 } 221 sep = ""; 222 for (count = 5; count < len; count++) { 223 ND_PRINT("%s %s (%u)", sep, 224 tok2str(eap_type_values, "unknown", GET_U_1((cp + count))), 225 GET_U_1(cp + count)); 226 sep = ","; 227 } 228 break; 229 230 case EAP_TYPE_TTLS: 231 case EAP_TYPE_TLS: 232 if (len < 6) { 233 ND_PRINT(" (too short for EAP TLS/TTLS request/response)"); 234 return; 235 } 236 if (subtype == EAP_TYPE_TTLS) 237 ND_PRINT(" TTLSv%u", 238 EAP_TTLS_VERSION(GET_U_1((cp + 5)))); 239 ND_PRINT(" flags [%s] 0x%02x", 240 bittok2str(eap_tls_flags_values, "none", GET_U_1((cp + 5))), 241 GET_U_1(cp + 5)); 242 243 if (EAP_TLS_EXTRACT_BIT_L(GET_U_1(cp + 5))) { 244 if (len < 10) { 245 ND_PRINT(" (too short for EAP TLS/TTLS request/response with length)"); 246 return; 247 } 248 ND_PRINT(", len %u", GET_BE_U_4(cp + 6)); 249 } 250 break; 251 252 case EAP_TYPE_FAST: 253 if (len < 6) { 254 ND_PRINT(" (too short for EAP FAST request/response)"); 255 return; 256 } 257 ND_PRINT(" FASTv%u", 258 EAP_TTLS_VERSION(GET_U_1((cp + 5)))); 259 ND_PRINT(" flags [%s] 0x%02x", 260 bittok2str(eap_tls_flags_values, "none", GET_U_1((cp + 5))), 261 GET_U_1(cp + 5)); 262 263 if (EAP_TLS_EXTRACT_BIT_L(GET_U_1(cp + 5))) { 264 if (len < 10) { 265 ND_PRINT(" (too short for EAP FAST request/response with length)"); 266 return; 267 } 268 ND_PRINT(", len %u", GET_BE_U_4(cp + 6)); 269 } 270 271 /* FIXME - TLV attributes follow */ 272 break; 273 274 case EAP_TYPE_AKA: 275 case EAP_TYPE_SIM: 276 if (len < 6) { 277 ND_PRINT(" (too short for EAP SIM/AKA request/response)"); 278 return; 279 } 280 ND_PRINT(" subtype [%s] 0x%02x", 281 tok2str(eap_aka_subtype_values, "unknown", GET_U_1((cp + 5))), 282 GET_U_1(cp + 5)); 283 284 /* FIXME - TLV attributes follow */ 285 break; 286 287 case EAP_TYPE_MD5_CHALLENGE: 288 case EAP_TYPE_OTP: 289 case EAP_TYPE_GTC: 290 case EAP_TYPE_EXPANDED_TYPES: 291 case EAP_TYPE_EXPERIMENTAL: 292 default: 293 break; 294 } 295 } 296 return; 297 trunc: 298 nd_print_trunc(ndo); 299 } 300 301 void 302 eapol_print(netdissect_options *ndo, 303 const u_char *cp) 304 { 305 const struct eap_frame_t *eap; 306 u_int eap_type, eap_len; 307 308 ndo->ndo_protocol = "eap"; 309 eap = (const struct eap_frame_t *)cp; 310 ND_TCHECK_SIZE(eap); 311 eap_type = GET_U_1(eap->type); 312 313 ND_PRINT("%s (%u) v%u, len %u", 314 tok2str(eap_frame_type_values, "unknown", eap_type), 315 eap_type, 316 GET_U_1(eap->version), 317 GET_BE_U_2(eap->length)); 318 if (ndo->ndo_vflag < 1) 319 return; 320 321 cp += sizeof(struct eap_frame_t); 322 eap_len = GET_BE_U_2(eap->length); 323 324 switch (eap_type) { 325 case EAP_FRAME_TYPE_PACKET: 326 if (eap_len == 0) 327 goto trunc; 328 ND_PRINT(", "); 329 eap_print(ndo, cp, eap_len); 330 return; 331 case EAP_FRAME_TYPE_LOGOFF: 332 case EAP_FRAME_TYPE_ENCAP_ASF_ALERT: 333 default: 334 break; 335 } 336 return; 337 338 trunc: 339 nd_print_trunc(ndo); 340 } 341