1/*
2 * Copyright (c) 2008-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 * EAPSIMAKAUtil.c
26 * - common definitions/routines for EAP-SIM and EAP-AKA
27 */
28
29#include "EAPSIMAKAUtil.h"
30#include <stddef.h>
31#include <stdlib.h>
32#include "EAPLog.h"
33#include "symbol_scope.h"
34#include "nbo.h"
35#include "printdata.h"
36#include "EAP.h"
37#include "EAPUtil.h"
38#include "fips186prf.h"
39#include "myCFUtil.h"
40#include <string.h>
41#include <CommonCrypto/CommonHMAC.h>
42
43/*
44 * Modification History
45 *
46 * October 8, 2012	Dieter Siegmund (dieter@apple)
47 * - created (from eapsim_plugin.c)
48 */
49
50PRIVATE_EXTERN const char *
51EAPSIMAKAPacketSubtypeGetString(EAPSIMAKAPacketSubtype subtype)
52{
53    static char		buf[8];
54    const char *	ret;
55
56    switch (subtype) {
57	/* EAP-AKA only */
58    case kEAPSIMAKAPacketSubtypeAKAChallenge:
59	ret = "Challenge";
60	break;
61    case kEAPSIMAKAPacketSubtypeAKAAuthenticationReject:
62	ret = "Authentication Reject";
63	break;
64    case kEAPSIMAKAPacketSubtypeAKASynchronizationFailure:
65	ret = "Synchronization Failure";
66	break;
67    case kEAPSIMAKAPacketSubtypeAKAIdentity:
68	ret = "Identity";
69	break;
70
71	/* EAP-SIM only */
72    case kEAPSIMAKAPacketSubtypeSIMStart :
73	ret = "Start";
74	break;
75    case kEAPSIMAKAPacketSubtypeSIMChallenge :
76	ret = "Challenge";
77	break;
78
79	/* EAP-AKA and EAP-SIM */
80    case kEAPSIMAKAPacketSubtypeNotification :
81	ret = "Notification";
82	break;
83    case kEAPSIMAKAPacketSubtypeReauthentication :
84	ret = "Reauthentication";
85	break;
86    case kEAPSIMAKAPacketSubtypeClientError :
87	ret = "Client Error";
88	break;
89    default:
90	snprintf(buf, sizeof(buf), "%d", subtype);
91	ret = buf;
92	break;
93    }
94    return (ret);
95}
96
97PRIVATE_EXTERN const char *
98EAPSIMAKAAttributeTypeGetString(EAPSIMAKAAttributeType attr)
99{
100    static char		buf[8];
101
102    switch (attr) {
103    case kAT_RAND:
104	return "AT_RAND";
105    case kAT_AUTN:
106	return "AT_AUTN";
107    case kAT_RES:
108	return "AT_RES";
109    case kAT_AUTS:
110	return "AT_AUTS";
111    case kAT_PADDING:
112	return "AT_PADDING";
113    case kAT_NONCE_MT:
114	return "AT_NONCE_MT";
115    case kAT_PERMANENT_ID_REQ:
116	return "AT_PERMANENT_ID_REQ";
117    case kAT_MAC:
118	return "AT_MAC";
119    case kAT_NOTIFICATION:
120	return "AT_NOTIFICATION";
121    case kAT_ANY_ID_REQ:
122	return "AT_ANY_ID_REQ";
123    case kAT_IDENTITY:
124	return "AT_IDENTITY";
125    case kAT_VERSION_LIST:
126	return "AT_VERSION_LIST";
127    case kAT_SELECTED_VERSION:
128	return "AT_SELECTED_VERSION";
129    case kAT_FULLAUTH_ID_REQ:
130	return "AT_FULLAUTH_ID_REQ";
131    case kAT_COUNTER:
132	return "AT_COUNTER";
133    case kAT_COUNTER_TOO_SMALL:
134	return "AT_COUNTER_TOO_SMALL";
135    case kAT_NONCE_S:
136	return "AT_NONCE_S";
137    case kAT_CLIENT_ERROR_CODE:
138	return "AT_CLIENT_ERROR_CODE";
139    case kAT_IV:
140	return "AT_IV";
141    case kAT_ENCR_DATA:
142	return "AT_ENCR_DATA";
143    case kAT_NEXT_PSEUDONYM:
144	return "AT_NEXT_PSEUDONYM";
145    case kAT_NEXT_REAUTH_ID:
146	return "AT_NEXT_REAUTH_ID";
147    case kAT_CHECKCODE:
148	return "AT_CHECKCODE";
149    case kAT_RESULT_IND:
150	return "AT_RESULT_IND";
151    default:
152	snprintf(buf, sizeof(buf), "%d", attr);
153	return (buf);
154    }
155}
156
157PRIVATE_EXTERN const char *
158ATNotificationCodeGetString(uint16_t code)
159{
160    const char *	str;
161
162    switch (code) {
163    case kATNotificationCodeGeneralFailureAfterAuthentication:
164	str = "General Failure After Authentication";
165	break;
166    case kATNotificationCodeGeneralFailureBeforeAuthentication:
167	str = "General Failure Before Authentication";
168	break;
169    case kATNotificationCodeSuccess:
170	str = "Success";
171	break;
172    case kATNotificationCodeTemporarilyDeniedAccess:
173	str = "Temporarily Denied Access";
174	break;
175    case kATNotificationCodeNotSubscribed:
176	str = "Not Subscribed";
177	break;
178    default:
179	str = NULL;
180	break;
181    }
182    return (str);
183}
184
185/**
186 ** Miscellaneous utilities
187 **/
188
189PRIVATE_EXTERN CFStringRef
190EAPSIMAKAPacketCopyDescription(const EAPPacketRef pkt, bool * packet_is_valid)
191{
192    int			attrs_length;
193    EAPSIMAKAPacketRef	simaka = (EAPSIMAKAPacketRef)pkt;
194    uint16_t		length = EAPPacketGetLength(pkt);
195    CFMutableStringRef	str = NULL;
196    TLVListDeclare(	tlvs_p);
197    bool		valid = FALSE;
198
199    switch (pkt->code) {
200    case kEAPCodeRequest:
201    case kEAPCodeResponse:
202	break;
203    default:
204	goto done;
205    }
206    str = CFStringCreateMutable(NULL, 0);
207    if (length < kEAPSIMAKAPacketHeaderLength) {
208	STRING_APPEND(str, "EAPSIMAKAPacket truncated header %d < %d\n",
209		      length, (int)kEAPSIMAKAPacketHeaderLength);
210	goto done;
211    }
212    attrs_length = length - kEAPSIMAKAPacketHeaderLength;
213    STRING_APPEND(str,
214		  "%s %s: Identifier %d Length %d [%s] Length %d\n",
215		  EAPTypeStr(simaka->type),
216		  pkt->code == kEAPCodeRequest ? "Request" : "Response",
217		  pkt->identifier, length,
218		  EAPSIMAKAPacketSubtypeGetString(simaka->subtype), attrs_length);
219    if (attrs_length != 0) {
220	CFStringRef	tlvs_str;
221
222	TLVListInit(tlvs_p);
223	if (TLVListParse(tlvs_p, simaka->attrs, attrs_length) == FALSE) {
224	    STRING_APPEND(str, "failed to parse TLVs: %s\n",
225			  TLVListErrorString(tlvs_p));
226	    goto done;
227	}
228	tlvs_str = TLVListCopyDescription(tlvs_p);
229	TLVListFree(tlvs_p);
230	STRING_APPEND(str, "%@", tlvs_str);
231	CFRelease(tlvs_str);
232    }
233    valid = TRUE;
234
235 done:
236    *packet_is_valid = valid;
237    return (str);
238}
239
240PRIVATE_EXTERN EAPSIMAKAStatus
241EAPSIMAKAStatusForATNotificationCode(uint16_t notification_code)
242{
243    EAPSIMAKAStatus	status = kEAPSIMAKAStatusOK;
244
245    switch (notification_code) {
246    case kATNotificationCodeGeneralFailureAfterAuthentication:
247	status = kEAPSIMAKAStatusFailureAfterAuthentication;
248	break;
249    case kATNotificationCodeGeneralFailureBeforeAuthentication:
250	status = kEAPSIMAKAStatusFailureBeforeAuthentication;
251	break;
252    case kATNotificationCodeSuccess:
253	status = kEAPSIMAKAStatusOK;
254	break;
255    case kATNotificationCodeTemporarilyDeniedAccess:
256	status = kEAPSIMAKAStatusAccessTemporarilyDenied;
257	break;
258    case kATNotificationCodeNotSubscribed:
259	status = kEAPSIMAKAStatusNotSubscribed;
260	break;
261    default:
262	status = kEAPSIMAKAStatusUnrecognizedNotification;
263	break;
264    }
265    return (status);
266}
267
268/*
269 * Function: EAPSIMAKAKeyInfoComputeMAC
270 * Purpose:
271 *    Compute the MAC value in the AT_MAC attribute using the
272 *    specified EAP packet 'pkt' and assuming 'mac_p' points to
273 *    an area within 'pkt' that holds the MAC value.
274 *
275 *    This function figures out how much data comes before the 'mac_p'
276 *    value and how much comes after, and feeds the before, zero-mac, and after
277 *    bytes into the HMAC-SHA1 algorithm.  It also includes the 'extra'
278 *    value, whose value depends on which packet is being MAC'd.
279 * Returns:
280 *    'hash' value is filled in with HMAC-SHA1 results.
281 */
282PRIVATE_EXTERN void
283EAPSIMAKAKeyInfoComputeMAC(EAPSIMAKAKeyInfoRef key_info_p,
284			   EAPPacketRef pkt,
285			   const uint8_t * mac_p,
286			   const uint8_t * extra, int extra_length,
287			   uint8_t hash[CC_SHA1_DIGEST_LENGTH])
288{
289    int			after_mac_size;
290    int			before_mac_size;
291    CCHmacContext	ctx;
292    int			pkt_len = EAPPacketGetLength(pkt);
293    uint8_t		zero_mac[MAC_SIZE];
294
295    bzero(&zero_mac, sizeof(zero_mac));
296    before_mac_size = mac_p - (const uint8_t *)pkt;
297    after_mac_size = pkt_len - (before_mac_size + sizeof(zero_mac));
298
299    /* compute the hash */
300    CCHmacInit(&ctx, kCCHmacAlgSHA1, key_info_p->s.k_aut,
301	       sizeof(key_info_p->s.k_aut));
302    CCHmacUpdate(&ctx, pkt, before_mac_size);
303    CCHmacUpdate(&ctx, zero_mac, sizeof(zero_mac));
304    CCHmacUpdate(&ctx, mac_p + sizeof(zero_mac), after_mac_size);
305    if (extra != NULL) {
306	CCHmacUpdate(&ctx, extra, extra_length);
307    }
308    CCHmacFinal(&ctx, hash);
309    return;
310}
311
312PRIVATE_EXTERN bool
313EAPSIMAKAKeyInfoVerifyMAC(EAPSIMAKAKeyInfoRef key_info,
314			  EAPPacketRef pkt,
315			  const uint8_t * mac_p,
316			  const uint8_t * extra, int extra_length)
317{
318    uint8_t		hash[CC_SHA1_DIGEST_LENGTH];
319
320    EAPSIMAKAKeyInfoComputeMAC(key_info, pkt, mac_p, extra, extra_length, hash);
321    return (bcmp(hash, mac_p, MAC_SIZE) == 0);
322}
323
324PRIVATE_EXTERN void
325EAPSIMAKAKeyInfoSetMAC(EAPSIMAKAKeyInfoRef key_info,
326		       EAPPacketRef pkt,
327		       uint8_t * mac_p,
328		       const uint8_t * extra, int extra_length)
329{
330    uint8_t		hash[CC_SHA1_DIGEST_LENGTH];
331
332    EAPSIMAKAKeyInfoComputeMAC(key_info, pkt, mac_p, extra, extra_length, hash);
333    bcopy(hash, mac_p, MAC_SIZE);
334    return;
335}
336
337#include <CommonCrypto/CommonDigest.h>
338#include <CommonCrypto/CommonCryptor.h>
339
340PRIVATE_EXTERN uint8_t *
341EAPSIMAKAKeyInfoDecryptTLVList(EAPSIMAKAKeyInfoRef key_info_p,
342			       AT_ENCR_DATA * encr_data_p, AT_IV * iv_p,
343			       TLVListRef decrypted_tlvs_p)
344{
345    CCCryptorRef	cryptor = NULL;
346    size_t		buf_used;
347    uint8_t *		decrypted_buffer = NULL;
348    int			encr_data_len;
349    CCCryptorStatus 	status;
350    bool		success = FALSE;
351
352    encr_data_len = encr_data_p->ed_length * TLV_ALIGNMENT
353	- offsetof(AT_ENCR_DATA, ed_encrypted_data);
354    decrypted_buffer = (uint8_t *)malloc(encr_data_len);
355    status = CCCryptorCreate(kCCDecrypt,
356			     kCCAlgorithmAES128,
357			     0,
358			     key_info_p->s.k_encr,
359			     sizeof(key_info_p->s.k_encr),
360			     iv_p->iv_initialization_vector,
361			     &cryptor);
362    if (status != kCCSuccess) {
363	EAPLOG_FL(LOG_NOTICE, "CCCryptoCreate failed with %d", status);
364	goto done;
365    }
366    status = CCCryptorUpdate(cryptor,
367			     encr_data_p->ed_encrypted_data,
368			     encr_data_len,
369			     decrypted_buffer,
370			     encr_data_len,
371			     &buf_used);
372    if (status != kCCSuccess) {
373	EAPLOG_FL(LOG_NOTICE, "CCCryptoUpdate failed with %d", status);
374	goto done;
375    }
376    if (buf_used != encr_data_len) {
377	EAPLOG_FL(LOG_NOTICE,
378		  "decryption consumed %d bytes (!= %d bytes)",
379		  (int)buf_used, encr_data_len);
380	goto done;
381    }
382    if (TLVListParse(decrypted_tlvs_p, decrypted_buffer, encr_data_len)
383	== FALSE) {
384	EAPLOG_FL(LOG_NOTICE,
385		  "TLVListParse failed on AT_ENCR_DATA, %s",
386		  TLVListErrorString(decrypted_tlvs_p));
387	goto done;
388    }
389    success = TRUE;
390
391 done:
392    if (cryptor != NULL) {
393	status = CCCryptorRelease(cryptor);
394	if (status != kCCSuccess) {
395	    EAPLOG_FL(LOG_NOTICE, "CCCryptoRelease failed with %d", status);
396	}
397    }
398    if (success == FALSE && decrypted_buffer != NULL) {
399	free(decrypted_buffer);
400	decrypted_buffer = NULL;
401    }
402    return (decrypted_buffer);
403}
404
405STATIC bool
406EAPSIMAKAKeyInfoEncrypt(EAPSIMAKAKeyInfoRef key_info_p, const uint8_t * iv_p,
407			const uint8_t * clear, int size, uint8_t * encrypted)
408{
409    size_t		buf_used;
410    CCCryptorRef	cryptor;
411    bool		ret = FALSE;
412    CCCryptorStatus 	status;
413
414    status = CCCryptorCreate(kCCEncrypt,
415			     kCCAlgorithmAES128,
416			     0,
417			     key_info_p->s.k_encr,
418			     sizeof(key_info_p->s.k_encr),
419			     iv_p,
420			     &cryptor);
421    if (status != kCCSuccess) {
422	EAPLOG_FL(LOG_NOTICE, "encrypt CCCryptoCreate failed with %d", status);
423	goto done;
424    }
425    status = CCCryptorUpdate(cryptor, clear, size, encrypted, size, &buf_used);
426    if (status != kCCSuccess) {
427	EAPLOG_FL(LOG_NOTICE, "encrypt CCCryptoUpdate failed with %d", status);
428	goto done;
429    }
430    if (buf_used != size) {
431	EAPLOG_FL(LOG_NOTICE,
432		  "encryption consumed %d, should have been %d",
433		  (int)buf_used, size);
434	goto done;
435    }
436    ret = TRUE;
437
438 done:
439    status = CCCryptorRelease(cryptor);
440    if (status != kCCSuccess) {
441	EAPLOG_FL(LOG_NOTICE, "CCCryptoRelease failed with %d", status);
442    }
443    return (ret);
444}
445
446STATIC void
447fill_with_random(uint8_t * buf, int len)
448{
449    int             i;
450    int             n;
451    void *          p;
452    uint32_t        random;
453
454    n = len / sizeof(random);
455    for (i = 0, p = buf; i < n; i++, p += sizeof(random)) {
456        random = arc4random();
457        bcopy(&random, p, sizeof(random));
458    }
459    return;
460}
461
462PRIVATE_EXTERN bool
463EAPSIMAKAKeyInfoEncryptTLVs(EAPSIMAKAKeyInfoRef key_info,
464			    TLVBufferRef tb_p, TLVBufferRef tb_add_p)
465{
466    int			buf_used;
467    int			padding_length;
468    AT_ENCR_DATA *	encr_data_p;
469    AT_IV *		iv_p;
470    bool		ret = FALSE;
471    TLVListDeclare(	temp);
472
473    buf_used = TLVBufferUsed(tb_add_p);
474    padding_length = AT_ENCR_DATA_ROUNDUP(buf_used) - buf_used;
475
476    if (padding_length != 0
477	&& TLVBufferAddPadding(tb_add_p, padding_length) == FALSE) {
478	EAPLOG_FL(LOG_NOTICE, "failed to add AT_PADDING, %s",
479		  TLVBufferErrorString(tb_p));
480	goto done;
481    }
482
483    if (TLVBufferUsed(tb_add_p) != TLVBufferMaxSize(tb_add_p)) {
484	EAPLOG_FL(LOG_NOTICE, "nested encrypted TLVs length %d != %d",
485		  TLVBufferUsed(tb_add_p), TLVBufferMaxSize(tb_add_p));
486	goto done;
487    }
488
489    TLVListInit(temp);
490    if (TLVListParse(temp, TLVBufferStorage(tb_add_p),
491		     TLVBufferUsed(tb_add_p)) == FALSE) {
492	EAPLOG_FL(LOG_NOTICE, "nested TLVs TLVListParse failed, %s",
493		  TLVListErrorString(temp));
494	goto done;
495    }
496    {
497	CFStringRef		str;
498
499	str = TLVListCopyDescription(temp);
500	TLVListFree(temp);
501	EAPLOG(LOG_DEBUG, "Encrypted TLVs:\n%@", str);
502	CFRelease(str);
503    }
504
505    /* AT_IV */
506    iv_p = (AT_IV *) TLVBufferAllocateTLV(tb_p, kAT_IV, sizeof(AT_IV));
507    if (iv_p == NULL) {
508	EAPLOG_FL(LOG_NOTICE, "failed to allocate AT_IV, %s",
509		  TLVBufferErrorString(tb_p));
510	goto done;
511    }
512    net_uint16_set(iv_p->iv_reserved, 0);
513    fill_with_random(iv_p->iv_initialization_vector,
514		     sizeof(iv_p->iv_initialization_vector));
515
516    /* AT_ENCR_DATA */
517    encr_data_p = (AT_ENCR_DATA *)
518	TLVBufferAllocateTLV(tb_p, kAT_ENCR_DATA,
519			     offsetof(AT_ENCR_DATA, ed_encrypted_data)
520			     + TLVBufferUsed(tb_add_p));
521    if (encr_data_p == NULL) {
522	EAPLOG_FL(LOG_NOTICE, "failed to allocate AT_ENCR_DATA, %s",
523		  TLVBufferErrorString(tb_add_p));
524	goto done;
525    }
526    net_uint16_set(encr_data_p->ed_reserved, 0);
527    if (!EAPSIMAKAKeyInfoEncrypt(key_info, iv_p->iv_initialization_vector,
528				 TLVBufferStorage(tb_add_p),
529				 TLVBufferUsed(tb_add_p),
530				 encr_data_p->ed_encrypted_data)) {
531	EAPLOG_FL(LOG_NOTICE, "failed to encrypt AT_ENCR_DATA");
532	goto done;
533    }
534    ret = TRUE;
535
536 done:
537    return (ret);
538}
539
540PRIVATE_EXTERN void
541EAPSIMAKAKeyInfoComputeReauthKey(EAPSIMAKAKeyInfoRef key_info,
542				 EAPSIMAKAPersistentStateRef persist,
543				 const void * identity,
544				 int identity_length,
545				 AT_COUNTER * counter_p,
546				 AT_NONCE_S * nonce_s_p)
547{
548    CC_SHA1_CTX		sha1_context;
549    EAPSIMAKAKeyInfo	temp_key_info;
550    uint8_t		xkey[CC_SHA1_DIGEST_LENGTH];
551
552    /*
553     * generate the XKEY':
554     * XKEY' = SHA1(Identity|counter|NONCE_S| MK)
555     */
556    CC_SHA1_Init(&sha1_context);
557    CC_SHA1_Update(&sha1_context, identity, identity_length);
558    CC_SHA1_Update(&sha1_context, counter_p->co_counter,
559		   sizeof(counter_p->co_counter));
560    CC_SHA1_Update(&sha1_context, nonce_s_p->nc_nonce_s,
561		   sizeof(nonce_s_p->nc_nonce_s));
562    CC_SHA1_Update(&sha1_context,
563		   EAPSIMAKAPersistentStateGetMasterKey(persist),
564		   EAPSIMAKAPersistentStateGetMasterKeySize(persist));
565    CC_SHA1_Final(xkey, &sha1_context);
566
567    /* now run PRF to generate keying material */
568    fips186_2prf(xkey, temp_key_info.key);
569
570    /* copy the new MSK */
571    bcopy(temp_key_info.key,
572	  key_info->s.msk,
573	  sizeof(key_info->s.msk));
574
575    /* copy the new EMSK */
576    bcopy(temp_key_info.key + sizeof(temp_key_info.s.msk),
577	  key_info->s.emsk,
578	  sizeof(key_info->s.emsk));
579    return;
580}
581
582PRIVATE_EXTERN EAPSIMAKAAttributeType
583EAPSIMAKAIdentityTypeGetAttributeType(CFStringRef string)
584{
585    EAPSIMAKAAttributeType	type = kAT_ANY_ID_REQ;
586
587    if (string != NULL) {
588	if (CFEqual(kEAPSIMAKAIdentityTypeFullAuthentication, string)) {
589	    type = kAT_FULLAUTH_ID_REQ;
590	}
591	else if (CFEqual(kEAPSIMAKAIdentityTypePermanent, string)) {
592	    type = kAT_PERMANENT_ID_REQ;
593	}
594    }
595    return (type);
596}
597
598/**
599 ** TLVBuffer routines
600 **/
601
602#define NBITS_PER_BYTE	8
603
604struct TLVBuffer {
605    uint8_t *		storage;
606    int			size;
607    int			offset;
608    char		err_str[160];
609};
610
611PRIVATE_EXTERN int
612TLVBufferSizeof(void)
613{
614    return (sizeof(struct TLVBuffer));
615}
616
617PRIVATE_EXTERN int
618TLVBufferUsed(TLVBufferRef tb)
619{
620    return (tb->offset);
621}
622
623PRIVATE_EXTERN const char *
624TLVBufferErrorString(TLVBufferRef tb)
625{
626    return (tb->err_str);
627}
628
629PRIVATE_EXTERN int
630TLVBufferMaxSize(TLVBufferRef tb)
631{
632    return (tb->size);
633}
634
635PRIVATE_EXTERN uint8_t *
636TLVBufferStorage(TLVBufferRef tb)
637{
638    return (tb->storage);
639}
640
641PRIVATE_EXTERN void
642TLVBufferInit(TLVBufferRef tb, uint8_t * storage, int size)
643{
644    tb->storage = storage;
645    tb->size = size;
646    tb->offset = 0;
647    tb->err_str[0] = '\0';
648    return;
649}
650
651PRIVATE_EXTERN TLVRef
652TLVBufferAllocateTLV(TLVBufferRef tb, EAPSIMAKAAttributeType type, int length)
653{
654    int		left;
655    int		padded_length;
656    TLVRef	tlv_p;
657
658    if (length < offsetof(TLV, tlv_value)) {
659	return (NULL);
660    }
661    padded_length = TLVRoundUp(length);
662    if (padded_length > TLV_MAX_LENGTH) {
663	snprintf(tb->err_str, sizeof(tb->err_str),
664		 "padded_length %d > max length %d",
665		 padded_length, TLV_MAX_LENGTH);
666	return (NULL);
667    }
668    left = tb->size - tb->offset;
669    if (left < padded_length) {
670	snprintf(tb->err_str, sizeof(tb->err_str),
671		 "available space %d < required %d",
672		 left, padded_length);
673	return (NULL);
674    }
675
676    /* set the type and length */
677    tlv_p = (TLVRef)(tb->storage + tb->offset);
678    tlv_p->tlv_type = type;
679    tlv_p->tlv_length = padded_length / TLV_ALIGNMENT;
680    tb->offset += padded_length;
681    return (tlv_p);
682}
683
684PRIVATE_EXTERN Boolean
685TLVBufferAddIdentity(TLVBufferRef tb_p,
686		     const uint8_t * identity, int identity_length)
687{
688    AttrUnion		attr;
689
690    attr.tlv_p = TLVBufferAllocateTLV(tb_p,
691				      kAT_IDENTITY,
692				      offsetof(AT_IDENTITY, id_identity)
693				      + identity_length);
694    if (attr.tlv_p == NULL) {
695	return (FALSE);
696    }
697    net_uint16_set(attr.at_identity->id_actual_length, identity_length);
698    bcopy(identity, attr.at_identity->id_identity, identity_length);
699    return (TRUE);
700}
701
702PRIVATE_EXTERN Boolean
703TLVBufferAddIdentityString(TLVBufferRef tb_p, CFStringRef identity,
704			   CFDataRef * ret_data)
705{
706    CFDataRef	data;
707    Boolean	result;
708
709    *ret_data = NULL;
710    data = CFStringCreateExternalRepresentation(NULL, identity,
711						kCFStringEncodingUTF8, 0);
712    if (data == NULL) {
713	return (FALSE);
714    }
715    result = TLVBufferAddIdentity(tb_p, CFDataGetBytePtr(data),
716				  CFDataGetLength(data));
717    if (result == TRUE && ret_data != NULL) {
718	*ret_data = data;
719    }
720    else {
721	CFRelease(data);
722    }
723    return (result);
724
725}
726
727PRIVATE_EXTERN Boolean
728TLVBufferAddCounter(TLVBufferRef tb_p, uint16_t at_counter)
729{
730    AT_COUNTER *	counter_p;
731
732    counter_p = (AT_COUNTER *)TLVBufferAllocateTLV(tb_p, kAT_COUNTER,
733						   sizeof(AT_COUNTER));
734    if (counter_p == NULL) {
735	return (FALSE);
736    }
737    net_uint16_set(counter_p->co_counter, at_counter);
738    return (TRUE);
739}
740
741PRIVATE_EXTERN Boolean
742TLVBufferAddCounterTooSmall(TLVBufferRef tb_p)
743{
744    AT_COUNTER_TOO_SMALL * counter_too_small_p;
745
746    counter_too_small_p = (AT_COUNTER_TOO_SMALL *)
747	TLVBufferAllocateTLV(tb_p, kAT_COUNTER_TOO_SMALL,
748			     sizeof(AT_COUNTER_TOO_SMALL));
749    if (counter_too_small_p == NULL) {
750	return (FALSE);
751    }
752    net_uint16_set(counter_too_small_p->cs_reserved, 0);
753    return (TRUE);
754}
755
756PRIVATE_EXTERN Boolean
757TLVBufferAddPadding(TLVBufferRef tb_p, int padding_length)
758{
759    AT_PADDING *	padding_p;
760
761    switch (padding_length) {
762    case 4:
763    case 8:
764    case 12:
765	break;
766    default:
767	snprintf(tb_p->err_str, sizeof(tb_p->err_str),
768		 "invalid AT_PADDING %d", padding_length);
769	return (FALSE);
770    }
771    padding_p = (AT_PADDING *)
772	TLVBufferAllocateTLV(tb_p, kAT_PADDING, padding_length);
773    if (padding_p == NULL) {
774	strlcpy(tb_p->err_str,"couldn't allocate TLV", sizeof(tb_p->err_str));
775	return (FALSE);
776    }
777    bzero(padding_p->pa_padding,
778	  padding_length - offsetof(AT_PADDING, pa_padding));
779    return (TRUE);
780}
781
782/**
783 ** TLVList routines
784 **/
785#define N_ATTRS_STATIC			10
786struct TLVList {
787    const void * *	attrs;		/* pointers to attributes */
788    const void *	attrs_static[N_ATTRS_STATIC];
789    int			count;
790    int			size;
791    char		err_str[160];
792};
793
794PRIVATE_EXTERN int
795TLVListSizeof(void)
796{
797    return (sizeof(struct TLVList));
798}
799
800INLINE int
801TLVListAttrsStaticSize(void)
802{
803    const TLVListRef	tlvs_p;
804
805    return ((int)sizeof(tlvs_p->attrs_static)
806	    / sizeof(tlvs_p->attrs_static[0]));
807}
808
809PRIVATE_EXTERN const char *
810TLVListErrorString(TLVListRef tlvs_p)
811{
812    return (tlvs_p->err_str);
813}
814
815PRIVATE_EXTERN void
816TLVListInit(TLVListRef tlvs_p)
817{
818    tlvs_p->attrs = NULL;
819    tlvs_p->count = tlvs_p->size = 0;
820    return;
821}
822
823PRIVATE_EXTERN void
824TLVListFree(TLVListRef tlvs_p)
825{
826    if (tlvs_p->attrs != NULL && tlvs_p->attrs != tlvs_p->attrs_static) {
827#ifdef TEST_TLVLIST_PARSE
828	printf("freeing data\n");
829#endif /* TEST_TLVLIST_PARSE */
830	free(tlvs_p->attrs);
831    }
832    TLVListInit(tlvs_p);
833    return;
834}
835
836PRIVATE_EXTERN void
837TLVListAddAttribute(TLVListRef tlvs_p, const uint8_t * attr)
838{
839    if (tlvs_p->attrs == NULL) {
840	tlvs_p->attrs = tlvs_p->attrs_static;
841	tlvs_p->size = TLVListAttrsStaticSize();
842    }
843    else if (tlvs_p->count == tlvs_p->size) {
844	tlvs_p->size += TLVListAttrsStaticSize();
845	if (tlvs_p->attrs == tlvs_p->attrs_static) {
846	    tlvs_p->attrs = (const void * *)
847		malloc(sizeof(*tlvs_p->attrs) * tlvs_p->size);
848	    bcopy(tlvs_p->attrs_static, tlvs_p->attrs,
849		  sizeof(*tlvs_p->attrs) * tlvs_p->count);
850	}
851	else {
852	    tlvs_p->attrs = (const void * *)
853		reallocf(tlvs_p->attrs,
854			 sizeof(*tlvs_p->attrs) * tlvs_p->size);
855	}
856    }
857    tlvs_p->attrs[tlvs_p->count++] = attr;
858    return;
859}
860
861enum {
862    kTLVGood = 0,
863    kTLVBad = 1,
864    kTLVUnrecognized = 2
865};
866
867PRIVATE_EXTERN int
868TLVCheckValidity(TLVListRef tlvs_p, TLVRef tlv_p)
869{
870    AttrUnion		attr;
871    int			i;
872    int			len;
873    int			n_bits;
874    int			offset;
875    int			ret = kTLVGood;
876    const uint8_t *	scan;
877    int			tlv_length;
878
879    attr.tlv_p = tlv_p;
880    tlv_length = tlv_p->tlv_length * TLV_ALIGNMENT;
881    switch (tlv_p->tlv_type) {
882    case kAT_RAND:
883	offset = offsetof(AT_RAND, ra_rand);
884	if (tlv_length <= offset) {
885	    /* truncated option */
886	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
887		     "%s truncated %d <= %d",
888		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
889		     tlv_length, offset);
890	    ret = kTLVBad;
891	    break;
892	}
893	len = tlv_length - offset;
894	if ((len % RAND_SIZE) != 0) {
895	    /* must be a multiple of 16 bytes */
896	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
897		     "AT_RAND rand length %d not multiple of %d",
898		     len, RAND_SIZE);
899	    ret = kTLVBad;
900	    break;
901	}
902	if (len == 0) {
903	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
904		     "AT_RAND contains no RANDs");
905	    ret = kTLVBad;
906	    break;
907	}
908	break;
909    case kAT_RES:
910	offset = offsetof(AT_RES, rs_res);
911	if (tlv_length <= offset) {
912	    /* truncated option */
913	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
914		     "%s truncated %d <= %d",
915		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
916		     tlv_length, offset);
917	    ret = kTLVBad;
918	    break;
919	}
920	n_bits = net_uint16_get(attr.at_res->rs_res_length);
921	len = (n_bits + NBITS_PER_BYTE - 1) / NBITS_PER_BYTE;
922	if (len > (tlv_length - offset)) {
923	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
924		     "%s actual length %d > TLV length %d",
925		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
926		     len, tlv_length - offset);
927	    ret = kTLVBad;
928	    break;
929	}
930	break;
931    case kAT_AUTS:
932	offset = offsetof(AT_AUTS, as_auts);
933	if (tlv_length <= offset) {
934	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
935		     "%s truncated %d <= %d",
936		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
937		     tlv_length, offset);
938	    ret = kTLVBad;
939	    break;
940	}
941	len = tlv_length - offset;
942	if (len != AUTS_SIZE) {
943	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
944		     "%s invalid length %d != %d",
945		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
946		     len, AUTS_SIZE);
947	    ret = kTLVBad;
948	    break;
949	}
950	break;
951    case kAT_PADDING:
952	switch (tlv_length) {
953	case 4:
954	case 8:
955	case 12:
956	    len = tlv_length - offsetof(AT_PADDING, pa_padding);
957	    for (i = 0, scan = attr.at_padding->pa_padding;
958		 i < len; i++, scan++) {
959		if (*scan != 0) {
960		    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
961			     "AT_PADDING non-zero value 0x%x at offset %d",
962			     *scan, i);
963		    ret = kTLVBad;
964		    break;
965		}
966	    }
967	    break;
968	default:
969	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
970		     "AT_PADDING length %d not 4, 8, or 12", tlv_length);
971	    ret = kTLVBad;
972	    break;
973	}
974	break;
975    case kAT_AUTN:
976    case kAT_NONCE_MT:
977    case kAT_IV:
978    case kAT_MAC:
979    case kAT_NONCE_S:
980	offset = offsetof(AT_NONCE_MT, nm_nonce_mt);
981	if (tlv_length <= offset) {
982	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
983		     "%s truncated %d <= %d",
984		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
985		     tlv_length, offset);
986	    ret = kTLVBad;
987	    break;
988	}
989	len = tlv_length - offset;
990	if (len != sizeof(attr.at_nonce_mt->nm_nonce_mt)) {
991	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
992		     "%s invalid length %d != %d",
993		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
994		     len, (int)sizeof(attr.at_nonce_mt->nm_nonce_mt));
995	    ret = kTLVBad;
996	    break;
997	}
998	break;
999    case kAT_IDENTITY:
1000    case kAT_VERSION_LIST:
1001    case kAT_NEXT_PSEUDONYM:
1002    case kAT_NEXT_REAUTH_ID:
1003	offset = offsetof(AT_IDENTITY, id_identity);
1004	if (tlv_length <= offset) {
1005	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1006		     "%s empty/truncated (%d <= %d)",
1007		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
1008		     tlv_length, offset);
1009	    ret = kTLVBad;
1010	    break;
1011	}
1012	len = net_uint16_get(attr.at_identity->id_actual_length);
1013	if (len > (tlv_length - offset)) {
1014	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1015		     "%s actual length %d > TLV length %d",
1016		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
1017		     len, tlv_length - offset);
1018	    ret = kTLVBad;
1019	    break;
1020	}
1021	if (tlv_p->tlv_type == kAT_VERSION_LIST && (len & 0x1) != 0) {
1022	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1023		     "AT_VERSION_LIST actual length %d not multiple of 2",
1024		     len);
1025	    ret = kTLVBad;
1026	    break;
1027	}
1028	break;
1029    case kAT_ENCR_DATA:
1030	offset = offsetof(AT_ENCR_DATA, ed_encrypted_data);
1031	if (tlv_length <= offset) {
1032	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1033		     "AT_ENCR_DATA empty/truncated (%d <= %d)",
1034		     tlv_length, offset);
1035	    ret = kTLVBad;
1036	    break;
1037	}
1038	break;
1039    case kAT_SELECTED_VERSION:
1040    case kAT_PERMANENT_ID_REQ:
1041    case kAT_ANY_ID_REQ:
1042    case kAT_FULLAUTH_ID_REQ:
1043    case kAT_RESULT_IND:
1044    case kAT_COUNTER:
1045    case kAT_COUNTER_TOO_SMALL:
1046    case kAT_CLIENT_ERROR_CODE:
1047    case kAT_NOTIFICATION:
1048	if (tlv_length != 4) {
1049	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1050		     "%s length %d != 4",
1051		     EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
1052		     tlv_length);
1053	    ret = kTLVBad;
1054	    break;
1055	}
1056	break;
1057    default:
1058	ret = kTLVUnrecognized;
1059	break;
1060    }
1061    return (ret);
1062}
1063
1064PRIVATE_EXTERN Boolean
1065TLVListParse(TLVListRef tlvs_p, const uint8_t * attrs, int attrs_length)
1066{
1067    int			offset;
1068    const uint8_t *	scan;
1069    Boolean		success = TRUE;
1070    int			tlv_length;
1071
1072    scan = attrs;
1073    offset = 0;
1074    while (TRUE) {
1075	int		left = attrs_length - offset;
1076	TLVRef		this_tlv;
1077	int		tlv_validity;
1078
1079	if (left == 0) {
1080	    /* we're done */
1081	    break;
1082	}
1083	if (left < TLV_HEADER_LENGTH) {
1084	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1085		     "Missing/truncated attribute at offset %d",
1086		     offset);
1087	    success = FALSE;
1088	    break;
1089	}
1090	this_tlv = (TLVRef)scan;
1091	tlv_length = this_tlv->tlv_length * TLV_ALIGNMENT;
1092	if (tlv_length > left) {
1093	    snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1094		     "%s too large %d (> %d) at offset %d",
1095		     EAPSIMAKAAttributeTypeGetString(this_tlv->tlv_type),
1096		     tlv_length, left, offset);
1097	    success = FALSE;
1098	    break;
1099	}
1100	tlv_validity = TLVCheckValidity(tlvs_p, this_tlv);
1101	if (tlv_validity == kTLVGood) {
1102	    TLVListAddAttribute(tlvs_p, scan);
1103	}
1104	else if (tlv_validity == kTLVBad
1105		 || ((tlv_validity == kTLVUnrecognized)
1106		     && (this_tlv->tlv_type
1107			 < kEAPSIM_TLV_SKIPPABLE_RANGE_START))) {
1108	    if (tlv_validity == kTLVUnrecognized) {
1109		snprintf(tlvs_p->err_str, sizeof(tlvs_p->err_str),
1110			 "unrecognized attribute %d", this_tlv->tlv_type);
1111	    }
1112	    success = FALSE;
1113	    break;
1114	}
1115	offset += tlv_length;;
1116	scan += tlv_length;
1117    }
1118    if (success == FALSE) {
1119	TLVListFree(tlvs_p);
1120    }
1121    return (success);
1122}
1123
1124#define _WIDTH	"%18"
1125
1126STATIC void
1127TLVPrintToString(CFMutableStringRef str, TLVRef tlv_p)
1128{
1129    AttrUnion		attr;
1130    char		buf[128];
1131    int			count;
1132    int			i;
1133    const char *	field_name;
1134    int			len;
1135    int			n_bits;
1136    int			pad_len;
1137    uint8_t *		scan;
1138    int			tlv_length;
1139    uint16_t		val16;
1140
1141    attr.tlv_p = tlv_p;
1142    tlv_length = tlv_p->tlv_length * TLV_ALIGNMENT;
1143    STRING_APPEND(str, "%s: Length %d\n",
1144		  EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type),
1145		  tlv_length);
1146    field_name = EAPSIMAKAAttributeTypeGetString(tlv_p->tlv_type) + 3;
1147    switch (tlv_p->tlv_type) {
1148    case kAT_RAND:
1149	STRING_APPEND(str, _WIDTH "s:\t", "(reserved)");
1150	print_bytes_cfstr(str, attr.at_rand->ra_reserved,
1151			  sizeof(attr.at_rand->ra_reserved));
1152	len = tlv_length - offsetof(AT_RAND, ra_rand);
1153	count = len / RAND_SIZE;
1154	STRING_APPEND(str, "\n" _WIDTH"s: (n=%d)\n", field_name, count);
1155	for (scan = attr.at_rand->ra_rand, i = 0;
1156	     i < count; i++, scan += RAND_SIZE) {
1157	    STRING_APPEND(str, _WIDTH "d:\t", i);
1158	    print_bytes_cfstr(str, scan, RAND_SIZE);
1159	    STRING_APPEND(str, "\n");
1160	}
1161	break;
1162    case kAT_RES:
1163	n_bits = net_uint16_get(attr.at_res->rs_res_length);
1164	len = (n_bits + NBITS_PER_BYTE - 1) / NBITS_PER_BYTE;
1165	STRING_APPEND(str, _WIDTH "s: %d bits (%d bytes)\n", field_name, n_bits, len);
1166	print_bytes_cfstr(str, attr.at_res->rs_res, len);
1167	STRING_APPEND(str, "\n");
1168	break;
1169    case kAT_AUTS:
1170	len = tlv_length - offsetof(AT_AUTS, as_auts);
1171	STRING_APPEND(str, _WIDTH "s: %d bytes\n", field_name, len);
1172	print_bytes_cfstr(str, attr.at_auts->as_auts, len);
1173	STRING_APPEND(str, "\n");
1174	break;
1175    case kAT_PADDING:
1176	len = tlv_length - offsetof(AT_PADDING, pa_padding);
1177	STRING_APPEND(str, _WIDTH "s: %d bytes\n", field_name, len);
1178	STRING_APPEND(str, _WIDTH "s\t", "");
1179	print_bytes_cfstr(str, attr.at_padding->pa_padding, len);
1180	STRING_APPEND(str, "\n");
1181	break;
1182    case kAT_AUTN:
1183    case kAT_NONCE_MT:
1184    case kAT_IV:
1185    case kAT_MAC:
1186    case kAT_NONCE_S:
1187	STRING_APPEND(str, _WIDTH "s:\t", "(reserved)");
1188	print_bytes_cfstr(str, attr.at_nonce_mt->nm_reserved,
1189			  sizeof(attr.at_nonce_mt->nm_reserved));
1190	STRING_APPEND(str, "\n" _WIDTH "s:\t", field_name);
1191	print_bytes_cfstr(str, attr.at_nonce_mt->nm_nonce_mt,
1192			  sizeof(attr.at_nonce_mt->nm_nonce_mt));
1193	STRING_APPEND(str, "\n");
1194	break;
1195    case kAT_VERSION_LIST:
1196	len = net_uint16_get(attr.at_version_list->vl_actual_length);
1197	count = len / sizeof(uint16_t);
1198	STRING_APPEND(str, _WIDTH "s: Actual Length %d\n", field_name, len);
1199	for (scan = attr.at_version_list->vl_version_list, i = 0;
1200	     i < count; i++, scan += sizeof(uint16_t)) {
1201	    uint16_t	this_vers = net_uint16_get(scan);
1202
1203	    STRING_APPEND(str, _WIDTH "d:\t%04d\n", i, this_vers);
1204	}
1205	pad_len = (tlv_length - offsetof(AT_VERSION_LIST, vl_version_list))
1206	    - len;
1207	snprintf(buf, sizeof(buf), "(%d pad bytes)", pad_len);
1208	STRING_APPEND(str, _WIDTH "s:\t", buf);
1209	print_bytes_cfstr(str, attr.at_identity->id_identity + len, pad_len);
1210	STRING_APPEND(str, "\n");
1211	break;
1212    case kAT_IDENTITY:
1213    case kAT_NEXT_PSEUDONYM:
1214    case kAT_NEXT_REAUTH_ID:
1215	len = net_uint16_get(attr.at_identity->id_actual_length);
1216	STRING_APPEND(str, _WIDTH "s: Actual Length %d\n", field_name, len);
1217	print_data_cfstr(str, attr.at_identity->id_identity, len);
1218	pad_len = (tlv_length - offsetof(AT_IDENTITY, id_identity)) - len;
1219	if (pad_len != 0) {
1220	    snprintf(buf, sizeof(buf), "(%d pad bytes)", pad_len);
1221	    STRING_APPEND(str, _WIDTH "s:\t", buf);
1222	    print_bytes_cfstr(str, attr.at_identity->id_identity + len, pad_len);
1223	    STRING_APPEND(str, "\n");
1224	}
1225	break;
1226    case kAT_ENCR_DATA:
1227	STRING_APPEND(str, _WIDTH "s:\t", "(reserved)");
1228	print_bytes_cfstr(str, attr.at_encr_data->ed_reserved,
1229			  sizeof(attr.at_encr_data->ed_reserved));
1230	len = tlv_length - offsetof(AT_ENCR_DATA, ed_encrypted_data);
1231	STRING_APPEND(str, "\n" _WIDTH "s: Length %d\n", field_name, len);
1232	print_data_cfstr(str, attr.at_encr_data->ed_encrypted_data, len);
1233	break;
1234    case kAT_SELECTED_VERSION:
1235    case kAT_COUNTER:
1236    case kAT_CLIENT_ERROR_CODE:
1237    case kAT_NOTIFICATION:
1238	val16 = net_uint16_get(attr.at_selected_version->sv_selected_version);
1239	STRING_APPEND(str, _WIDTH "s:\t%04d\n", field_name, val16);
1240	break;
1241    case kAT_PERMANENT_ID_REQ:
1242    case kAT_ANY_ID_REQ:
1243    case kAT_FULLAUTH_ID_REQ:
1244    case kAT_RESULT_IND:
1245    case kAT_COUNTER_TOO_SMALL:
1246	STRING_APPEND(str, _WIDTH "s:\t", "(reserved)");
1247	print_bytes_cfstr(str, attr.at_encr_data->ed_reserved,
1248			  sizeof(attr.at_encr_data->ed_reserved));
1249	STRING_APPEND(str, "\n");
1250	break;
1251    default:
1252	break;
1253    }
1254    return;
1255}
1256
1257PRIVATE_EXTERN CFStringRef
1258TLVListCopyDescription(TLVListRef tlvs_p)
1259{
1260    int			i;
1261    const void * *	scan;
1262    CFMutableStringRef 	str;
1263
1264    str = CFStringCreateMutable(NULL, 0);
1265    for (i = 0, scan = tlvs_p->attrs; i < tlvs_p->count; i++, scan++) {
1266	TLVRef	tlv_p = (TLVRef)(*scan);
1267
1268	TLVPrintToString(str, tlv_p);
1269    }
1270    return (str);
1271}
1272
1273PRIVATE_EXTERN TLVRef
1274TLVListLookupAttribute(TLVListRef tlvs_p, EAPSIMAKAAttributeType type)
1275{
1276    int			i;
1277    const void * *	scan;
1278
1279    for (i = 0, scan = tlvs_p->attrs; i < tlvs_p->count; i++, scan++) {
1280	TLVRef	tlv_p = (TLVRef)(*scan);
1281
1282	if (tlv_p->tlv_type == type) {
1283	    return (tlv_p);
1284	}
1285    }
1286    return (NULL);
1287}
1288
1289PRIVATE_EXTERN CFStringRef
1290TLVCreateString(TLVRef tlv_p)
1291{
1292    CFDataRef		data;
1293    int			len;
1294    AT_IDENTITY *	id_p = (AT_IDENTITY *)tlv_p;
1295    CFStringRef		str;
1296
1297    len = net_uint16_get(id_p->id_actual_length);
1298    data = CFDataCreateWithBytesNoCopy(NULL, id_p->id_identity, len,
1299				       kCFAllocatorNull);
1300    str = CFStringCreateFromExternalRepresentation(NULL, data,
1301						   kCFStringEncodingUTF8);
1302    CFRelease(data);
1303    return (str);
1304}
1305
1306PRIVATE_EXTERN CFStringRef
1307TLVListCreateStringFromAttribute(TLVListRef tlvs_p, EAPSIMAKAAttributeType type)
1308{
1309    TLVRef	tlv_p;
1310
1311    switch (type) {
1312    case kAT_NEXT_REAUTH_ID:
1313    case kAT_NEXT_PSEUDONYM:
1314	break;
1315    default:
1316	return (NULL);
1317    }
1318    tlv_p = TLVListLookupAttribute(tlvs_p, type);
1319    if (tlv_p == NULL) {
1320	return (NULL);
1321    }
1322    return (TLVCreateString(tlv_p));
1323}
1324
1325PRIVATE_EXTERN EAPSIMAKAAttributeType
1326TLVListLookupIdentityAttribute(TLVListRef tlvs_p)
1327{
1328    STATIC const EAPSIMAKAAttributeType S_types[] = {
1329	kAT_ANY_ID_REQ,
1330	kAT_FULLAUTH_ID_REQ,
1331	kAT_PERMANENT_ID_REQ
1332    };
1333    int 		i;
1334
1335    for (i = 0; i < sizeof(S_types) / sizeof(S_types[0]); i++) {
1336	if (TLVListLookupAttribute(tlvs_p, S_types[i]) != NULL) {
1337	    return (S_types[i]);
1338	}
1339    }
1340    return (0);
1341}
1342
1343/**
1344 **
1345 ** - - - -  T E S T   H A R N E S S E S   - - -
1346 **
1347 **/
1348
1349#ifdef EAPSIMAKA_PACKET_DUMP
1350PRIVATE_EXTERN bool
1351EAPSIMAKAPacketDump(FILE * out_f, EAPPacketRef pkt)
1352{
1353    bool		packet_is_valid = FALSE;
1354    CFStringRef		str;
1355
1356    str = EAPSIMAKAPacketCopyDescription(pkt, &packet_is_valid);
1357    if (str != NULL) {
1358	SCPrint(TRUE, out_f, CFSTR("%@"), str);
1359	CFRelease(str);
1360    }
1361    return (packet_is_valid);
1362}
1363#endif /* EAPSIMAKA_PACKET_DUMP */
1364
1365#ifdef TEST_TLVLIST_PARSE
1366/*
1367  A.3.  EAP-Request/SIM/Start
1368
1369  The server's first packet looks like this:
1370
1371  01                   ; Code: Request
1372  01                   ; Identifier: 1
1373  00 10                ; Length: 16 octets
1374  12                   ; Type: EAP-SIM
1375  0a                ; EAP-SIM subtype: Start
1376  00 00             ; (reserved)
1377  0f                ; Attribute type: AT_VERSION_LIST
1378  02             ; Attribute length: 8 octets (2*4)
1379  00 02          ; Actual version list length: 2 octets
1380  00 01          ; Version: 1
1381  00 00          ; (attribute padding)
1382*/
1383const uint8_t	eap_request_sim_start[] = {
1384    0x01,
1385    0x01,
1386    0x00, 0x10,
1387    0x12,
1388    0x0a,
1389    0x00, 0x00,
1390    0x0f,
1391    0x02,
1392    0x00, 0x02,
1393    0x00, 0x01,
1394    0x00, 0x00,
1395};
1396
1397/*
1398  A.4.  EAP-Response/SIM/Start
1399
1400  The client selects a nonce and responds with the following packet:
1401
1402  02                   ; Code: Response
1403  01                   ; Identifier: 1
1404  00 20                ; Length: 32 octets
1405  12                   ; Type: EAP-SIM
1406  0a                ; EAP-SIM subtype: Start
1407  00 00             ; (reserved)
1408  07                ; Attribute type: AT_NONCE_MT
1409  05             ; Attribute length: 20 octets (5*4)
1410  00 00          ; (reserved)
1411  01 23 45 67    ; NONCE_MT value
1412  89 ab cd ef
1413  fe dc ba 98
1414  76 54 32 10
1415  10                ; Attribute type: AT_SELECTED_VERSION
1416  01             ; Attribute length: 4 octets (1*4)
1417  00 01          ; Version: 1
1418
1419*/
1420const uint8_t	eap_response_sim_start[] = {
1421    0x02,
1422    0x01,
1423    0x00, 0x20,
1424    0x12,
1425    0x0a,
1426    0x00, 0x00,
1427    0x07,
1428    0x05,
1429    0x00, 0x00,
1430    0x01, 0x23, 0x45, 0x67,
1431    0x89, 0xab, 0xcd, 0xef,
1432    0xfe, 0xdc, 0xba, 0x98,
1433    0x76, 0x54, 0x32, 0x10,
1434    0x10,
1435    0x01,
1436    0x00, 0x01
1437};
1438
1439/*
1440  The EAP packet looks like this:
1441
1442  01                   ; Code: Request
1443  02                   ; Identifier: 2
1444  01 18                ; Length: 280 octets
1445  12                   ; Type: EAP-SIM
1446  0b                ; EAP-SIM subtype: Challenge
1447  00 00             ; (reserved)
1448  01                ; Attribute type: AT_RAND
1449  0d             ; Attribute length: 52 octets (13*4)
1450  00 00          ; (reserved)
1451  10 11 12 13    ; first RAND
1452  14 15 16 17
1453  18 19 1a 1b
1454  1c 1d 1e 1f
1455  20 21 22 23    ; second RAND
1456  24 25 26 27
1457  28 29 2a 2b
1458  2c 2d 2e 2f
1459  30 31 32 33    ; third RAND
1460  34 35 36 37
1461  38 39 3a 3b
1462  3c 3d 3e 3f
1463  81                ; Attribute type: AT_IV
1464  05             ; Attribute length: 20 octets (5*4)
1465  00 00          ; (reserved)
1466  9e 18 b0 c2    ; IV value
1467  9a 65 22 63
1468  c0 6e fb 54
1469  dd 00 a8 95
1470  82               ; Attribute type: AT_ENCR_DATA
1471  2d            ; Attribute length: 180 octets (45*4)
1472  00 00         ; (reserved)
1473  55 f2 93 9b bd b1 b1 9e a1 b4 7f c0 b3 e0 be 4c
1474  ab 2c f7 37 2d 98 e3 02 3c 6b b9 24 15 72 3d 58
1475  ba d6 6c e0 84 e1 01 b6 0f 53 58 35 4b d4 21 82
1476  78 ae a7 bf 2c ba ce 33 10 6a ed dc 62 5b 0c 1d
1477  5a a6 7a 41 73 9a e5 b5 79 50 97 3f c7 ff 83 01
1478  07 3c 6f 95 31 50 fc 30 3e a1 52 d1 e1 0a 2d 1f
1479  4f 52 26 da a1 ee 90 05 47 22 52 bd b3 b7 1d 6f
1480  0c 3a 34 90 31 6c 46 92 98 71 bd 45 cd fd bc a6
1481  11 2f 07 f8 be 71 79 90 d2 5f 6d d7 f2 b7 b3 20
1482  bf 4d 5a 99 2e 88 03 31 d7 29 94 5a ec 75 ae 5d
1483  43 c8 ed a5 fe 62 33 fc ac 49 4e e6 7a 0d 50 4d
1484  0b                ; Attribute type: AT_MAC
1485  05             ; Attribute length: 20 octets (5*4)
1486  00 00          ; (reserved)
1487  fe f3 24 ac    ; MAC value
1488  39 62 b5 9f
1489  3b d7 82 53
1490  ae 4d cb 6a
1491*/
1492const uint8_t	eap_request_fast_reauth[] = {
1493    0x01,
1494    0x02,
1495    0x01, 0x18,
1496    0x12,
1497    0x0b,
1498    0x00, 0x00,
1499    0x01,
1500    0x0d,
1501    0x00, 0x00,
1502    0x10, 0x11, 0x12, 0x13,
1503    0x14, 0x15, 0x16, 0x17,
1504    0x18, 0x19, 0x1a, 0x1b,
1505    0x1c, 0x1d, 0x1e, 0x1f,
1506    0x20, 0x21, 0x22, 0x23,
1507    0x24, 0x25, 0x26, 0x27,
1508    0x28, 0x29, 0x2a, 0x2b,
1509    0x2c, 0x2d, 0x2e, 0x2f,
1510    0x30, 0x31, 0x32, 0x33,
1511    0x34, 0x35, 0x36, 0x37,
1512    0x38, 0x39, 0x3a, 0x3b,
1513    0x3c, 0x3d, 0x3e, 0x3f,
1514    0x81,
1515    0x05,
1516    0x00, 0x00,
1517    0x9e, 0x18, 0xb0, 0xc2,
1518    0x9a, 0x65, 0x22, 0x63,
1519    0xc0, 0x6e, 0xfb, 0x54,
1520    0xdd, 0x00, 0xa8, 0x95,
1521    0x82,
1522    0x2d,
1523    0x00, 0x00,
1524    0x55, 0xf2, 0x93, 0x9b, 0xbd, 0xb1, 0xb1, 0x9e, 0xa1, 0xb4, 0x7f, 0xc0, 0xb3, 0xe0, 0xbe, 0x4c,
1525    0xab, 0x2c, 0xf7, 0x37, 0x2d, 0x98, 0xe3, 0x02, 0x3c, 0x6b, 0xb9, 0x24, 0x15, 0x72, 0x3d, 0x58,
1526    0xba, 0xd6, 0x6c, 0xe0, 0x84, 0xe1, 0x01, 0xb6, 0x0f, 0x53, 0x58, 0x35, 0x4b, 0xd4, 0x21, 0x82,
1527    0x78, 0xae, 0xa7, 0xbf, 0x2c, 0xba, 0xce, 0x33, 0x10, 0x6a, 0xed, 0xdc, 0x62, 0x5b, 0x0c, 0x1d,
1528    0x5a, 0xa6, 0x7a, 0x41, 0x73, 0x9a, 0xe5, 0xb5, 0x79, 0x50, 0x97, 0x3f, 0xc7, 0xff, 0x83, 0x01,
1529    0x07, 0x3c, 0x6f, 0x95, 0x31, 0x50, 0xfc, 0x30, 0x3e, 0xa1, 0x52, 0xd1, 0xe1, 0x0a, 0x2d, 0x1f,
1530    0x4f, 0x52, 0x26, 0xda, 0xa1, 0xee, 0x90, 0x05, 0x47, 0x22, 0x52, 0xbd, 0xb3, 0xb7, 0x1d, 0x6f,
1531    0x0c, 0x3a, 0x34, 0x90, 0x31, 0x6c, 0x46, 0x92, 0x98, 0x71, 0xbd, 0x45, 0xcd, 0xfd, 0xbc, 0xa6,
1532    0x11, 0x2f, 0x07, 0xf8, 0xbe, 0x71, 0x79, 0x90, 0xd2, 0x5f, 0x6d, 0xd7, 0xf2, 0xb7, 0xb3, 0x20,
1533    0xbf, 0x4d, 0x5a, 0x99, 0x2e, 0x88, 0x03, 0x31, 0xd7, 0x29, 0x94, 0x5a, 0xec, 0x75, 0xae, 0x5d,
1534    0x43, 0xc8, 0xed, 0xa5, 0xfe, 0x62, 0x33, 0xfc, 0xac, 0x49, 0x4e, 0xe6, 0x7a, 0x0d, 0x50, 0x4d,
1535    0x0b,
1536    0x05,
1537    0x00, 0x00,
1538    0xfe, 0xf3, 0x24, 0xac,
1539    0x39, 0x62, 0xb5, 0x9f,
1540    0x3b, 0xd7, 0x82, 0x53,
1541    0xae, 0x4d, 0xcb, 0x6a
1542};
1543
1544/*
1545  The following plaintext will be encrypted and stored in the
1546  AT_ENCR_DATA attribute:
1547
1548  84               ; Attribute type: AT_NEXT_PSEUDONYM
1549  13            ; Attribute length: 76 octets (19*4)
1550  00 46         ; Actual pseudonym length: 70 octets
1551  77 38 77 34 39 50 65 78 43 61 7a 57 4a 26 78 43
1552  49 41 52 6d 78 75 4d 4b 68 74 35 53 31 73 78 52
1553  44 71 58 53 45 46 42 45 67 33 44 63 5a 50 39 63
1554  49 78 54 65 35 4a 34 4f 79 49 77 4e 47 56 7a 78
1555  65 4a 4f 55 31 47
1556  00 00          ; (attribute padding)
1557  85                ; Attribute type: AT_NEXT_REAUTH_ID
1558  16             ; Attribute length: 88 octets (22*4)
1559  00 51          ; Actual re-auth identity length: 81 octets
1560  59 32 34 66 4e 53 72 7a 38 42 50 32 37 34 6a 4f
1561  4a 61 46 31 37 57 66 78 49 38 59 4f 37 51 58 30
1562  30 70 4d 58 6b 39 58 4d 4d 56 4f 77 37 62 72 6f
1563  61 4e 68 54 63 7a 75 46 71 35 33 61 45 70 4f 6b
1564  6b 33 4c 30 64 6d 40 65 61 70 73 69 6d 2e 66 6f
1565  6f
1566  00 00 00       ; (attribute padding)
1567  06                ; Attribute type: AT_PADDING
1568  03             ; Attribute length: 12 octets (3*4)
1569  00 00 00 00
1570  00 00 00 00
1571  00 00
1572
1573*/
1574const uint8_t	at_encr_attr[] = {
1575    /* faked out to look like packet */
1576    0x01,
1577    0x02,
1578    0x00, 0xb8,
1579    0x12,
1580    0x0b,
1581    0x00, 0x00,
1582    /* attrs */
1583    0x84,
1584    0x13,
1585    0x00, 0x46,
1586    0x77, 0x38, 0x77, 0x34, 0x39, 0x50, 0x65, 0x78, 0x43, 0x61, 0x7a, 0x57, 0x4a, 0x26, 0x78, 0x43,
1587    0x49, 0x41, 0x52, 0x6d, 0x78, 0x75, 0x4d, 0x4b, 0x68, 0x74, 0x35, 0x53, 0x31, 0x73, 0x78, 0x52,
1588    0x44, 0x71, 0x58, 0x53, 0x45, 0x46, 0x42, 0x45, 0x67, 0x33, 0x44, 0x63, 0x5a, 0x50, 0x39, 0x63,
1589    0x49, 0x78, 0x54, 0x65, 0x35, 0x4a, 0x34, 0x4f, 0x79, 0x49, 0x77, 0x4e, 0x47, 0x56, 0x7a, 0x78,
1590    0x65, 0x4a, 0x4f, 0x55, 0x31, 0x47,
1591    0x00, 0x00,
1592    0x85,
1593    0x16,
1594    0x00, 0x51,
1595    0x59, 0x32, 0x34, 0x66, 0x4e, 0x53, 0x72, 0x7a, 0x38, 0x42, 0x50, 0x32, 0x37, 0x34, 0x6a, 0x4f,
1596    0x4a, 0x61, 0x46, 0x31, 0x37, 0x57, 0x66, 0x78, 0x49, 0x38, 0x59, 0x4f, 0x37, 0x51, 0x58, 0x30,
1597    0x30, 0x70, 0x4d, 0x58, 0x6b, 0x39, 0x58, 0x4d, 0x4d, 0x56, 0x4f, 0x77, 0x37, 0x62, 0x72, 0x6f,
1598    0x61, 0x4e, 0x68, 0x54, 0x63, 0x7a, 0x75, 0x46, 0x71, 0x35, 0x33, 0x61, 0x45, 0x70, 0x4f, 0x6b,
1599    0x6b, 0x33, 0x4c, 0x30, 0x64, 0x6d, 0x40, 0x65, 0x61, 0x70, 0x73, 0x69, 0x6d, 0x2e, 0x66, 0x6f,
1600    0x6f,
1601    0x00, 0x00, 0x00,
1602    0x06,
1603    0x03,
1604    0x00, 0x00, 0x00, 0x00,
1605    0x00, 0x00, 0x00, 0x00,
1606    0x00, 0x00,
1607};
1608
1609const uint8_t	at_permanent_id_req[] = {
1610    0x01,
1611    0x02,
1612    0x00, 0x0c,
1613    0x12,
1614    0x0b,
1615    0x00, 0x00,
1616    /* PERMANENT_ID_REQ */
1617    0x0a,
1618    0x01,
1619    0x00, 0x00
1620};
1621
1622const uint8_t	bad_padding1[] = {
1623    0x01,
1624    0x02,
1625    0x00, 0x0f,
1626    0x12,
1627    0x0b,
1628    0x00, 0x00,
1629    /* PADDING */
1630    0x06,
1631    0x03,
1632    0x00, 0x00, 0x00, 0x00,
1633    0x00, 0x00, 0x00, 0x00,
1634    0x00, 0x10,
1635
1636};
1637
1638const uint8_t	bad_padding2[] = {
1639    0x01,
1640    0x02,
1641    0x00, 0x14,
1642    0x12,
1643    0x0b,
1644    0x00, 0x00,
1645    /* PADDING */
1646    0x06,
1647    0x03,
1648    0x00, 0x00, 0x00, 0x00,
1649    0x00, 0x00, 0x00, 0x00,
1650    0x00, 0x10,
1651
1652};
1653
1654const uint8_t	bad_padding3[] = {
1655    0x01,
1656    0x02,
1657    0x00, 0x18,
1658    0x12,
1659    0x0b,
1660    0x00, 0x00,
1661    /* PADDING */
1662    0x06,
1663    0x04,
1664    0x00, 0x00, 0x00, 0x00,
1665    0x00, 0x00, 0x00, 0x00,
1666    0x00, 0x00, 0x00, 0x00,
1667    0x00, 0x00
1668};
1669
1670const uint8_t	bad_at_encr_attr[] = {
1671    /* faked out to look like packet */
1672    0x01,
1673    0x02,
1674    0x00, 0xb8,
1675    0x12,
1676    0x0b,
1677    0x00, 0x00,
1678    /* attrs */
1679    0x84,
1680    0x13,
1681    0x00, 0x4a,
1682    0x77, 0x38, 0x77, 0x34, 0x39, 0x50, 0x65, 0x78, 0x43, 0x61, 0x7a, 0x57, 0x4a, 0x26, 0x78, 0x43,
1683    0x49, 0x41, 0x52, 0x6d, 0x78, 0x75, 0x4d, 0x4b, 0x68, 0x74, 0x35, 0x53, 0x31, 0x73, 0x78, 0x52,
1684    0x44, 0x71, 0x58, 0x53, 0x45, 0x46, 0x42, 0x45, 0x67, 0x33, 0x44, 0x63, 0x5a, 0x50, 0x39, 0x63,
1685    0x49, 0x78, 0x54, 0x65, 0x35, 0x4a, 0x34, 0x4f, 0x79, 0x49, 0x77, 0x4e, 0x47, 0x56, 0x7a, 0x78,
1686    0x65, 0x4a, 0x4f, 0x55, 0x31, 0x47,
1687    0x00, 0x00,
1688    0x85,
1689    0x16,
1690    0x00, 0x51,
1691    0x59, 0x32, 0x34, 0x66, 0x4e, 0x53, 0x72, 0x7a, 0x38, 0x42, 0x50, 0x32, 0x37, 0x34, 0x6a, 0x4f,
1692    0x4a, 0x61, 0x46, 0x31, 0x37, 0x57, 0x66, 0x78, 0x49, 0x38, 0x59, 0x4f, 0x37, 0x51, 0x58, 0x30,
1693    0x30, 0x70, 0x4d, 0x58, 0x6b, 0x39, 0x58, 0x4d, 0x4d, 0x56, 0x4f, 0x77, 0x37, 0x62, 0x72, 0x6f,
1694    0x61, 0x4e, 0x68, 0x54, 0x63, 0x7a, 0x75, 0x46, 0x71, 0x35, 0x33, 0x61, 0x45, 0x70, 0x4f, 0x6b,
1695    0x6b, 0x33, 0x4c, 0x30, 0x64, 0x6d, 0x40, 0x65, 0x61, 0x70, 0x73, 0x69, 0x6d, 0x2e, 0x66, 0x6f,
1696    0x6f,
1697    0x00, 0x00, 0x00,
1698    0x06,
1699    0x03,
1700    0x00, 0x00, 0x00, 0x00,
1701    0x00, 0x00, 0x00, 0x00,
1702    0x00, 0x00,
1703};
1704
1705struct {
1706    const uint8_t *	packet;
1707    int			size;
1708    bool		good;
1709    const char *	name;
1710} packets[] = {
1711    { eap_request_sim_start, sizeof(eap_request_sim_start), TRUE, "eap_request_sim_start" },
1712    { eap_response_sim_start, sizeof(eap_response_sim_start), TRUE, "eap_response_sim_start" },
1713    { eap_request_fast_reauth, sizeof(eap_request_fast_reauth), TRUE, "eap_request_fast_reauth" },
1714    { at_encr_attr, sizeof(at_encr_attr), TRUE, "at_encr_attr" },
1715    { at_permanent_id_req, sizeof(at_permanent_id_req), TRUE, "at_permanent_id_req" },
1716    { bad_padding1, sizeof(bad_padding1), FALSE, "bad_padding1" },
1717    { bad_padding2, sizeof(bad_padding2), FALSE, "bad_padding2" },
1718    { bad_padding3, sizeof(bad_padding3), FALSE, "bad_padding3" },
1719    { bad_at_encr_attr, sizeof(bad_at_encr_attr), FALSE, "bad_at_encr_attr" },
1720    { NULL, 0 }
1721};
1722
1723int
1724main(int argc, char * argv[])
1725{
1726    AttrUnion			attr;
1727    int				i;
1728    EAPSIMPacketRef		pkt;
1729    uint8_t			buf[1028];
1730    TLVBufferDeclare(		tlv_buf_p);
1731
1732    for (i = 0; packets[i].packet != NULL; i++) {
1733	bool	good;
1734
1735	pkt = (EAPSIMPacketRef)packets[i].packet;
1736	good = EAPSIMAKAPacketDump(stdout, (EAPPacketRef)pkt);
1737	printf("Test %d '%s' %s (found%serrors)\n", i,
1738	       packets[i].name,
1739	       good == packets[i].good ? "PASSED" : "FAILED",
1740	       !good ? " " : " no ");
1741	printf("\n");
1742    }
1743    pkt = (EAPSIMPacketRef)buf;
1744    TLVBufferInit(tlv_buf_p, pkt->attrs,
1745		  sizeof(buf) - offsetof(EAPSIMPacket, attrs));
1746    attr.tlv_p = TLVBufferAllocateTLV(tlv_buf_p, kAT_SELECTED_VERSION,
1747				      sizeof(AT_SELECTED_VERSION));
1748    if (attr.tlv_p == NULL) {
1749	fprintf(stderr, "failed allocating AT_SELECTED_VERSION, %s\n",
1750		TLVBufferErrorString(tlv_buf_p));
1751	exit(2);
1752    }
1753    net_uint16_set(attr.at_selected_version->sv_selected_version,
1754		   kEAPSIMVersion1);
1755    pkt->code = kEAPCodeResponse;
1756    pkt->identifier = 1;
1757    pkt->type = kEAPTypeEAPSIM;
1758    pkt->subtype = kEAPSIMAKAPacketSubtypeSIMStart;
1759    EAPPacketSetLength((EAPPacketRef)pkt,
1760		       offsetof(EAPSIMPacket, attrs)
1761		       + TLVBufferUsed(tlv_buf_p));
1762    if (EAPSIMAKAPacketDump(stdout, (EAPPacketRef)pkt) == FALSE) {
1763	fprintf(stderr, "Parse failed!\n");
1764	exit(2);
1765    }
1766
1767    exit(0);
1768    return (0);
1769}
1770
1771#endif /* TEST_TLVLIST_PARSE */
1772
1773#ifdef TEST_SIM_CRYPTO
1774#include <CommonCrypto/CommonDigest.h>
1775#include <CommonCrypto/CommonCryptor.h>
1776#include <CommonCrypto/CommonHMAC.h>
1777#include <CoreFoundation/CFPropertyList.h>
1778#include "fips186prf.h"
1779
1780typedef struct {
1781    uint8_t	Kc[SIM_KC_SIZE];
1782} SIMKc, *SIMKcRef;
1783
1784typedef struct {
1785    uint8_t	SRES[SIM_SRES_SIZE];
1786} SIMSRES, *SIMSRESRef;
1787
1788typedef struct {
1789    uint8_t	RAND[SIM_RAND_SIZE];
1790} SIMRAND, *SIMRANDRef;
1791
1792/*
1793  A.5.  EAP-Request/SIM/Challenge
1794
1795  Next, the server selects three authentication triplets
1796
1797  (RAND1,SRES1,Kc1) = (10111213 14151617 18191a1b 1c1d1e1f,
1798  d1d2d3d4,
1799  a0a1a2a3 a4a5a6a7)
1800  (RAND2,SRES2,Kc2) = (20212223 24252627 28292a2b 2c2d2e2f,
1801  e1e2e3e4,
1802  b0b1b2b3 b4b5b6b7)
1803  (RAND3,SRES3,Kc3) = (30313233 34353637 38393a3b 3c3d3e3f,
1804  f1f2f3f4,
1805  c0c1c2c3 c4c5c6c7)
1806*/
1807
1808const SIMKc	test_kc[EAPSIM_MAX_RANDS] = {
1809    { { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7 } },
1810    { { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7 } },
1811    { { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 } },
1812};
1813
1814const SIMSRES	test_sres[EAPSIM_MAX_RANDS] = {
1815    { { 0xd1, 0xd2, 0xd3, 0xd4 } },
1816    { { 0xe1, 0xe2, 0xe3, 0xe4 } },
1817    { { 0xf1, 0xf2, 0xf3, 0xf4 } }
1818};
1819
1820const SIMRAND test_rand[EAPSIM_MAX_RANDS] = {
1821    { { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1822	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f } },
1823    { { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
1824	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f } } ,
1825    { { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
1826	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f } }
1827};
1828
1829const uint8_t 	test_nonce_mt[NONCE_MT_SIZE] = {
1830    0x01, 0x23, 0x45, 0x67,
1831    0x89, 0xab, 0xcd, 0xef,
1832    0xfe, 0xdc, 0xba, 0x98,
1833    0x76, 0x54, 0x32, 0x10
1834};
1835const uint8_t	test_identity[] = "1244070100000001@eapsim.foo";
1836
1837/*
1838  Next, the MK is calculated as specified in Section 7*.
1839
1840  MK = e576d5ca 332e9930 018bf1ba ee2763c7 95b3c712
1841
1842  And the other keys are derived using the PRNG:
1843
1844  K_encr = 536e5ebc 4465582a a6a8ec99 86ebb620
1845  K_aut =  25af1942 efcbf4bc 72b39434 21f2a974
1846  MSK =    39d45aea f4e30601 983e972b 6cfd46d1
1847  c3637733 65690d09 cd44976b 525f47d3
1848  a60a985e 955c53b0 90b2e4b7 3719196a
1849  40254296 8fd14a88 8f46b9a7 886e4488
1850  EMSK =   5949eab0 fff69d52 315c6c63 4fd14a7f
1851  0d52023d 56f79698 fa6596ab eed4f93f
1852  bb48eb53 4d985414 ceed0d9a 8ed33c38
1853  7c9dfdab 92ffbdf2 40fcecf6 5a2c93b9
1854*/
1855
1856const uint8_t	test_mk[CC_SHA1_DIGEST_LENGTH] = {
1857    0xe5, 0x76, 0xd5, 0xca,
1858    0x33, 0x2e, 0x99, 0x30,
1859    0x01, 0x8b, 0xf1, 0xba,
1860    0xee, 0x27, 0x63, 0xc7,
1861    0x95, 0xb3, 0xc7, 0x12
1862};
1863
1864#define EAPSIMAKA_KEY_SIZE	(EAPSIMAKA_K_ENCR_SIZE + EAPSIMAKA_K_AUT_SIZE \
1865				 + EAPSIMAKA_MSK_SIZE + EAPSIMAKA_EMSK_SIZE)
1866
1867uint8_t key_block[EAPSIMAKA_KEY_SIZE] = {
1868    0x53, 0x6e, 0x5e, 0xbc, 0x44, 0x65, 0x58, 0x2a, 0xa6, 0xa8, 0xec, 0x99,  0x86, 0xeb, 0xb6, 0x20,
1869    0x25, 0xaf, 0x19, 0x42, 0xef, 0xcb, 0xf4, 0xbc, 0x72, 0xb3, 0x94, 0x34,  0x21, 0xf2, 0xa9, 0x74,
1870    0x39, 0xd4, 0x5a, 0xea, 0xf4, 0xe3, 0x06, 0x01, 0x98, 0x3e, 0x97, 0x2b,  0x6c, 0xfd, 0x46, 0xd1,
1871    0xc3, 0x63, 0x77, 0x33, 0x65, 0x69, 0x0d, 0x09, 0xcd, 0x44, 0x97, 0x6b,  0x52, 0x5f, 0x47, 0xd3,
1872    0xa6, 0x0a, 0x98, 0x5e, 0x95, 0x5c, 0x53, 0xb0, 0x90, 0xb2, 0xe4, 0xb7,  0x37, 0x19, 0x19, 0x6a,
1873    0x40, 0x25, 0x42, 0x96, 0x8f, 0xd1, 0x4a, 0x88, 0x8f, 0x46, 0xb9, 0xa7,  0x88, 0x6e, 0x44, 0x88,
1874    0x59, 0x49, 0xea, 0xb0, 0xff, 0xf6, 0x9d, 0x52, 0x31, 0x5c, 0x6c, 0x63,  0x4f, 0xd1, 0x4a, 0x7f,
1875    0x0d, 0x52, 0x02, 0x3d, 0x56, 0xf7, 0x96, 0x98, 0xfa, 0x65, 0x96, 0xab,  0xee, 0xd4, 0xf9, 0x3f,
1876    0xbb, 0x48, 0xeb, 0x53, 0x4d, 0x98, 0x54, 0x14, 0xce, 0xed, 0x0d, 0x9a,  0x8e, 0xd3, 0x3c, 0x38,
1877    0x7c, 0x9d, 0xfd, 0xab, 0x92, 0xff, 0xbd, 0xf2, 0x40, 0xfc, 0xec, 0xf6,  0x5a, 0x2c, 0x93, 0xb9,
1878};
1879
1880const uint8_t		test_version_list[2] = { 0x0, 0x1 };
1881const uint8_t		test_selected_version[2] = { 0x0, 0x1 };
1882
1883const uint8_t		test_packet[] = {
1884    0x01, 	/* code = 1 (request) */
1885    0x37, 	/* identifier = 55 */
1886    0x00, 0x50, /* length = 0x50 = 80 */
1887    0x12,	/* type = 0x12 = 18 = EAP-SIM */
1888    0x0b,	/* subtype = 0x0b = 11 = Challenge */
1889    0x00, 0x00, /* reserved */
1890
1891    /* AT_RAND */
1892    0x01,
1893    0x0d,	/* 0x0d (13) * 4 = 52 bytes */
1894    0x00, 0x00, /* reserved */
1895    0x10, 0x11, 0x12, 0x13,
1896    0x14, 0x15, 0x16, 0x17,
1897    0x18, 0x19, 0x1a, 0x1b,
1898    0x1c, 0x1d, 0x1e, 0x1f,
1899    0x20, 0x21, 0x22, 0x23,
1900    0x24, 0x25, 0x26, 0x27,
1901    0x28, 0x29, 0x2a, 0x2b,
1902    0x2c, 0x2d, 0x2e, 0x2f,
1903    0x30, 0x31, 0x32, 0x33,
1904    0x34, 0x35, 0x36, 0x37,
1905    0x38, 0x39, 0x3a, 0x3b,
1906    0x3c, 0x3d, 0x3e, 0x3f,
1907
1908    /* AT_MAC */
1909    0x0b,
1910    0x05,	/* 0x05 * 4 = 20 bytes */
1911    0x00, 0x00,	/* padding */
1912    0x00, 0x97, 0xc3, 0x64,
1913    0xf8, 0x43, 0x1d, 0xa4,
1914    0x92, 0x5b, 0xb2, 0xb1,
1915    0x95, 0xd0, 0xbe, 0x22
1916};
1917
1918static void
1919dump_plist(FILE * f, CFTypeRef p)
1920{
1921    CFDataRef	data;
1922    data = CFPropertyListCreateXMLData(NULL, p);
1923    if (data == NULL) {
1924	return;
1925    }
1926    fwrite(CFDataGetBytePtr(data), CFDataGetLength(data), 1, f);
1927    CFRelease(data);
1928    return;
1929}
1930
1931static void
1932dump_triplets(void)
1933{
1934    CFMutableDictionaryRef	dict;
1935    int				i;
1936    CFMutableArrayRef		array;
1937
1938    dict = CFDictionaryCreateMutable(NULL, 0,
1939				     &kCFTypeDictionaryKeyCallBacks,
1940				     &kCFTypeDictionaryValueCallBacks);
1941
1942    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1943    for (i = 0; i < EAPSIM_MAX_RANDS; i++) {
1944	CFDataRef		data;
1945
1946	data = CFDataCreateWithBytesNoCopy(NULL, test_kc[i].Kc, SIM_KC_SIZE,
1947					   kCFAllocatorNull);
1948	CFArrayAppendValue(array, data);
1949	CFRelease(data);
1950    }
1951    CFDictionarySetValue(dict, CFSTR("KcList"), array);
1952    CFRelease(array);
1953
1954    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1955    for (i = 0; i < EAPSIM_MAX_RANDS; i++) {
1956	CFDataRef		data;
1957
1958	data = CFDataCreateWithBytesNoCopy(NULL, test_sres[i].SRES,
1959					   SIM_SRES_SIZE,
1960					   kCFAllocatorNull);
1961	CFArrayAppendValue(array, data);
1962	CFRelease(data);
1963    }
1964    CFDictionarySetValue(dict, CFSTR("SRESList"), array);
1965    CFRelease(array);
1966
1967    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1968    for (i = 0; i < EAPSIM_MAX_RANDS; i++) {
1969	CFDataRef		data;
1970
1971	data = CFDataCreateWithBytesNoCopy(NULL, test_rand[i].RAND,
1972					   SIM_RAND_SIZE,
1973					   kCFAllocatorNull);
1974	CFArrayAppendValue(array, data);
1975	CFRelease(data);
1976    }
1977    CFDictionarySetValue(dict, CFSTR("RANDList"), array);
1978    CFRelease(array);
1979
1980    dump_plist(stdout, dict);
1981    CFRelease(dict);
1982    return;
1983}
1984
1985
1986const uint8_t	attrs_plaintext[] = {
1987    0x84,
1988    0x13,
1989    0x00, 0x46,
1990    0x77, 0x38, 0x77, 0x34, 0x39, 0x50, 0x65, 0x78, 0x43, 0x61, 0x7a, 0x57, 0x4a, 0x26, 0x78, 0x43,
1991    0x49, 0x41, 0x52, 0x6d, 0x78, 0x75, 0x4d, 0x4b, 0x68, 0x74, 0x35, 0x53, 0x31, 0x73, 0x78, 0x52,
1992    0x44, 0x71, 0x58, 0x53, 0x45, 0x46, 0x42, 0x45, 0x67, 0x33, 0x44, 0x63, 0x5a, 0x50, 0x39, 0x63,
1993    0x49, 0x78, 0x54, 0x65, 0x35, 0x4a, 0x34, 0x4f, 0x79, 0x49, 0x77, 0x4e, 0x47, 0x56, 0x7a, 0x78,
1994    0x65, 0x4a, 0x4f, 0x55, 0x31, 0x47,
1995    0x00, 0x00,
1996    0x85,
1997    0x16,
1998    0x00, 0x51,
1999    0x59, 0x32, 0x34, 0x66, 0x4e, 0x53, 0x72, 0x7a, 0x38, 0x42, 0x50, 0x32, 0x37, 0x34, 0x6a, 0x4f,
2000    0x4a, 0x61, 0x46, 0x31, 0x37, 0x57, 0x66, 0x78, 0x49, 0x38, 0x59, 0x4f, 0x37, 0x51, 0x58, 0x30,
2001    0x30, 0x70, 0x4d, 0x58, 0x6b, 0x39, 0x58, 0x4d, 0x4d, 0x56, 0x4f, 0x77, 0x37, 0x62, 0x72, 0x6f,
2002    0x61, 0x4e, 0x68, 0x54, 0x63, 0x7a, 0x75, 0x46, 0x71, 0x35, 0x33, 0x61, 0x45, 0x70, 0x4f, 0x6b,
2003    0x6b, 0x33, 0x4c, 0x30, 0x64, 0x6d, 0x40, 0x65, 0x61, 0x70, 0x73, 0x69, 0x6d, 0x2e, 0x66, 0x6f,
2004    0x6f,
2005    0x00, 0x00, 0x00,
2006    0x06,
2007    0x03,
2008    0x00, 0x00, 0x00, 0x00,
2009    0x00, 0x00, 0x00, 0x00,
2010    0x00, 0x00
2011};
2012
2013const static uint8_t	attrs_encrypted[] = {
2014    0x55, 0xf2, 0x93, 0x9b, 0xbd, 0xb1, 0xb1, 0x9e,
2015    0xa1, 0xb4, 0x7f, 0xc0, 0xb3, 0xe0, 0xbe, 0x4c,
2016    0xab, 0x2c, 0xf7, 0x37, 0x2d, 0x98, 0xe3, 0x02,
2017    0x3c, 0x6b, 0xb9, 0x24, 0x15, 0x72, 0x3d, 0x58,
2018    0xba, 0xd6, 0x6c, 0xe0, 0x84, 0xe1, 0x01, 0xb6,
2019    0x0f, 0x53, 0x58, 0x35, 0x4b, 0xd4, 0x21, 0x82,
2020    0x78, 0xae, 0xa7, 0xbf, 0x2c, 0xba, 0xce, 0x33,
2021    0x10, 0x6a, 0xed, 0xdc, 0x62, 0x5b, 0x0c, 0x1d,
2022    0x5a, 0xa6, 0x7a, 0x41, 0x73, 0x9a, 0xe5, 0xb5,
2023    0x79, 0x50, 0x97, 0x3f, 0xc7, 0xff, 0x83, 0x01,
2024    0x07, 0x3c, 0x6f, 0x95, 0x31, 0x50, 0xfc, 0x30,
2025    0x3e, 0xa1, 0x52, 0xd1, 0xe1, 0x0a, 0x2d, 0x1f,
2026    0x4f, 0x52, 0x26, 0xda, 0xa1, 0xee, 0x90, 0x05,
2027    0x47, 0x22, 0x52, 0xbd, 0xb3, 0xb7, 0x1d, 0x6f,
2028    0x0c, 0x3a, 0x34, 0x90, 0x31, 0x6c, 0x46, 0x92,
2029    0x98, 0x71, 0xbd, 0x45, 0xcd, 0xfd, 0xbc, 0xa6,
2030    0x11, 0x2f, 0x07, 0xf8, 0xbe, 0x71, 0x79, 0x90,
2031    0xd2, 0x5f, 0x6d, 0xd7, 0xf2, 0xb7, 0xb3, 0x20,
2032    0xbf, 0x4d, 0x5a, 0x99, 0x2e, 0x88, 0x03, 0x31,
2033    0xd7, 0x29, 0x94, 0x5a, 0xec, 0x75, 0xae, 0x5d,
2034    0x43, 0xc8, 0xed, 0xa5, 0xfe, 0x62, 0x33, 0xfc,
2035    0xac, 0x49, 0x4e, 0xe6, 0x7a, 0x0d, 0x50, 0x4d
2036};
2037
2038const static uint8_t	test_iv[] = {
2039    0x9e, 0x18, 0xb0, 0xc2,
2040    0x9a, 0x65, 0x22, 0x63,
2041    0xc0, 0x6e, 0xfb, 0x54,
2042    0xdd, 0x00, 0xa8, 0x95
2043};
2044
2045static void
2046test_encr_data(void)
2047{
2048    uint8_t 		buf[sizeof(attrs_encrypted)];
2049    size_t		buf_used;
2050    CCCryptorRef	cryptor;
2051    EAPSIMAKAKeyInfoRef	key_info_p = (EAPSIMAKAKeyInfoRef)key_block;
2052    CCCryptorStatus 	status;
2053
2054    status = CCCryptorCreate(kCCEncrypt,
2055			     kCCAlgorithmAES128,
2056			     0,
2057			     key_info_p->s.k_encr,
2058			     sizeof(key_info_p->s.k_encr),
2059			     test_iv,
2060			     &cryptor);
2061    if (status != kCCSuccess) {
2062	fprintf(stderr, "CCCryptoCreate failed with %d\n",
2063		status);
2064	return;
2065    }
2066    status = CCCryptorUpdate(cryptor,
2067			     attrs_plaintext,
2068			     sizeof(attrs_plaintext),
2069			     buf,
2070			     sizeof(buf),
2071			     &buf_used);
2072    if (status != kCCSuccess) {
2073	fprintf(stderr, "CCCryptoUpdate failed with %d\n",
2074		status);
2075	goto done;
2076    }
2077    if (buf_used != sizeof(buf)) {
2078	fprintf(stderr, "buf consumed %d, should have been %d\n",
2079		(int)buf_used, (int)sizeof(buf));
2080	goto done;
2081    }
2082
2083    if (bcmp(attrs_encrypted, buf, sizeof(attrs_encrypted))) {
2084	fprintf(stderr, "encryption yielded different results\n");
2085	goto done;
2086    }
2087    fprintf(stderr, "encryption matches!\n");
2088
2089 done:
2090    status = CCCryptorRelease(cryptor);
2091    if (status != kCCSuccess) {
2092	fprintf(stderr, "CCCryptoRelease failed with %d\n",
2093		status);
2094	return;
2095    }
2096    return;
2097}
2098
2099static void
2100test_decrypt_data(void)
2101{
2102    uint8_t 		buf[sizeof(attrs_encrypted)];
2103    size_t		buf_used;
2104    CCCryptorRef	cryptor;
2105    EAPSIMAKAKeyInfoRef	key_info_p = (EAPSIMAKAKeyInfoRef)key_block;
2106    CCCryptorStatus 	status;
2107
2108    status = CCCryptorCreate(kCCDecrypt,
2109			     kCCAlgorithmAES128,
2110			     0,
2111			     key_info_p->s.k_encr,
2112			     sizeof(key_info_p->s.k_encr),
2113			     test_iv,
2114			     &cryptor);
2115    if (status != kCCSuccess) {
2116	fprintf(stderr, "CCCryptoCreate failed with %d\n",
2117		status);
2118	return;
2119    }
2120    status = CCCryptorUpdate(cryptor,
2121			     attrs_encrypted,
2122			     sizeof(attrs_encrypted),
2123			     buf,
2124			     sizeof(buf),
2125			     &buf_used);
2126    if (status != kCCSuccess) {
2127	fprintf(stderr, "CCCryptoUpdate failed with %d\n",
2128		status);
2129	goto done;
2130    }
2131    if (buf_used != sizeof(buf)) {
2132	fprintf(stderr, "buf consumed %d, should have been %d\n",
2133		(int)buf_used, (int)sizeof(buf));
2134	goto done;
2135    }
2136
2137    if (bcmp(attrs_plaintext, buf, sizeof(attrs_plaintext))) {
2138	fprintf(stderr, "decryption yielded different results\n");
2139	goto done;
2140    }
2141    fprintf(stderr, "decryption matches!\n");
2142
2143 done:
2144    status = CCCryptorRelease(cryptor);
2145    if (status != kCCSuccess) {
2146	fprintf(stderr, "CCCryptoRelease failed with %d\n",
2147		status);
2148	return;
2149    }
2150    return;
2151}
2152
2153int
2154main(int argc, char * argv[])
2155{
2156    int			attrs_length;
2157    CC_SHA1_CTX		context;
2158    EAPSIMPacketRef	eapsim;
2159    uint8_t		hash[CC_SHA1_DIGEST_LENGTH];
2160    EAPSIMAKAKeyInfo	key_info;
2161    AT_MAC *		mac_p;
2162    uint8_t		mk[CC_SHA1_DIGEST_LENGTH];
2163    TLVListDeclare(	tlvs_p);
2164
2165    /* MK = SHA1(Identity|n*Kc| NONCE_MT| Version List| Selected Version) */
2166    CC_SHA1_Init(&context);
2167    CC_SHA1_Update(&context, test_identity, sizeof(test_identity) - 1);
2168    CC_SHA1_Update(&context, test_kc, sizeof(test_kc));
2169    CC_SHA1_Update(&context, test_nonce_mt, sizeof(test_nonce_mt));
2170    CC_SHA1_Update(&context, test_version_list, sizeof(test_version_list));
2171    CC_SHA1_Update(&context, test_selected_version,
2172		   sizeof(test_selected_version));
2173    CC_SHA1_Final(mk, &context);
2174
2175    if (bcmp(mk, test_mk, sizeof(test_mk))) {
2176	fprintf(stderr, "The mk values are different\n");
2177	printf("Computed:\n");
2178	print_data(mk, sizeof(mk));
2179	printf("Desired:\n");
2180	print_data((void *)test_mk, sizeof(test_mk));
2181    }
2182    else {
2183	printf("The MK values are the same!\n");
2184	printf("Computed:\n");
2185	print_data(mk, sizeof(mk));
2186	printf("Desired:\n");
2187	print_data((void *)test_mk, sizeof(test_mk));
2188    }
2189
2190    /* now run PRF to generate keying material */
2191    fips186_2prf(mk, key_info.key);
2192
2193    /* make sure the key blocks are the same */
2194    if (bcmp(key_info.key, key_block, sizeof(key_info.key))) {
2195	fprintf(stderr, "key blocks are different!\n");
2196	exit(1);
2197    }
2198    else {
2199	printf("key blocks match\n");
2200    }
2201
2202    if (EAPSIMAKAPacketDump(stdout, (EAPPacketRef)test_packet) == FALSE) {
2203	fprintf(stderr, "packet is bad\n");
2204	exit(1);
2205    }
2206
2207    eapsim = (EAPSIMPacketRef)test_packet;
2208    attrs_length = EAPPacketGetLength((EAPPacketRef)eapsim)
2209	- kEAPSIMAKAPacketHeaderLength;
2210    TLVListInit(tlvs_p);
2211    if (TLVListParse(tlvs_p, eapsim->attrs, attrs_length) == FALSE) {
2212	fprintf(stderr, "failed to parse TLVs: %s\n",
2213		TLVListErrorString(tlvs_p));
2214	exit(1);
2215    }
2216    mac_p = (AT_MAC *)TLVListLookupAttribute(tlvs_p, kAT_MAC);
2217    if (mac_p == NULL) {
2218	fprintf(stderr, "Challenge is missing AT_MAC\n");
2219	exit(1);
2220    }
2221    EAPSIMAKAKeyInfoComputeMAC(&key_info, (EAPPacketRef)test_packet,
2222			       mac_p->ma_mac,
2223			       test_nonce_mt, sizeof(test_nonce_mt),
2224			       hash);
2225    if (bcmp(hash, mac_p->ma_mac, MAC_SIZE) != 0) {
2226	print_data(hash, sizeof(hash));
2227	fprintf(stderr, "AT_MAC mismatch\n");
2228	exit(1);
2229    }
2230    else {
2231	printf("AT_MAC is good\n");
2232    }
2233
2234    dump_triplets();
2235    test_encr_data();
2236    test_decrypt_data();
2237    exit(0);
2238    return (0);
2239}
2240
2241#endif /* TEST_SIM_CRYPTO */
2242