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