/* * Copyright (c) 2001-2013 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * Modification History * * September 3, 2010 Dieter Siegmund (dieter@apple.com) * - moved here from EAPOLSocket.c */ /* * EAPOLUtil.c * - EAPOL utility functions */ #include "EAPUtil.h" #include "EAPOLUtil.h" #include "printdata.h" #include "nbo.h" #include "myCFUtil.h" #include static bool EAPOLPacketTypeValid(EAPOLPacketType type) { if (type >= kEAPOLPacketTypeEAPPacket && type <= kEAPOLPacketTypeEncapsulatedASFAlert) { return (true); } return (false); } static const char * EAPOLPacketTypeStr(EAPOLPacketType type) { static const char * str[] = { "EAP Packet", "Start", "Logoff", "Key", "Encapsulated ASF Alert" }; if (EAPOLPacketTypeValid(type)) { return (str[type]); } return (""); } static void RC4KeyDescriptorAppendDescription(EAPOLRC4KeyDescriptorRef descr_p, unsigned int body_length, CFMutableStringRef str) { int key_data_length; u_int16_t key_length; const char * which; if (descr_p->key_index & kEAPOLKeyDescriptorIndexUnicastFlag) { which = "Unicast"; } else { which = "Broadcast"; } key_length = EAPOLKeyDescriptorGetLength(descr_p); key_data_length = body_length - sizeof(*descr_p); STRING_APPEND(str, "EAPOL Key Descriptor: type RC4 (%d) length %d %s index %d\n", descr_p->descriptor_type, key_length, which, descr_p->key_index & kEAPOLKeyDescriptorIndexMask); STRING_APPEND(str, "%-16s", "replay_counter:"); print_bytes_cfstr(str, descr_p->replay_counter, sizeof(descr_p->replay_counter)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-16s", "key_IV:"); print_bytes_cfstr(str, descr_p->key_IV, sizeof(descr_p->key_IV)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-16s", "key_signature:"); print_bytes_cfstr(str, descr_p->key_signature, sizeof(descr_p->key_signature)); STRING_APPEND(str, "\n"); if (key_data_length > 0) { STRING_APPEND(str, "%-16s", "key:"); print_bytes_cfstr(str, descr_p->key, key_data_length); STRING_APPEND(str, "\n"); } return; } static void IEEE80211KeyDescriptorAppendDescription(EAPOLIEEE80211KeyDescriptorRef descr_p, unsigned int body_length, CFMutableStringRef str) { uint16_t key_data_length; uint16_t key_information; uint16_t key_length; key_length = EAPOLIEEE80211KeyDescriptorGetLength(descr_p); key_information = EAPOLIEEE80211KeyDescriptorGetInformation(descr_p); key_data_length = EAPOLIEEE80211KeyDescriptorGetKeyDataLength(descr_p); STRING_APPEND(str, "EAPOL Key Descriptor: type IEEE 802.11 (%d)\n", descr_p->descriptor_type); STRING_APPEND(str, "%-18s0x%04x\n", "key_information:", key_information); STRING_APPEND(str, "%-18s%d\n", "key_length:", key_length); STRING_APPEND(str, "%-18s", "replay_counter:"); print_bytes_cfstr(str, descr_p->replay_counter, sizeof(descr_p->replay_counter)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s", "key_nonce:"); print_bytes_cfstr(str, descr_p->key_nonce, sizeof(descr_p->key_nonce)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s", "EAPOL_key_IV:"); print_bytes_cfstr(str, descr_p->EAPOL_key_IV, sizeof(descr_p->EAPOL_key_IV)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s", "key_RSC:"); print_bytes_cfstr(str, descr_p->key_RSC, sizeof(descr_p->key_RSC)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s", "key_reserved:"); print_bytes_cfstr(str, descr_p->key_reserved, sizeof(descr_p->key_reserved)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s", "key_MIC:"); print_bytes_cfstr(str, descr_p->key_MIC, sizeof(descr_p->key_MIC)); STRING_APPEND(str, "\n"); STRING_APPEND(str, "%-18s%d\n", "key_data_length:", key_data_length); if (key_data_length > 0) { STRING_APPEND(str, "%-18s", "key_data:"); print_bytes_cfstr(str, descr_p->key_data, key_data_length); STRING_APPEND(str, "\n"); } return; } static bool eapol_key_descriptor_valid(void * body, unsigned int body_length, CFMutableStringRef str) { EAPOLIEEE80211KeyDescriptorRef ieee80211_descr_p = body; int key_data_length; EAPOLRC4KeyDescriptorRef rc4_descr_p = body; if (body_length < 1) { if (str != NULL) { STRING_APPEND(str, "EAPOLPacket empty body\n"); } return (false); } #define KEY_DESCRIPTOR_LABEL "EAPOLKeyDescriptor" switch (rc4_descr_p->descriptor_type) { case kEAPOLKeyDescriptorTypeRC4: if (body_length < sizeof(*rc4_descr_p)) { if (str != NULL) { STRING_APPEND(str, "%s(RC4) length %d < %d\n", KEY_DESCRIPTOR_LABEL, body_length, (int)sizeof(*rc4_descr_p)); } return (false); } if (str != NULL) { RC4KeyDescriptorAppendDescription(rc4_descr_p, body_length, str); } break; case kEAPOLKeyDescriptorTypeIEEE80211: case kEAPOLKeyDescriptorTypeWPA: if (body_length < sizeof(*ieee80211_descr_p)) { if (str != NULL) { STRING_APPEND(str, "%s(IEEE80211) length %d < %d\n", KEY_DESCRIPTOR_LABEL, body_length, (int)sizeof(*ieee80211_descr_p)); } return (false); } key_data_length = EAPOLIEEE80211KeyDescriptorGetKeyDataLength(ieee80211_descr_p); if ((body_length - sizeof(*ieee80211_descr_p)) < key_data_length) { if (str != NULL) { STRING_APPEND(str, "%s(IEEE80211) Key Data truncated %d < %d\n", KEY_DESCRIPTOR_LABEL, body_length - (int)sizeof(*ieee80211_descr_p), key_data_length); } return (false); } if (str != NULL) { IEEE80211KeyDescriptorAppendDescription(ieee80211_descr_p, body_length, str); } break; default: if (str != NULL) { STRING_APPEND(str, "%s Type %d unrecognized\n", KEY_DESCRIPTOR_LABEL, rc4_descr_p->descriptor_type); } return (false); } return (true); } static bool eapol_body_valid(EAPOLPacketRef eapol_p, unsigned int length, CFMutableStringRef str) { unsigned int body_length; bool ret = true; body_length = EAPOLPacketGetLength(eapol_p); length -= sizeof(*eapol_p); if (length < body_length) { if (str != NULL) { STRING_APPEND(str, "EAPOLPacket truncated %d < %d\n", length, body_length); } return (false); } switch (eapol_p->packet_type) { case kEAPOLPacketTypeEAPPacket: ret = EAPPacketIsValid((EAPPacketRef)eapol_p->body, body_length, str); break; case kEAPOLPacketTypeKey: ret = eapol_key_descriptor_valid(eapol_p->body, body_length, str); break; case kEAPOLPacketTypeStart: case kEAPOLPacketTypeLogoff: case kEAPOLPacketTypeEncapsulatedASFAlert: break; default: if (str != NULL) { STRING_APPEND(str, "EAPOLPacket type %d unrecognized\n", eapol_p->packet_type); print_data_cfstr(str, ((void *)eapol_p) + sizeof(*eapol_p), body_length); } break; } if (str != NULL && body_length < length) { STRING_APPEND(str, "EAPOL: %d bytes follow body:\n", length - body_length); print_data_cfstr(str, ((void *)eapol_p) + sizeof(*eapol_p) + body_length, length - body_length); } return (ret); } static bool eapol_header_valid(EAPOLPacketRef eapol_p, unsigned int length, CFMutableStringRef str) { if (length < sizeof(*eapol_p)) { if (str != NULL) { STRING_APPEND(str, "EAPOLPacket truncated header %d < %d\n", length, (int)sizeof(*eapol_p)); } return (false); } if (str != NULL) { STRING_APPEND(str, "EAPOL: proto version 0x%x type %s (%d) length %d\n", eapol_p->protocol_version, EAPOLPacketTypeStr(eapol_p->packet_type), eapol_p->packet_type, EAPOLPacketGetLength(eapol_p)); } return (true); } bool EAPOLPacketIsValid(EAPOLPacketRef eapol_p, unsigned int length, CFMutableStringRef str) { if (eapol_header_valid(eapol_p, length, str) == false) { return (false); } return (eapol_body_valid(eapol_p, length, str)); } bool EAPOLPacketValid(EAPOLPacketRef eapol_p, unsigned int length, FILE * f) { bool ret; CFMutableStringRef str = NULL; if (f != NULL) { str = CFStringCreateMutable(NULL, 0); } ret = EAPOLPacketIsValid(eapol_p, length, str); if (str != NULL) { SCPrint(TRUE, f, CFSTR("%@"), str); CFRelease(str); } return (ret); } void EAPOLPacketSetLength(EAPOLPacketRef pkt, uint16_t length) { net_uint16_set(pkt->body_length, length); return; } uint16_t EAPOLPacketGetLength(const EAPOLPacketRef pkt) { return (net_uint16_get(pkt->body_length)); } void EAPOLRC4KeyDescriptorSetLength(EAPOLRC4KeyDescriptorRef pkt, uint16_t length) { net_uint16_set(pkt->key_length, length); return; } void EAPOLKeyDescriptorSetLength(EAPOLKeyDescriptorRef pkt, uint16_t length) { EAPOLRC4KeyDescriptorSetLength(pkt, length); return; } uint16_t EAPOLRC4KeyDescriptorGetLength(const EAPOLRC4KeyDescriptorRef pkt) { return (net_uint16_get(pkt->key_length)); } uint16_t EAPOLKeyDescriptorGetLength(const EAPOLKeyDescriptorRef pkt) { return (EAPOLRC4KeyDescriptorGetLength(pkt)); } uint16_t EAPOLIEEE80211KeyDescriptorGetLength(const EAPOLIEEE80211KeyDescriptorRef pkt) { return (net_uint16_get(pkt->key_length)); } uint16_t EAPOLIEEE80211KeyDescriptorGetInformation(const EAPOLIEEE80211KeyDescriptorRef pkt) { return (net_uint16_get(pkt->key_information)); } uint16_t EAPOLIEEE80211KeyDescriptorGetKeyDataLength(const EAPOLIEEE80211KeyDescriptorRef pkt) { return (net_uint16_get(pkt->key_data_length)); }