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