1/* 2 * Copyright (c) 2001-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Modification History 26 * 27 * September 3, 2010 Dieter Siegmund (dieter@apple.com) 28 * - moved here from EAPOLSocket.c 29 */ 30 31/* 32 * EAPOLUtil.c 33 * - EAPOL utility functions 34 */ 35 36#include "EAPUtil.h" 37#include "EAPOLUtil.h" 38#include "printdata.h" 39#include "nbo.h" 40#include "myCFUtil.h" 41#include <SystemConfiguration/SCPrivate.h> 42 43static bool 44EAPOLPacketTypeValid(EAPOLPacketType type) 45{ 46 if (type >= kEAPOLPacketTypeEAPPacket 47 && type <= kEAPOLPacketTypeEncapsulatedASFAlert) { 48 return (true); 49 } 50 return (false); 51} 52 53static const char * 54EAPOLPacketTypeStr(EAPOLPacketType type) 55{ 56 static const char * str[] = { 57 "EAP Packet", 58 "Start", 59 "Logoff", 60 "Key", 61 "Encapsulated ASF Alert" 62 }; 63 64 if (EAPOLPacketTypeValid(type)) { 65 return (str[type]); 66 } 67 return ("<unknown>"); 68} 69 70static void 71RC4KeyDescriptorAppendDescription(EAPOLRC4KeyDescriptorRef descr_p, 72 unsigned int body_length, 73 CFMutableStringRef str) 74{ 75 int key_data_length; 76 u_int16_t key_length; 77 const char * which; 78 79 if (descr_p->key_index & kEAPOLKeyDescriptorIndexUnicastFlag) { 80 which = "Unicast"; 81 } 82 else { 83 which = "Broadcast"; 84 } 85 key_length = EAPOLKeyDescriptorGetLength(descr_p); 86 key_data_length = body_length - sizeof(*descr_p); 87 STRING_APPEND(str, 88 "EAPOL Key Descriptor: type RC4 (%d) length %d %s index %d\n", 89 descr_p->descriptor_type, 90 key_length, 91 which, 92 descr_p->key_index & kEAPOLKeyDescriptorIndexMask); 93 STRING_APPEND(str, "%-16s", "replay_counter:"); 94 print_bytes_cfstr(str, descr_p->replay_counter, 95 sizeof(descr_p->replay_counter)); 96 STRING_APPEND(str, "\n"); 97 STRING_APPEND(str, "%-16s", "key_IV:"); 98 print_bytes_cfstr(str, descr_p->key_IV, sizeof(descr_p->key_IV)); 99 STRING_APPEND(str, "\n"); 100 STRING_APPEND(str, "%-16s", "key_signature:"); 101 print_bytes_cfstr(str, descr_p->key_signature, 102 sizeof(descr_p->key_signature)); 103 STRING_APPEND(str, "\n"); 104 if (key_data_length > 0) { 105 STRING_APPEND(str, "%-16s", "key:"); 106 print_bytes_cfstr(str, descr_p->key, key_data_length); 107 STRING_APPEND(str, "\n"); 108 } 109 return; 110} 111 112static void 113IEEE80211KeyDescriptorAppendDescription(EAPOLIEEE80211KeyDescriptorRef descr_p, 114 unsigned int body_length, 115 CFMutableStringRef str) 116{ 117 uint16_t key_data_length; 118 uint16_t key_information; 119 uint16_t key_length; 120 121 key_length = EAPOLIEEE80211KeyDescriptorGetLength(descr_p); 122 key_information = EAPOLIEEE80211KeyDescriptorGetInformation(descr_p); 123 key_data_length = EAPOLIEEE80211KeyDescriptorGetKeyDataLength(descr_p); 124 STRING_APPEND(str, "EAPOL Key Descriptor: type IEEE 802.11 (%d)\n", 125 descr_p->descriptor_type); 126 STRING_APPEND(str, "%-18s0x%04x\n", "key_information:", key_information); 127 STRING_APPEND(str, "%-18s%d\n", "key_length:", key_length); 128 STRING_APPEND(str, "%-18s", "replay_counter:"); 129 print_bytes_cfstr(str, descr_p->replay_counter, 130 sizeof(descr_p->replay_counter)); 131 STRING_APPEND(str, "\n"); 132 STRING_APPEND(str, "%-18s", "key_nonce:"); 133 print_bytes_cfstr(str, descr_p->key_nonce, sizeof(descr_p->key_nonce)); 134 STRING_APPEND(str, "\n"); 135 STRING_APPEND(str, "%-18s", "EAPOL_key_IV:"); 136 print_bytes_cfstr(str, descr_p->EAPOL_key_IV, 137 sizeof(descr_p->EAPOL_key_IV)); 138 STRING_APPEND(str, "\n"); 139 STRING_APPEND(str, "%-18s", "key_RSC:"); 140 print_bytes_cfstr(str, descr_p->key_RSC, sizeof(descr_p->key_RSC)); 141 STRING_APPEND(str, "\n"); 142 STRING_APPEND(str, "%-18s", "key_reserved:"); 143 print_bytes_cfstr(str, descr_p->key_reserved, 144 sizeof(descr_p->key_reserved)); 145 STRING_APPEND(str, "\n"); 146 STRING_APPEND(str, "%-18s", "key_MIC:"); 147 print_bytes_cfstr(str, descr_p->key_MIC, sizeof(descr_p->key_MIC)); 148 STRING_APPEND(str, "\n"); 149 STRING_APPEND(str, "%-18s%d\n", "key_data_length:", key_data_length); 150 if (key_data_length > 0) { 151 STRING_APPEND(str, "%-18s", "key_data:"); 152 print_bytes_cfstr(str, descr_p->key_data, key_data_length); 153 STRING_APPEND(str, "\n"); 154 } 155 return; 156} 157 158static bool 159eapol_key_descriptor_valid(void * body, unsigned int body_length, 160 CFMutableStringRef str) 161{ 162 EAPOLIEEE80211KeyDescriptorRef ieee80211_descr_p = body; 163 int key_data_length; 164 EAPOLRC4KeyDescriptorRef rc4_descr_p = body; 165 166 if (body_length < 1) { 167 if (str != NULL) { 168 STRING_APPEND(str, "EAPOLPacket empty body\n"); 169 } 170 return (false); 171 } 172#define KEY_DESCRIPTOR_LABEL "EAPOLKeyDescriptor" 173 switch (rc4_descr_p->descriptor_type) { 174 case kEAPOLKeyDescriptorTypeRC4: 175 if (body_length < sizeof(*rc4_descr_p)) { 176 if (str != NULL) { 177 STRING_APPEND(str, "%s(RC4) length %d < %d\n", 178 KEY_DESCRIPTOR_LABEL, 179 body_length, (int)sizeof(*rc4_descr_p)); 180 } 181 return (false); 182 } 183 if (str != NULL) { 184 RC4KeyDescriptorAppendDescription(rc4_descr_p, body_length, str); 185 } 186 break; 187 case kEAPOLKeyDescriptorTypeIEEE80211: 188 case kEAPOLKeyDescriptorTypeWPA: 189 if (body_length < sizeof(*ieee80211_descr_p)) { 190 if (str != NULL) { 191 STRING_APPEND(str, "%s(IEEE80211) length %d < %d\n", 192 KEY_DESCRIPTOR_LABEL, 193 body_length, (int)sizeof(*ieee80211_descr_p)); 194 } 195 return (false); 196 } 197 key_data_length 198 = EAPOLIEEE80211KeyDescriptorGetKeyDataLength(ieee80211_descr_p); 199 if ((body_length - sizeof(*ieee80211_descr_p)) < key_data_length) { 200 if (str != NULL) { 201 STRING_APPEND(str, 202 "%s(IEEE80211) Key Data truncated %d < %d\n", 203 KEY_DESCRIPTOR_LABEL, 204 body_length - (int)sizeof(*ieee80211_descr_p), 205 key_data_length); 206 } 207 return (false); 208 } 209 if (str != NULL) { 210 IEEE80211KeyDescriptorAppendDescription(ieee80211_descr_p, 211 body_length, str); 212 } 213 break; 214 default: 215 if (str != NULL) { 216 STRING_APPEND(str, "%s Type %d unrecognized\n", 217 KEY_DESCRIPTOR_LABEL, 218 rc4_descr_p->descriptor_type); 219 } 220 return (false); 221 } 222 return (true); 223} 224 225static bool 226eapol_body_valid(EAPOLPacketRef eapol_p, unsigned int length, 227 CFMutableStringRef str) 228{ 229 unsigned int body_length; 230 bool ret = true; 231 232 body_length = EAPOLPacketGetLength(eapol_p); 233 length -= sizeof(*eapol_p); 234 if (length < body_length) { 235 if (str != NULL) { 236 STRING_APPEND(str, 237 "EAPOLPacket truncated %d < %d\n", 238 length, body_length); 239 } 240 return (false); 241 } 242 switch (eapol_p->packet_type) { 243 case kEAPOLPacketTypeEAPPacket: 244 ret = EAPPacketIsValid((EAPPacketRef)eapol_p->body, body_length, str); 245 break; 246 case kEAPOLPacketTypeKey: 247 ret = eapol_key_descriptor_valid(eapol_p->body, body_length, str); 248 break; 249 case kEAPOLPacketTypeStart: 250 case kEAPOLPacketTypeLogoff: 251 case kEAPOLPacketTypeEncapsulatedASFAlert: 252 break; 253 default: 254 if (str != NULL) { 255 STRING_APPEND(str, 256 "EAPOLPacket type %d unrecognized\n", 257 eapol_p->packet_type); 258 print_data_cfstr(str, 259 ((void *)eapol_p) + sizeof(*eapol_p), body_length); 260 } 261 break; 262 } 263 if (str != NULL && body_length < length) { 264 STRING_APPEND(str, "EAPOL: %d bytes follow body:\n", 265 length - body_length); 266 print_data_cfstr(str, 267 ((void *)eapol_p) + sizeof(*eapol_p) + body_length, 268 length - body_length); 269 } 270 return (ret); 271} 272 273static bool 274eapol_header_valid(EAPOLPacketRef eapol_p, unsigned int length, 275 CFMutableStringRef str) 276{ 277 if (length < sizeof(*eapol_p)) { 278 if (str != NULL) { 279 STRING_APPEND(str, "EAPOLPacket truncated header %d < %d\n", 280 length, (int)sizeof(*eapol_p)); 281 } 282 return (false); 283 } 284 if (str != NULL) { 285 STRING_APPEND(str, 286 "EAPOL: proto version 0x%x type %s (%d) length %d\n", 287 eapol_p->protocol_version, 288 EAPOLPacketTypeStr(eapol_p->packet_type), 289 eapol_p->packet_type, EAPOLPacketGetLength(eapol_p)); 290 } 291 return (true); 292} 293 294bool 295EAPOLPacketIsValid(EAPOLPacketRef eapol_p, unsigned int length, 296 CFMutableStringRef str) 297{ 298 if (eapol_header_valid(eapol_p, length, str) == false) { 299 return (false); 300 } 301 return (eapol_body_valid(eapol_p, length, str)); 302} 303 304bool 305EAPOLPacketValid(EAPOLPacketRef eapol_p, unsigned int length, FILE * f) 306{ 307 bool ret; 308 CFMutableStringRef str = NULL; 309 310 if (f != NULL) { 311 str = CFStringCreateMutable(NULL, 0); 312 } 313 ret = EAPOLPacketIsValid(eapol_p, length, str); 314 if (str != NULL) { 315 SCPrint(TRUE, f, CFSTR("%@"), str); 316 CFRelease(str); 317 } 318 return (ret); 319} 320 321void 322EAPOLPacketSetLength(EAPOLPacketRef pkt, uint16_t length) 323{ 324 net_uint16_set(pkt->body_length, length); 325 return; 326} 327 328uint16_t 329EAPOLPacketGetLength(const EAPOLPacketRef pkt) 330{ 331 return (net_uint16_get(pkt->body_length)); 332} 333 334void 335EAPOLRC4KeyDescriptorSetLength(EAPOLRC4KeyDescriptorRef pkt, uint16_t length) 336{ 337 net_uint16_set(pkt->key_length, length); 338 return; 339} 340 341void 342EAPOLKeyDescriptorSetLength(EAPOLKeyDescriptorRef pkt, uint16_t length) 343{ 344 EAPOLRC4KeyDescriptorSetLength(pkt, length); 345 return; 346} 347 348uint16_t 349EAPOLRC4KeyDescriptorGetLength(const EAPOLRC4KeyDescriptorRef pkt) 350{ 351 return (net_uint16_get(pkt->key_length)); 352} 353 354uint16_t 355EAPOLKeyDescriptorGetLength(const EAPOLKeyDescriptorRef pkt) 356{ 357 return (EAPOLRC4KeyDescriptorGetLength(pkt)); 358} 359 360uint16_t 361EAPOLIEEE80211KeyDescriptorGetLength(const EAPOLIEEE80211KeyDescriptorRef pkt) 362{ 363 return (net_uint16_get(pkt->key_length)); 364} 365 366uint16_t 367EAPOLIEEE80211KeyDescriptorGetInformation(const EAPOLIEEE80211KeyDescriptorRef pkt) 368{ 369 return (net_uint16_get(pkt->key_information)); 370} 371 372uint16_t 373EAPOLIEEE80211KeyDescriptorGetKeyDataLength(const EAPOLIEEE80211KeyDescriptorRef pkt) 374{ 375 return (net_uint16_get(pkt->key_data_length)); 376} 377