Return to eap_aka_peer.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / eap_aka |
1.1 misho 1: /* 2: * Copyright (C) 2006-2009 Martin Willi 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "eap_aka_peer.h" 17: 18: #include <library.h> 19: #include <daemon.h> 20: 21: #include <simaka_message.h> 22: #include <simaka_crypto.h> 23: #include <simaka_manager.h> 24: 25: typedef struct private_eap_aka_peer_t private_eap_aka_peer_t; 26: 27: /** 28: * Private data of an eap_aka_peer_t object. 29: */ 30: struct private_eap_aka_peer_t { 31: 32: /** 33: * Public authenticator_t interface. 34: */ 35: eap_aka_peer_t public; 36: 37: /** 38: * AKA backend manager 39: */ 40: simaka_manager_t *mgr; 41: 42: /** 43: * EAP-AKA crypto helper 44: */ 45: simaka_crypto_t *crypto; 46: 47: /** 48: * permanent ID of peer 49: */ 50: identification_t *permanent; 51: 52: /** 53: * Pseudonym identity the peer uses 54: */ 55: identification_t *pseudonym; 56: 57: /** 58: * Reauthentication identity the peer uses 59: */ 60: identification_t *reauth; 61: 62: /** 63: * EAP message identifier 64: */ 65: uint8_t identifier; 66: 67: /** 68: * MSK 69: */ 70: chunk_t msk; 71: 72: /** 73: * Master key, if reauthentication is used 74: */ 75: char mk[HASH_SIZE_SHA1]; 76: 77: /** 78: * Counter value if reauthentication is used 79: */ 80: uint16_t counter; 81: }; 82: 83: /** 84: * Generate a payload from a message, destroy message 85: */ 86: static bool generate_payload(simaka_message_t *message, chunk_t data, 87: eap_payload_t **out) 88: { 89: chunk_t chunk; 90: bool ok; 91: 92: ok = message->generate(message, data, &chunk); 93: if (ok) 94: { 95: *out = eap_payload_create_data_own(chunk); 96: } 97: message->destroy(message); 98: return ok; 99: } 100: 101: /** 102: * Create a AKA_CLIENT_ERROR: "Unable to process" 103: */ 104: static bool create_client_error(private_eap_aka_peer_t *this, 105: eap_payload_t **out) 106: { 107: simaka_message_t *message; 108: uint16_t encoded; 109: 110: DBG1(DBG_IKE, "sending client error '%N'", 111: simaka_client_error_names, AKA_UNABLE_TO_PROCESS); 112: 113: message = simaka_message_create(FALSE, this->identifier, EAP_AKA, 114: AKA_CLIENT_ERROR, this->crypto); 115: encoded = htons(AKA_UNABLE_TO_PROCESS); 116: message->add_attribute(message, AT_CLIENT_ERROR_CODE, 117: chunk_create((char*)&encoded, sizeof(encoded))); 118: 119: return generate_payload(message, chunk_empty, out); 120: } 121: 122: /** 123: * process an EAP-AKA/Request/Identity message 124: */ 125: static status_t process_identity(private_eap_aka_peer_t *this, 126: simaka_message_t *in, eap_payload_t **out) 127: { 128: simaka_message_t *message; 129: enumerator_t *enumerator; 130: simaka_attribute_t type; 131: chunk_t data, id = chunk_empty; 132: simaka_attribute_t id_req = 0; 133: 134: /* reset previously uses reauthentication/pseudonym data */ 135: this->crypto->clear_keys(this->crypto); 136: DESTROY_IF(this->pseudonym); 137: this->pseudonym = NULL; 138: DESTROY_IF(this->reauth); 139: this->reauth = NULL; 140: 141: enumerator = in->create_attribute_enumerator(in); 142: while (enumerator->enumerate(enumerator, &type, &data)) 143: { 144: switch (type) 145: { 146: case AT_ANY_ID_REQ: 147: case AT_FULLAUTH_ID_REQ: 148: case AT_PERMANENT_ID_REQ: 149: id_req = type; 150: break; 151: default: 152: if (!simaka_attribute_skippable(type)) 153: { 154: enumerator->destroy(enumerator); 155: if (!create_client_error(this, out)) 156: { 157: return FAILED; 158: } 159: return NEED_MORE; 160: } 161: break; 162: } 163: } 164: enumerator->destroy(enumerator); 165: 166: switch (id_req) 167: { 168: case AT_ANY_ID_REQ: 169: this->reauth = this->mgr->card_get_reauth(this->mgr, 170: this->permanent, this->mk, &this->counter); 171: if (this->reauth) 172: { 173: id = this->reauth->get_encoding(this->reauth); 174: break; 175: } 176: /* FALL */ 177: case AT_FULLAUTH_ID_REQ: 178: this->pseudonym = this->mgr->card_get_pseudonym(this->mgr, 179: this->permanent); 180: if (this->pseudonym) 181: { 182: id = this->pseudonym->get_encoding(this->pseudonym); 183: break; 184: } 185: /* FALL */ 186: case AT_PERMANENT_ID_REQ: 187: id = this->permanent->get_encoding(this->permanent); 188: break; 189: default: 190: break; 191: } 192: message = simaka_message_create(FALSE, this->identifier, EAP_AKA, 193: AKA_IDENTITY, this->crypto); 194: if (id.len) 195: { 196: message->add_attribute(message, AT_IDENTITY, id); 197: } 198: if (!generate_payload(message, chunk_empty, out)) 199: { 200: return FAILED; 201: } 202: return NEED_MORE; 203: } 204: 205: /** 206: * Process an EAP-AKA/Request/Challenge message 207: */ 208: static status_t process_challenge(private_eap_aka_peer_t *this, 209: simaka_message_t *in, eap_payload_t **out) 210: { 211: simaka_message_t *message; 212: enumerator_t *enumerator; 213: simaka_attribute_t type; 214: chunk_t data, rand = chunk_empty, autn = chunk_empty, mk; 215: u_char res[AKA_RES_MAX], ck[AKA_CK_LEN], ik[AKA_IK_LEN], auts[AKA_AUTS_LEN]; 216: int res_len; 217: identification_t *id; 218: status_t status; 219: 220: enumerator = in->create_attribute_enumerator(in); 221: while (enumerator->enumerate(enumerator, &type, &data)) 222: { 223: switch (type) 224: { 225: case AT_RAND: 226: rand = data; 227: break; 228: case AT_AUTN: 229: autn = data; 230: break; 231: default: 232: if (!simaka_attribute_skippable(type)) 233: { 234: enumerator->destroy(enumerator); 235: if (!create_client_error(this, out)) 236: { 237: return FAILED; 238: } 239: return NEED_MORE; 240: } 241: break; 242: } 243: } 244: enumerator->destroy(enumerator); 245: 246: if (!rand.len || !autn.len) 247: { 248: DBG1(DBG_IKE, "received invalid EAP-AKA challenge message"); 249: if (!create_client_error(this, out)) 250: { 251: return FAILED; 252: } 253: return NEED_MORE; 254: } 255: 256: status = this->mgr->card_get_quintuplet(this->mgr, this->permanent, 257: rand.ptr, autn.ptr, ck, ik, res, &res_len); 258: if (status == INVALID_STATE && 259: this->mgr->card_resync(this->mgr, this->permanent, rand.ptr, auts)) 260: { 261: DBG1(DBG_IKE, "received SQN invalid, sending %N", 262: simaka_subtype_names, AKA_SYNCHRONIZATION_FAILURE); 263: message = simaka_message_create(FALSE, in->get_identifier(in), EAP_AKA, 264: AKA_SYNCHRONIZATION_FAILURE, this->crypto); 265: message->add_attribute(message, AT_AUTS, 266: chunk_create(auts, AKA_AUTS_LEN)); 267: if (!generate_payload(message, chunk_empty, out)) 268: { 269: return FAILED; 270: } 271: return NEED_MORE; 272: } 273: if (status != SUCCESS) 274: { 275: DBG1(DBG_IKE, "no USIM found with quintuplets for '%Y', sending %N", 276: this->permanent, simaka_subtype_names, AKA_AUTHENTICATION_REJECT); 277: message = simaka_message_create(FALSE, in->get_identifier(in), EAP_AKA, 278: AKA_AUTHENTICATION_REJECT, this->crypto); 279: if (!generate_payload(message, chunk_empty, out)) 280: { 281: return FAILED; 282: } 283: return NEED_MORE; 284: } 285: 286: id = this->permanent; 287: if (this->pseudonym) 288: { 289: id = this->pseudonym; 290: } 291: data = chunk_cata("cc", chunk_create(ik, AKA_IK_LEN), 292: chunk_create(ck, AKA_CK_LEN)); 293: chunk_clear(&this->msk); 294: if (!this->crypto->derive_keys_full(this->crypto, id, data, &mk, &this->msk)) 295: { 296: return FAILED; 297: } 298: memcpy(this->mk, mk.ptr, mk.len); 299: chunk_clear(&mk); 300: 301: /* Verify AT_MAC attribute and parse() again after key derivation, 302: * reading encrypted attributes */ 303: if (!in->verify(in, chunk_empty) || !in->parse(in)) 304: { 305: if (!create_client_error(this, out)) 306: { 307: return FAILED; 308: } 309: return NEED_MORE; 310: } 311: 312: enumerator = in->create_attribute_enumerator(in); 313: while (enumerator->enumerate(enumerator, &type, &data)) 314: { 315: switch (type) 316: { 317: case AT_NEXT_REAUTH_ID: 318: this->counter = 0; 319: id = identification_create_from_data(data); 320: this->mgr->card_set_reauth(this->mgr, this->permanent, id, 321: this->mk, this->counter); 322: id->destroy(id); 323: break; 324: case AT_NEXT_PSEUDONYM: 325: id = identification_create_from_data(data); 326: this->mgr->card_set_pseudonym(this->mgr, this->permanent, id); 327: id->destroy(id); 328: break; 329: default: 330: break; 331: } 332: } 333: enumerator->destroy(enumerator); 334: 335: message = simaka_message_create(FALSE, this->identifier, EAP_AKA, 336: AKA_CHALLENGE, this->crypto); 337: message->add_attribute(message, AT_RES, chunk_create(res, res_len)); 338: if (!generate_payload(message, chunk_empty, out)) 339: { 340: return FAILED; 341: } 342: return NEED_MORE; 343: } 344: 345: /** 346: * Check if a received counter value is acceptable 347: */ 348: static bool counter_too_small(private_eap_aka_peer_t *this, chunk_t chunk) 349: { 350: uint16_t counter; 351: 352: memcpy(&counter, chunk.ptr, sizeof(counter)); 353: counter = htons(counter); 354: return counter < this->counter; 355: } 356: 357: /** 358: * process an EAP-AKA/Request/Reauthentication message 359: */ 360: static status_t process_reauthentication(private_eap_aka_peer_t *this, 361: simaka_message_t *in, eap_payload_t **out) 362: { 363: simaka_message_t *message; 364: enumerator_t *enumerator; 365: simaka_attribute_t type; 366: chunk_t data, counter = chunk_empty, nonce = chunk_empty, id = chunk_empty; 367: 368: if (!this->reauth) 369: { 370: DBG1(DBG_IKE, "received %N, but not expected", 371: simaka_subtype_names, AKA_REAUTHENTICATION); 372: if (!create_client_error(this, out)) 373: { 374: return FAILED; 375: } 376: return NEED_MORE; 377: } 378: 379: if (!this->crypto->derive_keys_reauth(this->crypto, 380: chunk_create(this->mk, HASH_SIZE_SHA1))) 381: { 382: return FAILED; 383: } 384: 385: /* verify MAC and parse again with decryption key */ 386: if (!in->verify(in, chunk_empty) || !in->parse(in)) 387: { 388: if (!create_client_error(this, out)) 389: { 390: return FAILED; 391: } 392: return NEED_MORE; 393: } 394: 395: enumerator = in->create_attribute_enumerator(in); 396: while (enumerator->enumerate(enumerator, &type, &data)) 397: { 398: switch (type) 399: { 400: case AT_COUNTER: 401: counter = data; 402: break; 403: case AT_NONCE_S: 404: nonce = data; 405: break; 406: case AT_NEXT_REAUTH_ID: 407: id = data; 408: break; 409: default: 410: if (!simaka_attribute_skippable(type)) 411: { 412: enumerator->destroy(enumerator); 413: if (!create_client_error(this, out)) 414: { 415: return FAILED; 416: } 417: return NEED_MORE; 418: } 419: break; 420: } 421: } 422: enumerator->destroy(enumerator); 423: 424: if (!nonce.len || !counter.len) 425: { 426: DBG1(DBG_IKE, "EAP-AKA/Request/Reauthentication message incomplete"); 427: if (!create_client_error(this, out)) 428: { 429: return FAILED; 430: } 431: return NEED_MORE; 432: } 433: 434: message = simaka_message_create(FALSE, in->get_identifier(in), EAP_AKA, 435: AKA_REAUTHENTICATION, this->crypto); 436: if (counter_too_small(this, counter)) 437: { 438: DBG1(DBG_IKE, "reauthentication counter too small"); 439: message->add_attribute(message, AT_COUNTER_TOO_SMALL, chunk_empty); 440: } 441: else 442: { 443: chunk_clear(&this->msk); 444: if (!this->crypto->derive_keys_reauth_msk(this->crypto, 445: this->reauth, counter, nonce, 446: chunk_create(this->mk, HASH_SIZE_SHA1), &this->msk)) 447: { 448: message->destroy(message); 449: return FAILED; 450: } 451: if (id.len) 452: { 453: identification_t *reauth; 454: 455: reauth = identification_create_from_data(data); 456: this->mgr->card_set_reauth(this->mgr, this->permanent, reauth, 457: this->mk, this->counter); 458: reauth->destroy(reauth); 459: } 460: } 461: message->add_attribute(message, AT_COUNTER, counter); 462: if (!generate_payload(message, nonce, out)) 463: { 464: return FAILED; 465: } 466: return NEED_MORE; 467: } 468: 469: /** 470: * Process an EAP-AKA/Request/Notification message 471: */ 472: static status_t process_notification(private_eap_aka_peer_t *this, 473: simaka_message_t *in, eap_payload_t **out) 474: { 475: simaka_message_t *message; 476: enumerator_t *enumerator; 477: simaka_attribute_t type; 478: chunk_t data; 479: bool success = TRUE; 480: 481: enumerator = in->create_attribute_enumerator(in); 482: while (enumerator->enumerate(enumerator, &type, &data)) 483: { 484: if (type == AT_NOTIFICATION) 485: { 486: uint16_t code; 487: 488: memcpy(&code, data.ptr, sizeof(code)); 489: code = ntohs(code); 490: 491: /* test success bit */ 492: if (!(data.ptr[0] & 0x80)) 493: { 494: DBG1(DBG_IKE, "received EAP-AKA notification error '%N'", 495: simaka_notification_names, code); 496: } 497: else 498: { 499: DBG1(DBG_IKE, "received EAP-AKA notification '%N'", 500: simaka_notification_names, code); 501: } 502: } 503: else if (!simaka_attribute_skippable(type)) 504: { 505: success = FALSE; 506: break; 507: } 508: } 509: enumerator->destroy(enumerator); 510: 511: if (success) 512: { /* empty notification reply */ 513: message = simaka_message_create(FALSE, this->identifier, EAP_AKA, 514: AKA_NOTIFICATION, this->crypto); 515: if (!generate_payload(message, chunk_empty, out)) 516: { 517: return FAILED; 518: } 519: } 520: else 521: { 522: if (!create_client_error(this, out)) 523: { 524: return FAILED; 525: } 526: } 527: return NEED_MORE; 528: } 529: 530: 531: METHOD(eap_method_t, process, status_t, 532: private_eap_aka_peer_t *this, eap_payload_t *in, eap_payload_t **out) 533: { 534: simaka_message_t *message; 535: status_t status; 536: 537: /* store received EAP message identifier */ 538: this->identifier = in->get_identifier(in); 539: 540: message = simaka_message_create_from_payload(in->get_data(in), this->crypto); 541: if (!message) 542: { 543: if (!create_client_error(this, out)) 544: { 545: return FAILED; 546: } 547: return NEED_MORE; 548: } 549: if (!message->parse(message)) 550: { 551: message->destroy(message); 552: if (!create_client_error(this, out)) 553: { 554: return FAILED; 555: } 556: return NEED_MORE; 557: } 558: switch (message->get_subtype(message)) 559: { 560: case AKA_IDENTITY: 561: status = process_identity(this, message, out); 562: break; 563: case AKA_CHALLENGE: 564: status = process_challenge(this, message, out); 565: break; 566: case AKA_REAUTHENTICATION: 567: status = process_reauthentication(this, message, out); 568: break; 569: case AKA_NOTIFICATION: 570: status = process_notification(this, message, out); 571: break; 572: default: 573: DBG1(DBG_IKE, "unable to process EAP-AKA subtype %N", 574: simaka_subtype_names, message->get_subtype(message)); 575: if (!create_client_error(this, out)) 576: { 577: status = FAILED; 578: } 579: else 580: { 581: status = NEED_MORE; 582: } 583: break; 584: } 585: message->destroy(message); 586: return status; 587: } 588: 589: METHOD(eap_method_t, initiate, status_t, 590: private_eap_aka_peer_t *this, eap_payload_t **out) 591: { 592: /* peer never initiates */ 593: return FAILED; 594: } 595: 596: METHOD(eap_method_t, get_type, eap_type_t, 597: private_eap_aka_peer_t *this, uint32_t *vendor) 598: { 599: *vendor = 0; 600: return EAP_AKA; 601: } 602: 603: METHOD(eap_method_t, get_msk, status_t, 604: private_eap_aka_peer_t *this, chunk_t *msk) 605: { 606: if (this->msk.ptr) 607: { 608: *msk = this->msk; 609: return SUCCESS; 610: } 611: return FAILED; 612: } 613: 614: METHOD(eap_method_t, get_identifier, uint8_t, 615: private_eap_aka_peer_t *this) 616: { 617: return this->identifier; 618: } 619: 620: METHOD(eap_method_t, set_identifier, void, 621: private_eap_aka_peer_t *this, uint8_t identifier) 622: { 623: this->identifier = identifier; 624: } 625: 626: METHOD(eap_method_t, is_mutual, bool, 627: private_eap_aka_peer_t *this) 628: { 629: return TRUE; 630: } 631: 632: METHOD(eap_method_t, destroy, void, 633: private_eap_aka_peer_t *this) 634: { 635: this->crypto->destroy(this->crypto); 636: this->permanent->destroy(this->permanent); 637: DESTROY_IF(this->pseudonym); 638: DESTROY_IF(this->reauth); 639: free(this->msk.ptr); 640: free(this); 641: } 642: 643: /* 644: * Described in header. 645: */ 646: eap_aka_peer_t *eap_aka_peer_create(identification_t *server, 647: identification_t *peer) 648: { 649: private_eap_aka_peer_t *this; 650: 651: INIT(this, 652: .public = { 653: .interface = { 654: .initiate = _initiate, 655: .process = _process, 656: .get_type = _get_type, 657: .is_mutual = _is_mutual, 658: .get_msk = _get_msk, 659: .get_identifier = _get_identifier, 660: .set_identifier = _set_identifier, 661: .destroy = _destroy, 662: }, 663: }, 664: .crypto = simaka_crypto_create(EAP_AKA), 665: .mgr = lib->get(lib, "aka-manager"), 666: ); 667: 668: if (!this->crypto) 669: { 670: free(this); 671: return NULL; 672: } 673: 674: this->permanent = peer->clone(peer); 675: 676: return &this->public; 677: } 678: