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 * eapsim_plugin.c 26 * - EAP-SIM client 27 */ 28 29/* 30 * Modification History 31 * 32 * December 8, 2008 Dieter Siegmund (dieter@apple) 33 * - created 34 */ 35#include "EAPClientProperties.h" 36#include <EAP8021X/EAPClientPlugin.h> 37#include <EAP8021X/EAPClientProperties.h> 38#include <CoreFoundation/CFData.h> 39#include <CoreFoundation/CFArray.h> 40#include <CoreFoundation/CFDictionary.h> 41#include <SystemConfiguration/SCValidation.h> 42#include <stdbool.h> 43#include <unistd.h> 44#include <stdlib.h> 45#include <string.h> 46#include <stdio.h> 47#include <syslog.h> 48#include <sys/param.h> 49#include <CommonCrypto/CommonDigest.h> 50#include <CommonCrypto/CommonCryptor.h> 51#include <sys/param.h> 52#include <EAP8021X/EAP.h> 53#include <EAP8021X/EAPUtil.h> 54#include <EAP8021X/EAPClientModule.h> 55#include <TargetConditionals.h> 56#include "myCFUtil.h" 57#include "printdata.h" 58#include "fips186prf.h" 59#include "SIMAccess.h" 60#include "nbo.h" 61#include "EAPSIMAKAPersistentState.h" 62#include "EAPSIMAKA.h" 63#include "EAPSIMAKAUtil.h" 64#include "EAPLog.h" 65 66#define EAP_SIM_NAME "EAP-SIM" 67 68#define kEAPClientPropEAPSIMIMSI \ 69 CFSTR("EAPSIMIMSI") /* string */ 70#define kEAPClientPropEAPSIMRealm \ 71 CFSTR("EAPSIMRealm") /* string */ 72#define kEAPClientPropEAPSIMNumberOfRANDs \ 73 CFSTR("EAPSIMNumberOfRANDs") /* number 2 or 3, default 3 */ 74 75/* 76 * kEAPClientPropEAPSIMKcList 77 * kEAPClientPropEAPSIMSRESList 78 * kEAPClientPropEAPSIMRANDList 79 * - static (Kc, SRES, RAND) triplets used for testing 80 * - these are parallel arrays and must all be defined and have exactly the 81 * same number of elements of the correct size and type 82 */ 83 84#define kEAPClientPropEAPSIMKcList CFSTR("EAPSIMKcList") /* array[data] */ 85#define kEAPClientPropEAPSIMSRESList CFSTR("EAPSIMSRESList") /* array[data] */ 86#define kEAPClientPropEAPSIMRANDList CFSTR("EAPSIMSRANDList") /* array[data] */ 87 88/* 89 * Declare these here to ensure that the compiler 90 * generates appropriate errors/warnings 91 */ 92EAPClientPluginFuncIntrospect eapsim_introspect; 93STATIC EAPClientPluginFuncVersion eapsim_version; 94STATIC EAPClientPluginFuncEAPType eapsim_type; 95STATIC EAPClientPluginFuncEAPName eapsim_name; 96STATIC EAPClientPluginFuncInit eapsim_init; 97STATIC EAPClientPluginFuncFree eapsim_free; 98STATIC EAPClientPluginFuncProcess eapsim_process; 99STATIC EAPClientPluginFuncFreePacket eapsim_free_packet; 100STATIC EAPClientPluginFuncSessionKey eapsim_session_key; 101STATIC EAPClientPluginFuncServerKey eapsim_server_key; 102STATIC EAPClientPluginFuncPublishProperties eapsim_publish_props; 103STATIC EAPClientPluginFuncUserName eapsim_user_name_copy; 104STATIC EAPClientPluginFuncCopyIdentity eapsim_copy_identity; 105STATIC EAPClientPluginFuncCopyPacketDescription eapsim_copy_packet_description; 106 107/** 108 ** Protocol-specific defines 109 **/ 110 111enum { 112 kEAPSIMClientStateNone = 0, 113 kEAPSIMClientStateStart = 1, 114 kEAPSIMClientStateChallenge = 2, 115 kEAPSIMClientStateReauthentication = 3, 116 kEAPSIMClientStateSuccess = 4, 117 kEAPSIMClientStateFailure = 5 118}; 119typedef int EAPSIMClientState; 120 121typedef struct { 122 CFArrayRef kc; 123 CFArrayRef sres; 124 CFArrayRef rand; 125} SIMStaticTriplets, * SIMStaticTripletsRef; 126 127/* 128 * Type: EAPSIMContext 129 * Purpose: 130 * Holds the EAP-SIM module's context private data. 131 */ 132typedef struct { 133 EAPClientPluginDataRef plugin; 134 EAPClientState plugin_state; 135 EAPSIMClientState state; 136 int previous_identifier; 137 int start_count; 138 int n_required_rands; 139 EAPSIMAKAAttributeType last_identity_type; 140 CFDataRef last_identity; 141 SIMStaticTriplets sim_static; 142 EAPSIMAKAKeyInfo key_info; 143 bool key_info_valid; 144 uint8_t nonce_mt[NONCE_MT_SIZE]; 145 EAPSIMAKAPersistentStateRef persist; 146 bool reauth_success; 147 uint16_t * version_list; 148 int version_list_count; 149 uint8_t pkt[1500]; 150} EAPSIMContext, *EAPSIMContextRef; 151 152/** 153 ** Identity routines 154 **/ 155STATIC CFStringRef 156copy_imsi_identity(CFStringRef imsi, CFStringRef realm) 157{ 158 159 if (realm != NULL) { 160 return (CFStringCreateWithFormat(NULL, NULL, 161 CFSTR("1" "%@" "@" "%@"), 162 imsi, realm)); 163 } 164 return (CFStringCreateWithFormat(NULL, NULL, CFSTR("1" "%@"), 165 imsi)); 166} 167 168STATIC CFStringRef 169copy_static_realm(CFDictionaryRef properties) 170{ 171 CFStringRef realm = NULL; 172 173 if (properties == NULL) { 174 return (NULL); 175 } 176 realm = isA_CFString(CFDictionaryGetValue(properties, 177 kEAPClientPropEAPSIMRealm)); 178 if (realm == NULL) { 179 realm 180 = isA_CFString(CFDictionaryGetValue(properties, 181 kEAPClientPropEAPSIMAKARealm)); 182 if (realm == NULL) { 183 return (NULL); 184 } 185 } 186 return (CFRetain(realm)); 187} 188 189STATIC CFStringRef 190copy_static_imsi(CFDictionaryRef properties) 191{ 192 CFStringRef imsi; 193 194 if (properties == NULL) { 195 return (NULL); 196 } 197 imsi = isA_CFString(CFDictionaryGetValue(properties, 198 kEAPClientPropEAPSIMIMSI)); 199 if (imsi == NULL) { 200 imsi = isA_CFString(CFDictionaryGetValue(properties, 201 kEAPClientPropEAPSIMAKAIMSI)); 202 if (imsi == NULL) { 203 return (NULL); 204 } 205 } 206 return (CFRetain(imsi)); 207} 208 209STATIC CFStringRef 210copy_static_identity(CFDictionaryRef properties) 211{ 212 CFStringRef imsi; 213 CFStringRef realm; 214 CFStringRef ret_identity; 215 216 imsi = copy_static_imsi(properties); 217 if (imsi == NULL) { 218 return (NULL); 219 } 220 realm = copy_static_realm(properties); 221 ret_identity = copy_imsi_identity(imsi, realm); 222 my_CFRelease(&imsi); 223 my_CFRelease(&realm); 224 return (ret_identity); 225} 226 227#if TARGET_OS_EMBEDDED 228 229STATIC CFStringRef 230copy_pseudonym_identity(CFStringRef pseudonym, CFStringRef realm) 231{ 232 if (realm != NULL) { 233 return (CFStringCreateWithFormat(NULL, NULL, 234 CFSTR("%@" "@" "%@"), 235 pseudonym, realm)); 236 } 237 return (CFRetain(pseudonym)); 238} 239 240STATIC CFStringRef 241create_identity(EAPSIMAKAPersistentStateRef persist, 242 EAPSIMAKAAttributeType requested_type, 243 CFStringRef realm, 244 Boolean * is_reauth_id_p) 245{ 246 CFStringRef ret_identity = NULL; 247 248 if (is_reauth_id_p != NULL) { 249 *is_reauth_id_p = FALSE; 250 } 251 if (persist == NULL) { 252 return (NULL); 253 } 254 if (requested_type == kAT_ANY_ID_REQ 255 || requested_type == kAT_FULLAUTH_ID_REQ) { 256 CFStringRef reauth_id; 257 CFStringRef pseudonym; 258 259 reauth_id = EAPSIMAKAPersistentStateGetReauthID(persist); 260 pseudonym = EAPSIMAKAPersistentStateGetPseudonym(persist); 261 if (requested_type == kAT_ANY_ID_REQ && reauth_id != NULL) { 262 if (is_reauth_id_p != NULL) { 263 *is_reauth_id_p = TRUE; 264 } 265 ret_identity = CFRetain(reauth_id); 266 } 267 else if (pseudonym != NULL) { 268 ret_identity = copy_pseudonym_identity(pseudonym, realm); 269 } 270 } 271 if (ret_identity == NULL) { 272 /* use permanent id */ 273 ret_identity 274 = copy_imsi_identity(EAPSIMAKAPersistentStateGetIMSI(persist), 275 realm); 276 } 277 return (ret_identity); 278} 279 280STATIC CFStringRef 281sim_identity_create(EAPSIMAKAPersistentStateRef persist, 282 CFDictionaryRef properties, 283 EAPSIMAKAAttributeType identity_type, 284 Boolean * is_reauth_id_p) 285{ 286 CFStringRef realm = NULL; 287 CFStringRef ret_identity = NULL; 288 289 if (is_reauth_id_p != NULL) { 290 *is_reauth_id_p = FALSE; 291 } 292 realm = copy_static_realm(properties); 293 if (realm == NULL) { 294 realm = SIMCopyRealm(); 295 } 296 ret_identity = create_identity(persist, identity_type, realm, 297 is_reauth_id_p); 298 my_CFRelease(&realm); 299 return (ret_identity); 300} 301 302#else /* TARGET_OS_EMBEDDED */ 303 304STATIC CFStringRef 305sim_identity_create(EAPSIMAKAPersistentStateRef persist, 306 CFDictionaryRef properties, 307 EAPSIMAKAAttributeType identity_type, 308 Boolean * is_reauth_id_p) 309{ 310 if (is_reauth_id_p != NULL) { 311 *is_reauth_id_p = FALSE; 312 } 313 return (NULL); 314} 315 316#endif /* TARGET_OS_EMBEDDED */ 317 318/** 319 ** Utility Routines 320 **/ 321static int 322S_get_plist_int(CFDictionaryRef plist, CFStringRef key, int def) 323{ 324 CFNumberRef n; 325 int ret = def; 326 327 n = isA_CFNumber(CFDictionaryGetValue(plist, key)); 328 if (n != NULL) { 329 if (CFNumberGetValue(n, kCFNumberIntType, &ret) == FALSE) { 330 ret = def; 331 } 332 } 333 return (ret); 334} 335 336STATIC bool 337blocks_are_duplicated(const uint8_t * blocks, int n_blocks, int block_size) 338{ 339 int i; 340 int j; 341 const uint8_t * scan; 342 343 for (i = 0, scan = blocks; i < (n_blocks - 1); i++, scan += block_size) { 344 const uint8_t * scan_j = scan + block_size; 345 346 for (j = i + 1; j < n_blocks; j++, scan_j += block_size) { 347 if (bcmp(scan, scan_j, block_size) == 0) { 348 return (TRUE); 349 } 350 } 351 } 352 return (FALSE); 353} 354 355STATIC void 356fill_with_random(uint8_t * buf, int len) 357{ 358 int i; 359 int n; 360 void * p; 361 uint32_t random; 362 363 n = len / sizeof(random); 364 for (i = 0, p = buf; i < n; i++, p += sizeof(random)) { 365 random = arc4random(); 366 bcopy(&random, p, sizeof(random)); 367 } 368 return; 369} 370 371STATIC EAPSIMAKAAttributeType 372S_get_identity_type(CFDictionaryRef dict) 373{ 374 CFStringRef identity_type_str; 375 376 if (dict == NULL) { 377 identity_type_str = NULL; 378 } 379 else { 380 identity_type_str 381 = CFDictionaryGetValue(dict, kEAPClientPropEAPSIMAKAIdentityType); 382 identity_type_str = isA_CFString(identity_type_str); 383 } 384 return (EAPSIMAKAIdentityTypeGetAttributeType(identity_type_str)); 385} 386 387STATIC void 388EAPSIMContextSetLastIdentity(EAPSIMContextRef context, CFDataRef identity_data) 389{ 390 if (identity_data != NULL) { 391 CFRetain(identity_data); 392 } 393 if (context->last_identity != NULL) { 394 CFRelease(context->last_identity); 395 } 396 context->last_identity = identity_data; 397 return; 398} 399 400STATIC void 401EAPSIMContextSetVersionList(EAPSIMContextRef context, 402 const void * list, int count) 403{ 404 if (list != NULL) { 405 int size = count * sizeof(uint16_t); 406 407 if (context->version_list != NULL 408 && count == context->version_list_count 409 && bcmp(context->version_list, list, size) == 0) { 410 /* current list is the same, no need to copy it */ 411 } 412 else { 413 if (context->version_list != NULL) { 414 free(context->version_list); 415 } 416 context->version_list = (uint16_t *)malloc(size); 417 bcopy(list, context->version_list, size); 418 context->version_list_count = count; 419 } 420 } 421 else if (context->version_list != NULL) { 422 free(context->version_list); 423 context->version_list = NULL; 424 context->version_list_count = 0; 425 } 426 return; 427} 428 429STATIC void 430EAPSIMContextClear(EAPSIMContextRef context) 431{ 432 bzero(context, sizeof(*context)); 433 context->plugin_state = kEAPClientStateAuthenticating; 434 context->state = kEAPSIMClientStateNone; 435 context->previous_identifier = -1; 436 return; 437} 438 439STATIC CFArrayRef 440copy_data_array(CFDictionaryRef properties, CFStringRef prop_name, 441 int data_size) 442{ 443 int count; 444 int i; 445 CFArrayRef list; 446 447 if (properties == NULL) { 448 return (NULL); 449 } 450 list = CFDictionaryGetValue(properties, prop_name); 451 if (isA_CFArray(list) == NULL) { 452 return (NULL); 453 } 454 count = CFArrayGetCount(list); 455 if (count == 0) { 456 return (NULL); 457 } 458 for (i = 0; i < count; i++) { 459 CFDataRef data = CFArrayGetValueAtIndex(list, i); 460 461 if (isA_CFData(data) == NULL 462 || CFDataGetLength(data) != data_size) { 463 return (NULL); 464 } 465 } 466 return (CFRetain(list)); 467} 468 469STATIC bool 470SIMStaticTripletsInitFromProperties(SIMStaticTripletsRef sim_static_p, 471 CFDictionaryRef properties) 472{ 473 int count; 474 CFArrayRef kc; 475 CFArrayRef rand; 476 CFArrayRef sres; 477 478 my_CFRelease(&sim_static_p->kc); 479 my_CFRelease(&sim_static_p->sres); 480 my_CFRelease(&sim_static_p->rand); 481 if (properties == NULL) { 482 return (FALSE); 483 } 484 kc = copy_data_array(properties, 485 kEAPClientPropEAPSIMKcList, 486 SIM_KC_SIZE); 487 sres = copy_data_array(properties, 488 kEAPClientPropEAPSIMSRESList, 489 SIM_SRES_SIZE); 490 rand = copy_data_array(properties, 491 kEAPClientPropEAPSIMRANDList, 492 SIM_RAND_SIZE); 493 494 /* 495 * If SRES and Kc are specified, use statically defined values. 496 * If RAND is NULL, use the first element of the Kc/SRES arrays. 497 * If RAND is not NULL, RAND, Kc, and SRES must be parallel arrays; 498 * the RAND value provided by the server is looked up in the RAND array 499 * and the corresponding Kc and SRES value is retrieved. 500 */ 501 if (kc == NULL || sres == NULL) { 502 goto failed; 503 } 504 count = CFArrayGetCount(kc); 505 if (count != CFArrayGetCount(sres) 506 || (rand != NULL && count != CFArrayGetCount(rand))) { 507 /* they need to be parallel arrays */ 508 goto failed; 509 } 510 sim_static_p->kc = kc; 511 sim_static_p->sres = sres; 512 sim_static_p->rand = rand; 513 return (TRUE); 514 515 failed: 516 my_CFRelease(&kc); 517 my_CFRelease(&sres); 518 my_CFRelease(&rand); 519 return (FALSE); 520} 521 522STATIC void 523EAPSIMContextFree(EAPSIMContextRef context) 524{ 525 EAPSIMContextSetVersionList(context, NULL, 0); 526 SIMStaticTripletsInitFromProperties(&context->sim_static, NULL); 527 EAPSIMAKAPersistentStateRelease(context->persist); 528 EAPSIMContextSetLastIdentity(context, NULL); 529 EAPSIMContextClear(context); 530 free(context); 531 return; 532} 533 534STATIC int 535EAPSIMContextLookupStaticRAND(EAPSIMContextRef context, 536 const uint8_t rand[SIM_RAND_SIZE]) 537{ 538 int count; 539 int i; 540 541 if (context->sim_static.rand == NULL) { 542 return (-1); 543 } 544 count = CFArrayGetCount(context->sim_static.rand); 545 for (i = 0; i < count; i++) { 546 CFDataRef data; 547 548 data = CFArrayGetValueAtIndex(context->sim_static.rand, i); 549 if (bcmp(rand, CFDataGetBytePtr(data), SIM_RAND_SIZE) == 0) { 550 return (i); 551 } 552 } 553 return (-1); 554} 555 556STATIC bool 557EAPSIMContextSIMProcessRAND(EAPSIMContextRef context, 558 const uint8_t * rand_p, int count, 559 uint8_t * kc_p, uint8_t * sres_p) 560{ 561 int i; 562 uint8_t * kc_scan; 563 const uint8_t * rand_scan; 564 uint8_t * sres_scan; 565 566 if (context->sim_static.kc != NULL) { 567 /* use the static SIM information */ 568 rand_scan = rand_p; 569 kc_scan = kc_p; 570 sres_scan = sres_p; 571 for (i = 0; i < count; i++) { 572 CFDataRef kc_data; 573 CFDataRef sres_data; 574 int where; 575 576 if (context->sim_static.rand != NULL) { 577 where = EAPSIMContextLookupStaticRAND(context, rand_scan); 578 if (where == -1) { 579 EAPLOG(LOG_NOTICE, "eapsim: can't find static RAND value"); 580 return (FALSE); 581 } 582 } 583 else { 584 /* If RAND is NULL, choose first KC and SRES */ 585 where = 0; 586 } 587 588 kc_data = CFArrayGetValueAtIndex(context->sim_static.kc, where); 589 bcopy(CFDataGetBytePtr(kc_data), kc_scan, SIM_KC_SIZE); 590 sres_data = CFArrayGetValueAtIndex(context->sim_static.sres, where); 591 bcopy(CFDataGetBytePtr(sres_data), sres_scan, SIM_SRES_SIZE); 592 593 /* move to the next element */ 594 rand_scan += SIM_RAND_SIZE; 595 kc_scan += SIM_KC_SIZE; 596 sres_scan += SIM_SRES_SIZE; 597 } 598 } 599 else { 600 /* ask the SIM to get the (Kc, SRES) pairs from the RAND's */ 601 if (SIMAuthenticateGSM(rand_p, count, kc_p, sres_p) == FALSE) { 602 EAPLOG(LOG_NOTICE, "SIMAuthenticateGSM failed"); 603 return (FALSE); 604 } 605 } 606 return (TRUE); 607} 608 609/** 610 ** EAP-SIM module functions 611 **/ 612STATIC EAPClientStatus 613eapsim_init(EAPClientPluginDataRef plugin, CFArrayRef * require_props, 614 EAPClientDomainSpecificError * error) 615{ 616 EAPSIMContextRef context = NULL; 617 EAPSIMAKAAttributeType identity_type; 618 CFStringRef imsi = NULL; 619 SIMStaticTriplets triplets; 620 621 /* for testing, allow static triplets to override a real SIM */ 622 bzero(&triplets, sizeof(triplets)); 623 if (SIMStaticTripletsInitFromProperties(&triplets, 624 plugin->properties)) { 625 imsi = copy_static_imsi(plugin->properties); 626 if (imsi == NULL) { 627 EAPLOG(LOG_NOTICE, 628 "eapsim: static triplets specified but IMSI missing"); 629 SIMStaticTripletsInitFromProperties(&triplets, NULL); 630 return (kEAPClientStatusConfigurationInvalid); 631 } 632 } 633 else { 634 /* check for a real SIM module */ 635 imsi = SIMCopyIMSI(); 636 if (imsi == NULL) { 637 EAPLOG(LOG_NOTICE, "EAP-SIM: no SIM available"); 638 return (kEAPClientStatusResourceUnavailable); 639 } 640 EAPLOG(LOG_NOTICE, "EAP-SIM: SIM found"); 641 } 642 643 /* allocate a context */ 644 context = (EAPSIMContextRef)malloc(sizeof(*context)); 645 if (context == NULL) { 646 CFRelease(imsi); 647 (void)SIMStaticTripletsInitFromProperties(&triplets, NULL); 648 return (kEAPClientStatusAllocationFailed); 649 } 650 EAPSIMContextClear(context); 651 identity_type = S_get_identity_type(plugin->properties); 652 context->persist 653 = EAPSIMAKAPersistentStateCreate(kEAPTypeEAPSIM, 654 CC_SHA1_DIGEST_LENGTH, 655 imsi, identity_type); 656 CFRelease(imsi); 657 context->sim_static = triplets; 658 context->n_required_rands 659 = S_get_plist_int(plugin->properties, 660 kEAPClientPropEAPSIMNumberOfRANDs, 661 EAPSIM_MAX_RANDS); 662 if (context->n_required_rands != 2 663 && context->n_required_rands != 3) { 664 EAPLOG(LOG_NOTICE, 665 "eapsim: EAPSIMNumberOfRands %d is invalid, using 3 instead", 666 context->n_required_rands); 667 context->n_required_rands = EAPSIM_MAX_RANDS; 668 } 669 if (EAPSIMAKAPersistentStateGetReauthID(context->persist) != NULL) { 670 /* now run PRF to generate keying material */ 671 fips186_2prf(EAPSIMAKAPersistentStateGetMasterKey(context->persist), 672 context->key_info.key); 673 context->key_info_valid = TRUE; 674 } 675 context->plugin = plugin; 676 plugin->private = context; 677 return (kEAPClientStatusOK); 678} 679 680STATIC void 681eapsim_free(EAPClientPluginDataRef plugin) 682{ 683 EAPSIMContextFree(plugin->private); 684 plugin->private = NULL; 685 return; 686} 687 688STATIC void 689eapsim_free_packet(EAPClientPluginDataRef plugin, EAPPacketRef arg) 690{ 691 return; 692} 693 694STATIC EAPPacketRef 695eapsim_make_response(EAPSIMContextRef context, 696 EAPPacketRef in_pkt, EAPSIMAKAPacketSubtype subtype, 697 TLVBufferRef tb_p) 698{ 699 EAPSIMPacketRef pkt; 700 701 pkt = (EAPSIMPacketRef)context->pkt; 702 TLVBufferInit(tb_p, pkt->attrs, 703 sizeof(context->pkt) - offsetof(EAPSIMPacket, attrs)); 704 pkt->code = kEAPCodeResponse; 705 pkt->identifier = in_pkt->identifier; 706 pkt->type = kEAPTypeEAPSIM; 707 pkt->subtype = subtype; 708 net_uint16_set(pkt->reserved, 0); 709 return ((EAPPacketRef)pkt); 710} 711 712STATIC EAPPacketRef 713eapsim_make_client_error(EAPSIMContextRef context, 714 EAPPacketRef in_pkt, ClientErrorCode code) 715{ 716 AttrUnion attr; 717 EAPPacketRef pkt; 718 TLVBufferDeclare( tb_p); 719 720 pkt = eapsim_make_response(context, in_pkt, 721 kEAPSIMAKAPacketSubtypeClientError, tb_p); 722 attr.tlv_p = TLVBufferAllocateTLV(tb_p, kAT_CLIENT_ERROR_CODE, 723 sizeof(AT_CLIENT_ERROR_CODE)); 724 if (attr.tlv_p == NULL) { 725 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_CLIENT_ERROR_CODE, %s", 726 TLVBufferErrorString(tb_p)); 727 return (NULL); 728 } 729 net_uint16_set(attr.at_client_error_code->ce_client_error_code, code); 730 EAPPacketSetLength(pkt, 731 offsetof(EAPSIMPacket, attrs) + TLVBufferUsed(tb_p)); 732 733 return (pkt); 734} 735 736STATIC void 737save_persistent_state(EAPSIMContextRef context) 738{ 739 CFStringRef ssid = NULL; 740#if TARGET_OS_EMBEDDED 741 CFStringRef trust_domain; 742 743 trust_domain = CFDictionaryGetValue(context->plugin->properties, 744 kEAPClientPropTLSTrustExceptionsDomain); 745 if (my_CFEqual(trust_domain, kEAPTLSTrustExceptionsDomainWirelessSSID)) { 746 ssid = CFDictionaryGetValue(context->plugin->properties, 747 kEAPClientPropTLSTrustExceptionsID); 748 } 749#endif 750 EAPSIMAKAPersistentStateSave(context->persist, context->key_info_valid, 751 ssid); 752 return; 753} 754 755STATIC EAPPacketRef 756eapsim_start(EAPSIMContextRef context, 757 const EAPPacketRef in_pkt, 758 TLVListRef tlvs_p, 759 EAPClientStatus * client_status) 760{ 761 AttrUnion attr; 762 int count; 763 int i; 764 CFStringRef identity = NULL; 765 EAPSIMAKAAttributeType identity_req_type; 766 bool good_version = FALSE; 767 EAPPacketRef pkt = NULL; 768 const uint8_t * scan; 769 bool skip_identity = FALSE; 770 TLVBufferDeclare( tb_p); 771 AT_VERSION_LIST * version_list_p; 772 773 version_list_p = (AT_VERSION_LIST *) 774 TLVListLookupAttribute(tlvs_p, kAT_VERSION_LIST); 775 if (version_list_p == NULL) { 776 EAPLOG(LOG_NOTICE, "eapsim: Start is missing AT_VERSION_LIST"); 777 *client_status = kEAPClientStatusProtocolError; 778 goto done; 779 } 780 count = net_uint16_get(version_list_p->vl_actual_length) / sizeof(uint16_t); 781 for (i = 0, scan = version_list_p->vl_version_list; 782 i < count; i++, scan += sizeof(uint16_t)) { 783 uint16_t this_vers = net_uint16_get(scan); 784 785 /* we only support version 1 */ 786 if (this_vers == kEAPSIMVersion1) { 787 good_version = TRUE; 788 break; 789 } 790 } 791 if (good_version == FALSE) { 792 pkt = eapsim_make_client_error(context, in_pkt, 793 kClientErrorCodeUnsupportedVersion); 794 *client_status = kEAPClientStatusProtocolError; 795 goto done; 796 } 797 if (count > 1) { 798 /* if there was more than one version, save the list */ 799 EAPSIMContextSetVersionList(context, 800 version_list_p->vl_version_list, count); 801 } 802 else { 803 EAPSIMContextSetVersionList(context, NULL, 0); 804 } 805 if (context->state != kEAPSIMClientStateStart) { 806 /* starting over */ 807 context->plugin_state = kEAPClientStateAuthenticating; 808 context->start_count = 0; 809 context->last_identity_type = 0; 810 context->state = kEAPSIMClientStateStart; 811 } 812 if (context->start_count == 0) { 813 fill_with_random(context->nonce_mt, sizeof(context->nonce_mt)); 814 } 815 context->start_count++; 816 if (context->start_count > kEAPSIMAKAIdentityAttributesCount) { 817 EAPLOG(LOG_NOTICE, "eapsim: too many Start packets (%d > %d)", 818 context->start_count, kEAPSIMAKAIdentityAttributesCount); 819 *client_status = kEAPClientStatusProtocolError; 820 goto done; 821 } 822 identity_req_type = TLVListLookupIdentityAttribute(tlvs_p); 823 switch (identity_req_type) { 824 case kAT_ANY_ID_REQ: 825 if (context->start_count > 1) { 826 EAPLOG(LOG_NOTICE, 827 "eapsim: AT_ANY_ID_REQ at Start #%d", 828 context->start_count); 829 *client_status = kEAPClientStatusProtocolError; 830 goto done; 831 } 832 break; 833 case kAT_FULLAUTH_ID_REQ: 834 if (context->start_count > 1 835 && context->last_identity_type != kAT_ANY_ID_REQ) { 836 EAPLOG(LOG_NOTICE, 837 "eapsim: AT_FULLAUTH_ID_REQ follows %s at Start #%d", 838 EAPSIMAKAAttributeTypeGetString(context->last_identity_type), 839 context->start_count); 840 *client_status = kEAPClientStatusProtocolError; 841 goto done; 842 } 843 break; 844 case kAT_PERMANENT_ID_REQ: 845 if (context->start_count > 1 846 && context->last_identity_type != kAT_ANY_ID_REQ 847 && context->last_identity_type != kAT_FULLAUTH_ID_REQ) { 848 EAPLOG(LOG_NOTICE, 849 "eapsim: AT_PERMANENT_ID_REQ follows %s at Start #%d", 850 EAPSIMAKAAttributeTypeGetString(context->last_identity_type), 851 context->start_count); 852 *client_status = kEAPClientStatusProtocolError; 853 goto done; 854 } 855 break; 856 default: 857 if (context->start_count > 1) { 858 EAPLOG(LOG_NOTICE, 859 "eapsim: no *ID_REQ follows %s at Start #%d", 860 EAPSIMAKAAttributeTypeGetString(context->last_identity_type), 861 context->start_count); 862 *client_status = kEAPClientStatusProtocolError; 863 goto done; 864 } 865 /* no need to submit an identity */ 866 skip_identity = TRUE; 867 break; 868 } 869 870 /* create our response */ 871 context->last_identity_type = identity_req_type; 872 pkt = eapsim_make_response(context, in_pkt, kEAPSIMAKAPacketSubtypeSIMStart, 873 tb_p); 874 875 if (!skip_identity) { 876 CFDataRef identity_data = NULL; 877 Boolean reauth_id_used = FALSE; 878 879 if (context->sim_static.kc != NULL) { 880 identity = copy_static_identity(context->plugin->properties); 881 } 882 else { 883 identity = sim_identity_create(context->persist, 884 context->plugin->properties, 885 identity_req_type, 886 &reauth_id_used); 887 } 888 if (identity == NULL) { 889 EAPLOG(LOG_NOTICE, "eapsim: can't find SIM identity"); 890 *client_status = kEAPClientStatusResourceUnavailable; 891 pkt = NULL; 892 goto done; 893 } 894 895 if (!TLVBufferAddIdentityString(tb_p, identity, &identity_data)) { 896 EAPLOG(LOG_NOTICE, "eapsim: can't add AT_IDENTITY, %s", 897 TLVBufferErrorString(tb_p)); 898 *client_status = kEAPClientStatusInternalError; 899 pkt = NULL; 900 goto done; 901 } 902 EAPSIMContextSetLastIdentity(context, identity_data); 903 my_CFRelease(&identity_data); 904 905 if (reauth_id_used) { 906 /* packet only contains fast re-auth id */ 907 goto packet_complete; 908 } 909 } 910 911 /* We are now sure that re-auth will not take place */ 912 context->key_info_valid = FALSE; 913 914 /* set the AT_SELECTED_VERSION attribute */ 915 attr.tlv_p = TLVBufferAllocateTLV(tb_p, kAT_SELECTED_VERSION, 916 sizeof(AT_SELECTED_VERSION)); 917 if (attr.tlv_p == NULL) { 918 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_SELECTED_VERSION, %s", 919 TLVBufferErrorString(tb_p)); 920 *client_status = kEAPClientStatusInternalError; 921 pkt = NULL; 922 goto done; 923 } 924 net_uint16_set(attr.at_selected_version->sv_selected_version, 925 kEAPSIMVersion1); 926 927 /* set the AT_NONCE_MT attribute */ 928 attr.tlv_p = TLVBufferAllocateTLV(tb_p, kAT_NONCE_MT, 929 sizeof(AT_NONCE_MT)); 930 if (attr.tlv_p == NULL) { 931 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_NONCE_MT, %s", 932 TLVBufferErrorString(tb_p)); 933 pkt = NULL; 934 goto done; 935 } 936 net_uint16_set(attr.at_nonce_mt->nm_reserved, 0); 937 bcopy(context->nonce_mt, attr.at_nonce_mt->nm_nonce_mt, 938 sizeof(context->nonce_mt)); 939 940 packet_complete: 941 /* packet fully formed, set the EAP packet length */ 942 EAPPacketSetLength(pkt, 943 offsetof(EAPSIMPacket, attrs) + TLVBufferUsed(tb_p)); 944 945 done: 946 my_CFRelease(&identity); 947 return (pkt); 948} 949 950STATIC bool 951eapsim_challenge_process_encr_data(EAPSIMContextRef context, TLVListRef tlvs_p) 952{ 953 uint8_t * decrypted_buffer = NULL; 954 TLVListDeclare( decrypted_tlvs_p); 955 AT_ENCR_DATA * encr_data_p; 956 AT_IV * iv_p; 957 CFStringRef next_reauth_id; 958 CFStringRef next_pseudonym; 959 960 TLVListInit(decrypted_tlvs_p); 961 encr_data_p = (AT_ENCR_DATA *)TLVListLookupAttribute(tlvs_p, kAT_ENCR_DATA); 962 if (encr_data_p == NULL) { 963 return (TRUE); 964 } 965 iv_p = (AT_IV *)TLVListLookupAttribute(tlvs_p, kAT_IV); 966 if (iv_p == NULL) { 967 EAPLOG(LOG_NOTICE, 968 "eapsim: Challenge missing AT_IV"); 969 return (FALSE); 970 } 971 decrypted_buffer 972 = EAPSIMAKAKeyInfoDecryptTLVList(&context->key_info, encr_data_p, iv_p, 973 decrypted_tlvs_p); 974 if (decrypted_buffer == NULL) { 975 EAPLOG(LOG_NOTICE, "eapsim: Challenge decrypt AT_ENCR_DATA failed"); 976 return (FALSE); 977 } 978 { 979 CFStringRef str; 980 981 str = TLVListCopyDescription(decrypted_tlvs_p); 982 EAPLOG(-LOG_DEBUG, "Decrypted TLVs:\n%@", str); 983 CFRelease(str); 984 } 985 986 /* save the next fast re-auth id */ 987 next_reauth_id = TLVListCreateStringFromAttribute(decrypted_tlvs_p, 988 kAT_NEXT_REAUTH_ID); 989 if (next_reauth_id != NULL) { 990 EAPSIMAKAPersistentStateSetReauthID(context->persist, 991 next_reauth_id); 992 CFRelease(next_reauth_id); 993 } 994 /* save the next pseudonym */ 995 next_pseudonym = TLVListCreateStringFromAttribute(decrypted_tlvs_p, 996 kAT_NEXT_PSEUDONYM); 997 if (next_pseudonym != NULL) { 998 EAPSIMAKAPersistentStateSetPseudonym(context->persist, 999 next_pseudonym); 1000 CFRelease(next_pseudonym); 1001 } 1002 if (decrypted_buffer != NULL) { 1003 free(decrypted_buffer); 1004 } 1005 TLVListFree(decrypted_tlvs_p); 1006 return (TRUE); 1007} 1008 1009STATIC EAPPacketRef 1010eapsim_challenge(EAPSIMContextRef context, 1011 const EAPPacketRef in_pkt, 1012 TLVListRef tlvs_p, 1013 EAPClientStatus * client_status) 1014{ 1015 int count; 1016 uint8_t kc[SIM_KC_SIZE * EAPSIM_MAX_RANDS]; 1017 AT_MAC * mac_p; 1018 EAPPacketRef pkt = NULL; 1019 AT_RAND * rand_p; 1020 uint16_t selected_version = htons(kEAPSIMVersion1); 1021 CC_SHA1_CTX sha1_context; 1022 uint8_t sres[SIM_SRES_SIZE * EAPSIM_MAX_RANDS]; 1023 TLVBufferDeclare( tb_p); 1024 1025 if (context->state != kEAPSIMClientStateStart) { 1026 EAPLOG(LOG_NOTICE, "eapsim: Challenge sent without Start"); 1027 *client_status = kEAPClientStatusProtocolError; 1028 goto done; 1029 } 1030 context->state = kEAPSIMClientStateChallenge; 1031 EAPSIMAKAPersistentStateSetCounter(context->persist, 1); 1032 context->reauth_success = FALSE; 1033 rand_p = (AT_RAND *)TLVListLookupAttribute(tlvs_p, kAT_RAND); 1034 if (rand_p == NULL) { 1035 EAPLOG(LOG_NOTICE, "eapsim: Challenge is missing AT_RAND"); 1036 *client_status = kEAPClientStatusProtocolError; 1037 goto done; 1038 } 1039 count = ((rand_p->ra_length * TLV_ALIGNMENT) 1040 - offsetof(AT_RAND, ra_rand)) / SIM_RAND_SIZE; 1041 if (count < context->n_required_rands) { 1042 EAPLOG(LOG_NOTICE, 1043 "eapsim: Challenge AT_RAND has %d RANDs, policy requires %d", 1044 count, context->n_required_rands); 1045 pkt = eapsim_make_client_error(context, in_pkt, 1046 kClientErrorCodeInsufficientNumberOfChallenges); 1047 1048 *client_status = kEAPClientStatusProtocolError; 1049 goto done; 1050 } 1051 /* check that there aren't more than EAPSIM_MAX_RANDS */ 1052 if (count > EAPSIM_MAX_RANDS) { 1053 EAPLOG(LOG_NOTICE, 1054 "eapsim: Challenge AT_RAND has %d RANDs > %d", 1055 count, EAPSIM_MAX_RANDS); 1056 *client_status = kEAPClientStatusProtocolError; 1057 goto done; 1058 } 1059 if (blocks_are_duplicated(rand_p->ra_rand, count, SIM_RAND_SIZE)) { 1060 EAPLOG(LOG_NOTICE, 1061 "eapsim: Challenge AT_RAND has duplicate RANDs"); 1062 *client_status = kEAPClientStatusProtocolError; 1063 goto done; 1064 } 1065 1066 /* get the (Kc, SRES) pairs from the SIM */ 1067 if (EAPSIMContextSIMProcessRAND(context, rand_p->ra_rand, count, kc, sres) 1068 == FALSE) { 1069 *client_status = kEAPClientStatusInternalError; 1070 goto done; 1071 } 1072 1073 /* 1074 * generate the MK: 1075 * MK = SHA1(Identity|n*Kc| NONCE_MT| Version List| Selected Version) 1076 */ 1077 CC_SHA1_Init(&sha1_context); 1078 if (context->last_identity != NULL) { 1079 CC_SHA1_Update(&sha1_context, CFDataGetBytePtr(context->last_identity), 1080 CFDataGetLength(context->last_identity)); 1081 } 1082 else { 1083 CC_SHA1_Update(&sha1_context, context->plugin->username, 1084 context->plugin->username_length); 1085 } 1086 CC_SHA1_Update(&sha1_context, kc, SIM_KC_SIZE * count); 1087 CC_SHA1_Update(&sha1_context, context->nonce_mt, sizeof(context->nonce_mt)); 1088 if (context->version_list != NULL) { 1089 CC_SHA1_Update(&sha1_context, context->version_list, 1090 (sizeof(*context->version_list) 1091 * context->version_list_count)); 1092 } 1093 else { 1094 CC_SHA1_Update(&sha1_context, &selected_version, 1095 sizeof(selected_version)); 1096 } 1097 CC_SHA1_Update(&sha1_context, &selected_version, sizeof(selected_version)); 1098 CC_SHA1_Final(EAPSIMAKAPersistentStateGetMasterKey(context->persist), 1099 &sha1_context); 1100 1101 /* now run PRF to generate keying material */ 1102 fips186_2prf(EAPSIMAKAPersistentStateGetMasterKey(context->persist), 1103 context->key_info.key); 1104 1105 /* validate the MAC */ 1106 mac_p = (AT_MAC *)TLVListLookupAttribute(tlvs_p, kAT_MAC); 1107 if (mac_p == NULL) { 1108 EAPLOG(LOG_NOTICE, 1109 "eapsim: Challenge is missing AT_MAC"); 1110 *client_status = kEAPClientStatusProtocolError; 1111 goto done; 1112 } 1113 if (!EAPSIMAKAKeyInfoVerifyMAC(&context->key_info, in_pkt, 1114 mac_p->ma_mac, 1115 context->nonce_mt, 1116 sizeof(context->nonce_mt))) { 1117 EAPLOG(LOG_NOTICE, 1118 "eapsim: Challenge AT_MAC not valid"); 1119 *client_status = kEAPClientStatusProtocolError; 1120 goto done; 1121 } 1122 1123 /* check for and process encrypted data */ 1124 if (eapsim_challenge_process_encr_data(context, tlvs_p) == FALSE) { 1125 *client_status = kEAPClientStatusProtocolError; 1126 goto done; 1127 } 1128 1129 /* create our response */ 1130 pkt = eapsim_make_response(context, in_pkt, 1131 kEAPSIMAKAPacketSubtypeSIMChallenge, tb_p); 1132 mac_p = (AT_MAC *)TLVBufferAllocateTLV(tb_p, kAT_MAC, 1133 sizeof(AT_MAC)); 1134 if (mac_p == NULL) { 1135 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_MAC, %s", 1136 TLVBufferErrorString(tb_p)); 1137 *client_status = kEAPClientStatusInternalError; 1138 pkt = NULL; 1139 goto done; 1140 } 1141 net_uint16_set(mac_p->ma_reserved, 0); 1142 EAPPacketSetLength(pkt, 1143 offsetof(EAPSIMPacket, attrs) + TLVBufferUsed(tb_p)); 1144 /* compute/set the MAC value */ 1145 EAPSIMAKAKeyInfoSetMAC(&context->key_info, pkt, mac_p->ma_mac, 1146 sres, SIM_SRES_SIZE * count); 1147 1148 /* as far as we're concerned, we're successful */ 1149 context->state = kEAPSIMClientStateSuccess; 1150 context->key_info_valid = TRUE; 1151 save_persistent_state(context); 1152 1153 done: 1154 return (pkt); 1155} 1156 1157STATIC void 1158eapsim_compute_reauth_key(EAPSIMContextRef context, 1159 AT_COUNTER * counter_p, 1160 AT_NONCE_S * nonce_s_p) 1161 1162{ 1163 const void * identity; 1164 int identity_length; 1165 1166 if (context->last_identity != NULL) { 1167 identity = CFDataGetBytePtr(context->last_identity); 1168 identity_length = CFDataGetLength(context->last_identity); 1169 } 1170 else { 1171 identity = context->plugin->username; 1172 identity_length = context->plugin->username_length; 1173 } 1174 EAPSIMAKAKeyInfoComputeReauthKey(&context->key_info, 1175 context->persist, 1176 identity, identity_length, 1177 counter_p, nonce_s_p); 1178 return; 1179} 1180 1181#define ENCR_BUFSIZE (sizeof(AT_COUNTER) + sizeof(AT_COUNTER_TOO_SMALL)) 1182#define ENCR_BUFSIZE_R AT_ENCR_DATA_ROUNDUP(ENCR_BUFSIZE) 1183 1184STATIC EAPPacketRef 1185eapsim_reauthentication(EAPSIMContextRef context, 1186 const EAPPacketRef in_pkt, 1187 TLVListRef tlvs_p, 1188 EAPClientStatus * client_status) 1189{ 1190 uint16_t at_counter; 1191 AT_COUNTER * counter_p; 1192 bool force_fullauth = FALSE; 1193 uint8_t encr_buffer[ENCR_BUFSIZE_R]; 1194 TLVBufferDeclare( encr_tb_p); 1195 uint8_t * decrypted_buffer = NULL; 1196 TLVListDeclare( decrypted_tlvs_p); 1197 AT_ENCR_DATA * encr_data_p; 1198 AT_IV * iv_p; 1199 AT_MAC * mac_p; 1200 CFStringRef next_reauth_id; 1201 AT_NONCE_S * nonce_s_p; 1202 EAPPacketRef pkt = NULL; 1203 CFStringRef reauth_id = NULL; 1204 TLVBufferDeclare( tb_p); 1205 1206 TLVListInit(decrypted_tlvs_p); 1207 if (context->key_info_valid == FALSE) { 1208 EAPLOG(LOG_NOTICE, 1209 "eapsim: Reauthentication but no key info available"); 1210 *client_status = kEAPClientStatusProtocolError; 1211 goto done; 1212 } 1213 reauth_id = EAPSIMAKAPersistentStateGetReauthID(context->persist); 1214 if (reauth_id == NULL) { 1215 EAPLOG(LOG_NOTICE, 1216 "eapsim: received Reauthentication but don't have reauth id"); 1217 *client_status = kEAPClientStatusProtocolError; 1218 goto done; 1219 } 1220 context->state = kEAPSIMClientStateReauthentication; 1221 context->plugin_state = kEAPClientStateAuthenticating; 1222 1223 /* validate the MAC */ 1224 mac_p = (AT_MAC *)TLVListLookupAttribute(tlvs_p, kAT_MAC); 1225 if (mac_p == NULL) { 1226 EAPLOG(LOG_NOTICE, 1227 "eapsim: Reauthentication is missing AT_MAC"); 1228 *client_status = kEAPClientStatusProtocolError; 1229 goto done; 1230 } 1231 if (!EAPSIMAKAKeyInfoVerifyMAC(&context->key_info, in_pkt, mac_p->ma_mac, 1232 NULL, 0)) { 1233 EAPLOG(LOG_NOTICE, 1234 "eapsim: Reauthentication AT_MAC not valid"); 1235 *client_status = kEAPClientStatusProtocolError; 1236 goto done; 1237 } 1238 1239 /* packet must contain AT_ENCR_DATA, AT_IV */ 1240 encr_data_p = (AT_ENCR_DATA *)TLVListLookupAttribute(tlvs_p, kAT_ENCR_DATA); 1241 iv_p = (AT_IV *)TLVListLookupAttribute(tlvs_p, kAT_IV); 1242 if (encr_data_p == NULL || iv_p == NULL) { 1243 if (encr_data_p == NULL) { 1244 EAPLOG(LOG_NOTICE, 1245 "eapsim: Reauthentication missing AT_ENCR_DATA"); 1246 } 1247 if (iv_p == NULL) { 1248 EAPLOG(LOG_NOTICE, 1249 "eapsim: Reauthentication missing AT_IV"); 1250 } 1251 *client_status = kEAPClientStatusProtocolError; 1252 goto done; 1253 } 1254 decrypted_buffer 1255 = EAPSIMAKAKeyInfoDecryptTLVList(&context->key_info, encr_data_p, iv_p, 1256 decrypted_tlvs_p); 1257 if (decrypted_buffer == NULL) { 1258 EAPLOG(LOG_NOTICE, 1259 "eapsim: failed to decrypt Reauthentication AT_ENCR_DATA"); 1260 *client_status = kEAPClientStatusProtocolError; 1261 goto done; 1262 } 1263 { 1264 CFStringRef str; 1265 1266 str = TLVListCopyDescription(decrypted_tlvs_p); 1267 EAPLOG(-LOG_DEBUG, "Decrypted TLVs:\n%@", str); 1268 CFRelease(str); 1269 } 1270 1271 /* Reauthentication must contain AT_NONCE_S, AT_COUNTER */ 1272 nonce_s_p 1273 = (AT_NONCE_S *)TLVListLookupAttribute(decrypted_tlvs_p, kAT_NONCE_S); 1274 counter_p 1275 = (AT_COUNTER *)TLVListLookupAttribute(decrypted_tlvs_p, kAT_COUNTER); 1276 if (nonce_s_p == NULL || counter_p == NULL) { 1277 if (nonce_s_p == NULL) { 1278 EAPLOG(LOG_NOTICE, 1279 "eapsim: Reauthentication AT_ENCR_DATA missing AT_NONCE_S"); 1280 } 1281 if (counter_p == NULL) { 1282 EAPLOG(LOG_NOTICE, 1283 "eapsim: Reauthentication AT_ENCR_DATA missing AT_COUNTER"); 1284 } 1285 *client_status = kEAPClientStatusProtocolError; 1286 goto done; 1287 } 1288 1289 /* check the at_counter */ 1290 at_counter = net_uint16_get(counter_p->co_counter); 1291 if (at_counter < EAPSIMAKAPersistentStateGetCounter(context->persist)) { 1292 force_fullauth = TRUE; 1293 } 1294 else { 1295 /* save the next fast re-auth id */ 1296 next_reauth_id = TLVListCreateStringFromAttribute(decrypted_tlvs_p, 1297 kAT_NEXT_REAUTH_ID); 1298 if (next_reauth_id != NULL) { 1299 EAPSIMAKAPersistentStateSetReauthID(context->persist, 1300 next_reauth_id); 1301 CFRelease(next_reauth_id); 1302 } 1303 EAPSIMAKAPersistentStateSetCounter(context->persist, at_counter); 1304 } 1305 1306 /* create our response */ 1307 pkt = eapsim_make_response(context, in_pkt, 1308 kEAPSIMAKAPacketSubtypeReauthentication, tb_p); 1309 1310 /* 1311 * create nested attributes containing: 1312 * AT_COUNTER 1313 * AT_COUNTER_TOO_SMALL (if necessary) 1314 */ 1315 TLVBufferInit(encr_tb_p, encr_buffer, sizeof(encr_buffer)); 1316 if (TLVBufferAddCounter(encr_tb_p, at_counter) == FALSE) { 1317 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_COUNTER, %s", 1318 TLVBufferErrorString(tb_p)); 1319 *client_status = kEAPClientStatusInternalError; 1320 pkt = NULL; 1321 goto done; 1322 } 1323 if (force_fullauth 1324 && TLVBufferAddCounterTooSmall(encr_tb_p) == FALSE) { 1325 EAPLOG(LOG_NOTICE, 1326 "eapsim: failed allocating AT_COUNTER_TOO_SMALL, %s", 1327 TLVBufferErrorString(tb_p)); 1328 *client_status = kEAPClientStatusInternalError; 1329 pkt = NULL; 1330 goto done; 1331 } 1332 1333 /* AT_IV and AT_ENCR_DATA */ 1334 if (!EAPSIMAKAKeyInfoEncryptTLVs(&context->key_info, tb_p, encr_tb_p)) { 1335 *client_status = kEAPClientStatusInternalError; 1336 pkt = NULL; 1337 goto done; 1338 } 1339 1340 /* AT_MAC */ 1341 mac_p = (AT_MAC *)TLVBufferAllocateTLV(tb_p, kAT_MAC, 1342 sizeof(AT_MAC)); 1343 if (mac_p == NULL) { 1344 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_MAC, %s", 1345 TLVBufferErrorString(tb_p)); 1346 *client_status = kEAPClientStatusInternalError; 1347 pkt = NULL; 1348 goto done; 1349 } 1350 net_uint16_set(mac_p->ma_reserved, 0); 1351 1352 /* set the packet length */ 1353 EAPPacketSetLength(pkt, 1354 offsetof(EAPSIMPacket, attrs) + TLVBufferUsed(tb_p)); 1355 1356 /* compute/set the MAC value */ 1357 EAPSIMAKAKeyInfoSetMAC(&context->key_info, pkt, 1358 mac_p->ma_mac, nonce_s_p->nc_nonce_s, 1359 sizeof(nonce_s_p->nc_nonce_s)); 1360 1361 if (force_fullauth == FALSE) { 1362 /* as far as we're concerned, we're successful */ 1363 context->state = kEAPSIMClientStateSuccess; 1364 eapsim_compute_reauth_key(context, counter_p, nonce_s_p); 1365 context->key_info_valid = TRUE; 1366 context->reauth_success = TRUE; 1367 } 1368 else { 1369 context->key_info_valid = FALSE; 1370 } 1371 save_persistent_state(context); 1372 1373 done: 1374 if (decrypted_buffer != NULL) { 1375 free(decrypted_buffer); 1376 } 1377 TLVListFree(decrypted_tlvs_p); 1378 return (pkt); 1379} 1380 1381#define ENCR_BUFSIZE_NOTIF (sizeof(AT_COUNTER)) 1382#define ENCR_BUFSIZE_NOTIF_R AT_ENCR_DATA_ROUNDUP(ENCR_BUFSIZE_NOTIF) 1383 1384STATIC EAPPacketRef 1385eapsim_notification(EAPSIMContextRef context, 1386 const EAPPacketRef in_pkt, 1387 TLVListRef tlvs_p, 1388 EAPClientStatus * client_status, 1389 EAPClientDomainSpecificError * error) 1390{ 1391 bool after_auth; 1392 uint16_t current_at_counter; 1393 bool do_replay_protection = FALSE; 1394 AT_NOTIFICATION * notification_p; 1395 AT_MAC * mac_p; 1396 uint16_t notification_code = 0; 1397 EAPPacketRef pkt = NULL; 1398 TLVBufferDeclare( tb_p); 1399 1400 *client_status = kEAPClientStatusOK; 1401 *error = 0; 1402 notification_p = 1403 (AT_NOTIFICATION *)TLVListLookupAttribute(tlvs_p, kAT_NOTIFICATION); 1404 1405 if (notification_p == NULL) { 1406 EAPLOG(LOG_NOTICE, "eapsim: Notification does not contain " 1407 "AT_NOTIFICATION attribute"); 1408 *client_status = kEAPClientStatusProtocolError; 1409 goto done; 1410 } 1411 1412 notification_code = net_uint16_get(notification_p->nt_notification); 1413 after_auth = ATNotificationPhaseIsAfterAuthentication(notification_code); 1414 if (ATNotificationCodeIsSuccess(notification_code) && after_auth == FALSE) { 1415 EAPLOG(LOG_NOTICE, 1416 "eapsim: Notification code '%d' indicates " 1417 "success before authentication", notification_code); 1418 *client_status = kEAPClientStatusProtocolError; 1419 goto done; 1420 } 1421 1422 /* validate the MAC */ 1423 mac_p = (AT_MAC *)TLVListLookupAttribute(tlvs_p, kAT_MAC); 1424 if (mac_p == NULL) { 1425 if (after_auth) { 1426 EAPLOG(LOG_NOTICE, "eapsim: Notification is missing AT_MAC"); 1427 *client_status = kEAPClientStatusProtocolError; 1428 goto done; 1429 } 1430 } 1431 else { 1432 if (after_auth == FALSE) { 1433 EAPLOG(LOG_NOTICE, 1434 "eapsim: Notification incorrectly contains AT_MAC"); 1435 *client_status = kEAPClientStatusProtocolError; 1436 goto done; 1437 } 1438 1439 if (!EAPSIMAKAKeyInfoVerifyMAC(&context->key_info, in_pkt, 1440 mac_p->ma_mac, NULL, 0)) { 1441 EAPLOG(LOG_NOTICE, "eapsim: Notification AT_MAC not valid"); 1442 *client_status = kEAPClientStatusProtocolError; 1443 goto done; 1444 } 1445 } 1446 current_at_counter = EAPSIMAKAPersistentStateGetCounter(context->persist); 1447 do_replay_protection = context->reauth_success && after_auth; 1448 if (do_replay_protection) { 1449 uint16_t at_counter; 1450 uint8_t * decrypted_buffer; 1451 AT_ENCR_DATA * encr_data_p; 1452 TLVListDeclare( decrypted_tlvs_p); 1453 bool has_counter = FALSE; 1454 AT_IV * iv_p; 1455 1456 encr_data_p 1457 = (AT_ENCR_DATA *)TLVListLookupAttribute(tlvs_p, kAT_ENCR_DATA); 1458 iv_p = (AT_IV *)TLVListLookupAttribute(tlvs_p, kAT_IV); 1459 if (encr_data_p == NULL || iv_p == NULL) { 1460 EAPLOG(LOG_NOTICE, 1461 "eapsim: Notification after re-auth missing " 1462 "AT_ENCR_DATA (%p) or AT_IV (%p)", encr_data_p, iv_p); 1463 *client_status = kEAPClientStatusProtocolError; 1464 goto done; 1465 } 1466 1467 decrypted_buffer 1468 = EAPSIMAKAKeyInfoDecryptTLVList(&context->key_info, 1469 encr_data_p, iv_p, 1470 decrypted_tlvs_p); 1471 if (decrypted_buffer != NULL) { 1472 AT_COUNTER * counter_p; 1473 CFStringRef str; 1474 1475 str = TLVListCopyDescription(decrypted_tlvs_p); 1476 EAPLOG(-LOG_DEBUG, "Decrypted TLVs:\n%@", str); 1477 CFRelease(str); 1478 1479 counter_p = (AT_COUNTER *)TLVListLookupAttribute(decrypted_tlvs_p, 1480 kAT_COUNTER); 1481 if (counter_p != NULL) { 1482 at_counter = net_uint16_get(counter_p->co_counter); 1483 has_counter = TRUE; 1484 } 1485 free(decrypted_buffer); 1486 TLVListFree(decrypted_tlvs_p); 1487 } 1488 else { 1489 EAPLOG(LOG_NOTICE, 1490 "eapsim: failed to decrypt Notification AT_ENCR_DATA"); 1491 *client_status = kEAPClientStatusInternalError; 1492 goto done; 1493 } 1494 if (!has_counter) { 1495 EAPLOG(LOG_NOTICE, 1496 "eapsim: Notification AT_ENCR_DATA missing AT_COUNTER"); 1497 *client_status = kEAPClientStatusProtocolError; 1498 goto done; 1499 } 1500 if (at_counter != current_at_counter) { 1501 EAPLOG(LOG_NOTICE, "eapsim: Notification AT_COUNTER (%d) does not " 1502 "match current counter (%d)", at_counter, 1503 current_at_counter); 1504 *client_status = kEAPClientStatusProtocolError; 1505 goto done; 1506 } 1507 } 1508 1509 /* create our response */ 1510 pkt = eapsim_make_response(context, in_pkt, 1511 kEAPSIMAKAPacketSubtypeNotification, 1512 tb_p); 1513 if (do_replay_protection) { 1514 uint8_t encr_buffer[ENCR_BUFSIZE_NOTIF_R]; 1515 TLVBufferDeclare( encr_tb_p); 1516 1517 /* 1518 * create nested attributes containing: 1519 * AT_COUNTER 1520 */ 1521 TLVBufferInit(encr_tb_p, encr_buffer, sizeof(encr_buffer)); 1522 if (TLVBufferAddCounter(encr_tb_p, current_at_counter) == FALSE) { 1523 EAPLOG(LOG_NOTICE, "eapsim: failed to allocate AT_COUNTER, %s", 1524 TLVBufferErrorString(encr_tb_p)); 1525 *client_status = kEAPClientStatusAllocationFailed; 1526 goto done; 1527 } 1528 1529 /* AT_IV and AT_ENCR_DATA */ 1530 if (!EAPSIMAKAKeyInfoEncryptTLVs(&context->key_info, tb_p, encr_tb_p)) { 1531 *client_status = kEAPClientStatusInternalError; 1532 pkt = NULL; 1533 goto done; 1534 } 1535 } 1536 if (mac_p != NULL) { 1537 /* AT_MAC */ 1538 mac_p = (AT_MAC *)TLVBufferAllocateTLV(tb_p, kAT_MAC, sizeof(AT_MAC)); 1539 if (mac_p == NULL) { 1540 EAPLOG(LOG_NOTICE, "eapsim: failed allocating AT_MAC, %s", 1541 TLVBufferErrorString(tb_p)); 1542 *client_status = kEAPClientStatusAllocationFailed; 1543 pkt = NULL; 1544 goto done; 1545 } 1546 net_uint16_set(mac_p->ma_reserved, 0); 1547 } 1548 1549 /* set the packet length */ 1550 EAPPacketSetLength(pkt, 1551 offsetof(EAPSIMPacket, attrs) + TLVBufferUsed(tb_p)); 1552 if (mac_p != NULL) { 1553 /* compute/set the MAC value */ 1554 EAPSIMAKAKeyInfoSetMAC(&context->key_info, pkt, mac_p->ma_mac, NULL, 0); 1555 } 1556 if (ATNotificationCodeIsSuccess(notification_code)) { 1557 context->state = kEAPSIMClientStateSuccess; 1558 } 1559 else { 1560 const char * str; 1561 1562 context->state = kEAPSIMClientStateFailure; 1563 *client_status = kEAPClientStatusPluginSpecificError; 1564 *error = EAPSIMAKAStatusForATNotificationCode(notification_code); 1565 str = ATNotificationCodeGetString(notification_code); 1566 if (str == NULL) { 1567 EAPLOG(LOG_NOTICE, 1568 "eapsim: Notification code '%d' unrecognized failure", 1569 notification_code); 1570 } 1571 else { 1572 EAPLOG(LOG_NOTICE, "eapsim: Notification: %s", str); 1573 } 1574 } 1575 1576 done: 1577 return (pkt); 1578} 1579 1580STATIC EAPPacketRef 1581eapsim_request(EAPSIMContextRef context, 1582 const EAPPacketRef in_pkt, 1583 EAPClientStatus * client_status, 1584 EAPClientDomainSpecificError * error) 1585{ 1586 EAPSIMPacketRef eapsim_in = (EAPSIMPacketRef)in_pkt; 1587 EAPPacketRef eapsim_out = NULL; 1588 uint16_t in_length = EAPPacketGetLength(in_pkt); 1589 uint8_t subtype; 1590 TLVListDeclare( tlvs_p); 1591 1592 TLVListInit(tlvs_p); 1593 if (in_length <= kEAPSIMAKAPacketHeaderLength) { 1594 EAPLOG_FL(LOG_NOTICE, "length %d <= %ld", 1595 in_length, kEAPSIMAKAPacketHeaderLength); 1596 *client_status = kEAPClientStatusProtocolError; 1597 goto done; 1598 } 1599 if (TLVListParse(tlvs_p, eapsim_in->attrs, 1600 in_length - kEAPSIMAKAPacketHeaderLength) == FALSE) { 1601 EAPLOG_FL(LOG_NOTICE, "parse failed: %s", 1602 TLVListErrorString(tlvs_p)); 1603 *client_status = kEAPClientStatusProtocolError; 1604 goto done; 1605 } 1606 if (context->state != kEAPSIMClientStateNone 1607 && context->previous_identifier == in_pkt->identifier) { 1608 /* re-send our previous response */ 1609 return ((EAPPacketRef)context->pkt); 1610 } 1611 subtype = eapsim_in->subtype; 1612 switch (subtype) { 1613 case kEAPSIMAKAPacketSubtypeSIMStart: 1614 eapsim_out = eapsim_start(context, in_pkt, tlvs_p, client_status); 1615 break; 1616 case kEAPSIMAKAPacketSubtypeSIMChallenge: 1617 eapsim_out = eapsim_challenge(context, in_pkt, tlvs_p, client_status); 1618 break; 1619 case kEAPSIMAKAPacketSubtypeNotification: 1620 eapsim_out = eapsim_notification(context, in_pkt, tlvs_p, 1621 client_status, error); 1622 break; 1623 case kEAPSIMAKAPacketSubtypeReauthentication: 1624 eapsim_out 1625 = eapsim_reauthentication(context, in_pkt, tlvs_p, client_status); 1626 break; 1627 default: 1628 *client_status = kEAPClientStatusProtocolError; 1629 EAPLOG_FL(LOG_NOTICE, "unexpected Subtype %s", 1630 EAPSIMAKAPacketSubtypeGetString(subtype)); 1631 *client_status = kEAPClientStatusProtocolError; 1632 goto done; 1633 } 1634 1635 done: 1636 TLVListFree(tlvs_p); 1637 if (*client_status != kEAPClientStatusOK) { 1638 context->plugin_state = kEAPClientStateFailure; 1639 context->state = kEAPSIMClientStateFailure; 1640 } 1641 if (eapsim_out == NULL 1642 && *client_status == kEAPClientStatusProtocolError) { 1643 eapsim_out 1644 = eapsim_make_client_error(context, in_pkt, 1645 kClientErrorCodeUnableToProcessPacket); 1646 } 1647 if (eapsim_out != NULL) { 1648 context->previous_identifier = in_pkt->identifier; 1649 } 1650 return (eapsim_out); 1651 1652} 1653 1654STATIC EAPClientState 1655eapsim_process(EAPClientPluginDataRef plugin, 1656 const EAPPacketRef in_pkt, 1657 EAPPacketRef * out_pkt_p, 1658 EAPClientStatus * client_status, 1659 EAPClientDomainSpecificError * error) 1660{ 1661 EAPSIMContextRef context = (EAPSIMContextRef)plugin->private; 1662 1663 *client_status = kEAPClientStatusOK; 1664 *error = 0; 1665 switch (in_pkt->code) { 1666 case kEAPCodeRequest: 1667 *out_pkt_p = eapsim_request(context, in_pkt, client_status, error); 1668 break; 1669 case kEAPCodeSuccess: 1670 context->previous_identifier = -1; 1671 if (context->state == kEAPSIMClientStateSuccess) { 1672 context->plugin_state = kEAPClientStateSuccess; 1673 } 1674 break; 1675 case kEAPCodeFailure: 1676 context->previous_identifier = -1; 1677 context->plugin_state = kEAPClientStateFailure; 1678 break; 1679 default: 1680 break; 1681 } 1682 return (context->plugin_state); 1683} 1684 1685STATIC const char * 1686eapsim_failure_string(EAPClientPluginDataRef plugin) 1687{ 1688 return (NULL); 1689} 1690 1691STATIC void * 1692eapsim_session_key(EAPClientPluginDataRef plugin, int * key_length) 1693{ 1694 EAPSIMContextRef context = (EAPSIMContextRef)plugin->private; 1695 1696 if (context->state == kEAPSIMClientStateSuccess 1697 && context->key_info_valid) { 1698 *key_length = 32; 1699 return (context->key_info.s.msk); 1700 } 1701 return (NULL); 1702} 1703 1704STATIC void * 1705eapsim_server_key(EAPClientPluginDataRef plugin, int * key_length) 1706{ 1707 EAPSIMContextRef context = (EAPSIMContextRef)plugin->private; 1708 1709 if (context->state == kEAPSIMClientStateSuccess 1710 && context->key_info_valid) { 1711 *key_length = 32; 1712 return (context->key_info.s.msk + 32); 1713 } 1714 return (NULL); 1715} 1716 1717STATIC CFDictionaryRef 1718eapsim_publish_props(EAPClientPluginDataRef plugin) 1719{ 1720 return (NULL); 1721} 1722 1723STATIC CFStringRef 1724eapsim_user_name_copy(CFDictionaryRef properties) 1725{ 1726 EAPSIMAKAAttributeType identity_type; 1727 CFStringRef imsi; 1728 EAPSIMAKAPersistentStateRef persist; 1729 CFStringRef ret_identity; 1730 1731 ret_identity = copy_static_identity(properties); 1732 if (ret_identity != NULL) { 1733 return (ret_identity); 1734 } 1735 imsi = SIMCopyIMSI(); 1736 if (imsi == NULL) { 1737 return (NULL); 1738 } 1739 identity_type = S_get_identity_type(properties); 1740 persist = EAPSIMAKAPersistentStateCreate(kEAPTypeEAPSIM, 1741 CC_SHA1_DIGEST_LENGTH, 1742 imsi, identity_type); 1743 CFRelease(imsi); 1744 if (persist != NULL) { 1745 ret_identity = sim_identity_create(persist, properties, 1746 identity_type, NULL); 1747 EAPSIMAKAPersistentStateRelease(persist); 1748 } 1749 return (ret_identity); 1750} 1751 1752/* 1753 * Function: eapsim_copy_identity 1754 * Purpose: 1755 * Return the current identity we should use in responding to an 1756 * EAP Request Identity packet. 1757 */ 1758STATIC CFStringRef 1759eapsim_copy_identity(EAPClientPluginDataRef plugin) 1760{ 1761 EAPSIMContextRef context = (EAPSIMContextRef)plugin->private; 1762 1763 EAPSIMContextSetLastIdentity(context, NULL); 1764 context->state = kEAPSIMClientStateNone; 1765 context->previous_identifier = -1; 1766 if (context->sim_static.rand != NULL) { 1767 return (copy_static_identity(plugin->properties)); 1768 } 1769 return (sim_identity_create(context->persist, plugin->properties, 1770 kAT_ANY_ID_REQ, NULL)); 1771} 1772 1773STATIC CFStringRef 1774eapsim_copy_packet_description(const EAPPacketRef pkt, bool * packet_is_valid) 1775{ 1776 return (EAPSIMAKAPacketCopyDescription(pkt, packet_is_valid)); 1777} 1778 1779STATIC EAPType 1780eapsim_type(void) 1781{ 1782 return (kEAPTypeEAPSIM); 1783 1784} 1785 1786STATIC const char * 1787eapsim_name(void) 1788{ 1789 return (EAP_SIM_NAME); 1790 1791} 1792 1793STATIC EAPClientPluginVersion 1794eapsim_version(void) 1795{ 1796 return (kEAPClientPluginVersion); 1797} 1798 1799STATIC struct func_table_ent { 1800 const char * name; 1801 void * func; 1802} func_table[] = { 1803#if 0 1804 { kEAPClientPluginFuncNameIntrospect, eapsim_introspect }, 1805#endif /* 0 */ 1806 { kEAPClientPluginFuncNameVersion, eapsim_version }, 1807 { kEAPClientPluginFuncNameEAPType, eapsim_type }, 1808 { kEAPClientPluginFuncNameEAPName, eapsim_name }, 1809 { kEAPClientPluginFuncNameInit, eapsim_init }, 1810 { kEAPClientPluginFuncNameFree, eapsim_free }, 1811 { kEAPClientPluginFuncNameProcess, eapsim_process }, 1812 { kEAPClientPluginFuncNameFreePacket, eapsim_free_packet }, 1813 { kEAPClientPluginFuncNameFailureString, eapsim_failure_string }, 1814 { kEAPClientPluginFuncNameSessionKey, eapsim_session_key }, 1815 { kEAPClientPluginFuncNameServerKey, eapsim_server_key }, 1816 { kEAPClientPluginFuncNamePublishProperties, eapsim_publish_props }, 1817 { kEAPClientPluginFuncNameUserName, eapsim_user_name_copy }, 1818 { kEAPClientPluginFuncNameCopyIdentity, eapsim_copy_identity }, 1819 { kEAPClientPluginFuncNameCopyPacketDescription, 1820 eapsim_copy_packet_description }, 1821 { NULL, NULL}, 1822}; 1823 1824 1825EAPClientPluginFuncRef 1826eapsim_introspect(EAPClientPluginFuncName name) 1827{ 1828 struct func_table_ent * scan; 1829 1830 for (scan = func_table; scan->name != NULL; scan++) { 1831 if (strcmp(name, scan->name) == 0) { 1832 return (scan->func); 1833 } 1834 } 1835 return (NULL); 1836} 1837 1838 1839#ifdef TEST_RAND_DUPS 1840const uint8_t randval1[3 * SIM_RAND_SIZE] = { 1841 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1842 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1843 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf 1844}; 1845 1846const uint8_t randval2[3 * SIM_RAND_SIZE] = { 1847 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1848 0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1849 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf 1850}; 1851 1852const uint8_t randval3[3 * SIM_RAND_SIZE] = { 1853 0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1854 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1855 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf 1856}; 1857 1858const uint8_t randval4[3 * SIM_RAND_SIZE] = { 1859 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1860 0x10, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 1861 0x20, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf 1862}; 1863 1864struct { 1865 const uint8_t * block; 1866 int size; 1867 bool duplicated; 1868} rands[] = { 1869 { randval1, sizeof(randval1), TRUE }, 1870 { randval2, sizeof(randval2), TRUE }, 1871 { randval3, sizeof(randval3), TRUE }, 1872 { randval4, sizeof(randval4), FALSE }, 1873 { NULL, 0 } 1874}; 1875 1876int 1877main() 1878{ 1879 int i; 1880 1881 for (i = 0; rands[i].block != NULL; i++) { 1882 bool duplicated; 1883 1884 duplicated = blocks_are_duplicated(rands[i].block, 1885 rands[i].size / SIM_RAND_SIZE, 1886 SIM_RAND_SIZE); 1887 if (duplicated == rands[i].duplicated) { 1888 printf("Test %d passed (found%sduplicate)\n", i, 1889 duplicated ? " " : " no "); 1890 } 1891 else { 1892 printf("Test %d failed\n", i); 1893 } 1894 } 1895 exit(0); 1896 return (0); 1897} 1898 1899#endif /* TEST_RAND_DUPS */ 1900 1901#ifdef TEST_SET_VERSION_LIST 1902int 1903main(int argc, char * argv[]) 1904{ 1905 EAPSIMContext context; 1906 uint16_t list1[2] = { 0x1234, 0x5678 }; 1907 uint16_t list2[3] = { 0x1, 0x2, 0x3 }; 1908 uint16_t list3[2] = { 0x4, 0x5 }; 1909 1910 EAPSIMContextClear(&context); 1911 EAPSIMContextSetVersionList(&context, 1912 list1, sizeof(list1) / sizeof(list1[0])); 1913 EAPSIMContextSetVersionList(&context, 1914 list1, sizeof(list1) / sizeof(list1[0])); 1915 EAPSIMContextSetVersionList(&context, 1916 list2, sizeof(list2) / sizeof(list2[0])); 1917 EAPSIMContextSetVersionList(&context, 1918 list2, sizeof(list2) / sizeof(list2[0])); 1919 EAPSIMContextSetVersionList(&context, 1920 list3, sizeof(list3) / sizeof(list3[0])); 1921 EAPSIMContextSetVersionList(&context, 1922 list3, sizeof(list3) / sizeof(list3[0])); 1923 EAPSIMContextSetVersionList(&context, NULL, 0); 1924 exit(0); 1925 return (0); 1926} 1927 1928#endif /* TEST_SET_VERSION_LIST */ 1929 1930#ifdef TEST_SIM_INFO 1931#if TARGET_OS_EMBEDDED 1932int 1933main() 1934{ 1935 CFStringRef identity; 1936 1937 identity = eapsim_user_name_copy(NULL); 1938 if (identity != NULL) { 1939 CFShow(identity); 1940 CFRelease(identity); 1941 } 1942 exit(0); 1943 return (0); 1944} 1945#endif /* TARGET_OS_EMBEDDED */ 1946#endif /* TEST_SIM_INFO */ 1947