1118611Snjl/* 2118611Snjl * hostapd / EAP-SIM (RFC 4186) 3118611Snjl * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi> 4118611Snjl * 5118611Snjl * This program is free software; you can redistribute it and/or modify 6118611Snjl * it under the terms of the GNU General Public License version 2 as 7118611Snjl * published by the Free Software Foundation. 8217365Sjkim * 9229989Sjkim * Alternatively, this software may be distributed under the terms of BSD 10118611Snjl * license. 11118611Snjl * 12217365Sjkim * See README and COPYING for more details. 13217365Sjkim */ 14217365Sjkim 15217365Sjkim#include "includes.h" 16217365Sjkim 17217365Sjkim#include "common.h" 18217365Sjkim#include "eap_server/eap_i.h" 19217365Sjkim#include "eap_common/eap_sim_common.h" 20217365Sjkim#include "eap_server/eap_sim_db.h" 21217365Sjkim 22217365Sjkim 23217365Sjkimstruct eap_sim_data { 24217365Sjkim u8 mk[EAP_SIM_MK_LEN]; 25217365Sjkim u8 nonce_mt[EAP_SIM_NONCE_MT_LEN]; 26118611Snjl u8 nonce_s[EAP_SIM_NONCE_S_LEN]; 27217365Sjkim u8 k_aut[EAP_SIM_K_AUT_LEN]; 28217365Sjkim u8 k_encr[EAP_SIM_K_ENCR_LEN]; 29217365Sjkim u8 msk[EAP_SIM_KEYING_DATA_LEN]; 30118611Snjl u8 emsk[EAP_EMSK_LEN]; 31217365Sjkim u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; 32217365Sjkim u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; 33217365Sjkim u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; 34217365Sjkim int num_chal; 35217365Sjkim enum { 36217365Sjkim START, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE 37217365Sjkim } state; 38217365Sjkim char *next_pseudonym; 39217365Sjkim char *next_reauth_id; 40217365Sjkim u16 counter; 41217365Sjkim struct eap_sim_reauth *reauth; 42217365Sjkim u16 notification; 43217365Sjkim int use_result_ind; 44118611Snjl}; 45118611Snjl 46118611Snjl 47118611Snjlstatic const char * eap_sim_state_txt(int state) 48151937Sjkim{ 49193529Sjkim switch (state) { 50210976Sjkim case START: 51118611Snjl return "START"; 52118611Snjl case CHALLENGE: 53118611Snjl return "CHALLENGE"; 54118611Snjl case REAUTH: 55118611Snjl return "REAUTH"; 56118611Snjl case SUCCESS: 57118611Snjl return "SUCCESS"; 58118611Snjl case FAILURE: 59151937Sjkim return "FAILURE"; 60118611Snjl case NOTIFICATION: 61151937Sjkim return "NOTIFICATION"; 62151937Sjkim default: 63151937Sjkim return "Unknown?!"; 64151937Sjkim } 65151937Sjkim} 66237412Sjkim 67151937Sjkim 68151937Sjkimstatic void eap_sim_state(struct eap_sim_data *data, int state) 69151937Sjkim{ 70151937Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s", 71151937Sjkim eap_sim_state_txt(data->state), 72151937Sjkim eap_sim_state_txt(state)); 73151937Sjkim data->state = state; 74151937Sjkim} 75151937Sjkim 76151937Sjkim 77193529Sjkimstatic void * eap_sim_init(struct eap_sm *sm) 78151937Sjkim{ 79151937Sjkim struct eap_sim_data *data; 80151937Sjkim 81151937Sjkim if (sm->eap_sim_db_priv == NULL) { 82197104Sjkim wpa_printf(MSG_WARNING, "EAP-SIM: eap_sim_db not configured"); 83197104Sjkim return NULL; 84197104Sjkim } 85197104Sjkim 86197104Sjkim data = os_zalloc(sizeof(*data)); 87151937Sjkim if (data == NULL) 88197104Sjkim return NULL; 89197104Sjkim data->state = START; 90197104Sjkim 91197104Sjkim return data; 92197104Sjkim} 93197104Sjkim 94197104Sjkim 95197104Sjkimstatic void eap_sim_reset(struct eap_sm *sm, void *priv) 96197104Sjkim{ 97197104Sjkim struct eap_sim_data *data = priv; 98197104Sjkim os_free(data->next_pseudonym); 99238381Sjkim os_free(data->next_reauth_id); 100197104Sjkim os_free(data); 101197104Sjkim} 102118611Snjl 103118611Snjl 104118611Snjlstatic struct wpabuf * eap_sim_build_start(struct eap_sm *sm, 105118611Snjl struct eap_sim_data *data, u8 id) 106118611Snjl{ 107118611Snjl struct eap_sim_msg *msg; 108118611Snjl u8 ver[2]; 109118611Snjl 110118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); 111118611Snjl msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 112118611Snjl EAP_SIM_SUBTYPE_START); 113118611Snjl if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity, 114151937Sjkim sm->identity_len)) { 115118611Snjl wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); 116118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); 117118611Snjl } else { 118118611Snjl /* 119228110Sjkim * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is 120228110Sjkim * ignored and the SIM/Start is used to request the identity. 121228110Sjkim */ 122238381Sjkim wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ"); 123197104Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0); 124233250Sjkim } 125233250Sjkim wpa_printf(MSG_DEBUG, " AT_VERSION_LIST"); 126233250Sjkim ver[0] = 0; 127233250Sjkim ver[1] = EAP_SIM_VERSION; 128234623Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver), 129233250Sjkim ver, sizeof(ver)); 130197104Sjkim return eap_sim_msg_finish(msg, NULL, NULL, 0); 131228110Sjkim} 132228110Sjkim 133228110Sjkim 134228110Sjkimstatic int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, 135228110Sjkim struct eap_sim_msg *msg, u16 counter, 136228110Sjkim const u8 *nonce_s) 137233250Sjkim{ 138234623Sjkim os_free(data->next_pseudonym); 139118611Snjl data->next_pseudonym = 140138287Smarks eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0); 141233250Sjkim os_free(data->next_reauth_id); 142233250Sjkim if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { 143233250Sjkim data->next_reauth_id = 144118611Snjl eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0); 145138287Smarks } else { 146228110Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " 147228110Sjkim "count exceeded - force full authentication"); 148228110Sjkim data->next_reauth_id = NULL; 149228110Sjkim } 150228110Sjkim 151228110Sjkim if (data->next_pseudonym == NULL && data->next_reauth_id == NULL && 152118611Snjl counter == 0 && nonce_s == NULL) 153212761Sjkim return 0; 154228110Sjkim 155228110Sjkim wpa_printf(MSG_DEBUG, " AT_IV"); 156228110Sjkim wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 157118611Snjl eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA); 158209746Sjkim 159228110Sjkim if (counter > 0) { 160228110Sjkim wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter); 161228110Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0); 162209746Sjkim } 163118611Snjl 164228110Sjkim if (nonce_s) { 165228110Sjkim wpa_printf(MSG_DEBUG, " *AT_NONCE_S"); 166228110Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s, 167228110Sjkim EAP_SIM_NONCE_S_LEN); 168228110Sjkim } 169228110Sjkim 170228110Sjkim if (data->next_pseudonym) { 171228110Sjkim wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)", 172118611Snjl data->next_pseudonym); 173118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM, 174237412Sjkim os_strlen(data->next_pseudonym), 175228110Sjkim (u8 *) data->next_pseudonym, 176237412Sjkim os_strlen(data->next_pseudonym)); 177228110Sjkim } 178228110Sjkim 179237412Sjkim if (data->next_reauth_id) { 180237412Sjkim wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)", 181237412Sjkim data->next_reauth_id); 182237412Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID, 183237412Sjkim os_strlen(data->next_reauth_id), 184237412Sjkim (u8 *) data->next_reauth_id, 185237412Sjkim os_strlen(data->next_reauth_id)); 186237412Sjkim } 187118611Snjl 188118611Snjl if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) { 189118611Snjl wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt " 190118611Snjl "AT_ENCR_DATA"); 191118611Snjl return -1; 192237412Sjkim } 193118611Snjl 194118611Snjl return 0; 195118611Snjl} 196118611Snjl 197118611Snjl 198237412Sjkimstatic struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm, 199118611Snjl struct eap_sim_data *data, 200118611Snjl u8 id) 201118611Snjl{ 202151937Sjkim struct eap_sim_msg *msg; 203237412Sjkim 204118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge"); 205118611Snjl msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 206118611Snjl EAP_SIM_SUBTYPE_CHALLENGE); 207228110Sjkim wpa_printf(MSG_DEBUG, " AT_RAND"); 208118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand, 209118611Snjl data->num_chal * GSM_RAND_LEN); 210118611Snjl 211118611Snjl if (eap_sim_build_encr(sm, data, msg, 0, NULL)) { 212118611Snjl eap_sim_msg_free(msg); 213118611Snjl return NULL; 214118611Snjl } 215118611Snjl 216118611Snjl if (sm->eap_sim_aka_result_ind) { 217118611Snjl wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 218118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 219118611Snjl } 220118611Snjl 221118611Snjl wpa_printf(MSG_DEBUG, " AT_MAC"); 222118611Snjl eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 223118611Snjl return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt, 224118611Snjl EAP_SIM_NONCE_MT_LEN); 225118611Snjl} 226118611Snjl 227118611Snjl 228118611Snjlstatic struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, 229118611Snjl struct eap_sim_data *data, u8 id) 230151937Sjkim{ 231118611Snjl struct eap_sim_msg *msg; 232118611Snjl 233118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication"); 234118611Snjl 235228110Sjkim if (os_get_random(data->nonce_s, EAP_SIM_NONCE_S_LEN)) 236228110Sjkim return NULL; 237118611Snjl wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S", 238118611Snjl data->nonce_s, EAP_SIM_NONCE_S_LEN); 239118611Snjl 240118611Snjl eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, 241118611Snjl data->emsk); 242118611Snjl eap_sim_derive_keys_reauth(data->counter, sm->identity, 243118611Snjl sm->identity_len, data->nonce_s, data->mk, 244118611Snjl data->msk, data->emsk); 245118611Snjl 246118611Snjl msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 247118611Snjl EAP_SIM_SUBTYPE_REAUTHENTICATION); 248118611Snjl 249118611Snjl if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) { 250118611Snjl eap_sim_msg_free(msg); 251118611Snjl return NULL; 252118611Snjl } 253151937Sjkim 254151937Sjkim if (sm->eap_sim_aka_result_ind) { 255151937Sjkim wpa_printf(MSG_DEBUG, " AT_RESULT_IND"); 256118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); 257118611Snjl } 258118611Snjl 259118611Snjl wpa_printf(MSG_DEBUG, " AT_MAC"); 260118611Snjl eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 261118611Snjl return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 262118611Snjl} 263118611Snjl 264118611Snjl 265118611Snjlstatic struct wpabuf * eap_sim_build_notification(struct eap_sm *sm, 266118611Snjl struct eap_sim_data *data, 267118611Snjl u8 id) 268118611Snjl{ 269118611Snjl struct eap_sim_msg *msg; 270118611Snjl 271118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Notification"); 272118611Snjl msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, 273118611Snjl EAP_SIM_SUBTYPE_NOTIFICATION); 274118611Snjl wpa_printf(MSG_DEBUG, " AT_NOTIFICATION (%d)", data->notification); 275118611Snjl eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification, 276118611Snjl NULL, 0); 277118611Snjl if (data->use_result_ind) { 278118611Snjl if (data->reauth) { 279118611Snjl wpa_printf(MSG_DEBUG, " AT_IV"); 280118611Snjl wpa_printf(MSG_DEBUG, " AT_ENCR_DATA"); 281118611Snjl eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, 282197104Sjkim EAP_SIM_AT_ENCR_DATA); 283118611Snjl wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", 284197104Sjkim data->counter); 285197104Sjkim eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, data->counter, 286118611Snjl NULL, 0); 287118611Snjl 288118611Snjl if (eap_sim_msg_add_encr_end(msg, data->k_encr, 289197104Sjkim EAP_SIM_AT_PADDING)) { 290118611Snjl wpa_printf(MSG_WARNING, "EAP-SIM: Failed to " 291118611Snjl "encrypt AT_ENCR_DATA"); 292118611Snjl eap_sim_msg_free(msg); 293197104Sjkim return NULL; 294197104Sjkim } 295197104Sjkim } 296197104Sjkim 297197104Sjkim wpa_printf(MSG_DEBUG, " AT_MAC"); 298197104Sjkim eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); 299197104Sjkim } 300197104Sjkim return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); 301197104Sjkim} 302197104Sjkim 303197104Sjkim 304197104Sjkimstatic struct wpabuf * eap_sim_buildReq(struct eap_sm *sm, void *priv, u8 id) 305197104Sjkim{ 306197104Sjkim struct eap_sim_data *data = priv; 307197104Sjkim 308197104Sjkim switch (data->state) { 309197104Sjkim case START: 310197104Sjkim return eap_sim_build_start(sm, data, id); 311197104Sjkim case CHALLENGE: 312197104Sjkim return eap_sim_build_challenge(sm, data, id); 313197104Sjkim case REAUTH: 314197104Sjkim return eap_sim_build_reauth(sm, data, id); 315197104Sjkim case NOTIFICATION: 316197104Sjkim return eap_sim_build_notification(sm, data, id); 317197104Sjkim default: 318197104Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " 319197104Sjkim "buildReq", data->state); 320197104Sjkim break; 321197104Sjkim } 322197104Sjkim return NULL; 323197104Sjkim} 324193529Sjkim 325197104Sjkim 326197104Sjkimstatic Boolean eap_sim_check(struct eap_sm *sm, void *priv, 327118611Snjl struct wpabuf *respData) 328197104Sjkim{ 329197104Sjkim struct eap_sim_data *data = priv; 330197104Sjkim const u8 *pos; 331197104Sjkim size_t len; 332197104Sjkim u8 subtype; 333118611Snjl 334118611Snjl pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); 335197104Sjkim if (pos == NULL || len < 3) { 336197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame"); 337197104Sjkim return TRUE; 338197104Sjkim } 339197104Sjkim subtype = *pos; 340197104Sjkim 341197104Sjkim if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) 342118611Snjl return FALSE; 343197104Sjkim 344197104Sjkim switch (data->state) { 345197104Sjkim case START: 346197104Sjkim if (subtype != EAP_SIM_SUBTYPE_START) { 347197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 348197104Sjkim "subtype %d", subtype); 349197104Sjkim return TRUE; 350197104Sjkim } 351197104Sjkim break; 352197104Sjkim case CHALLENGE: 353118611Snjl if (subtype != EAP_SIM_SUBTYPE_CHALLENGE) { 354197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 355197104Sjkim "subtype %d", subtype); 356197104Sjkim return TRUE; 357197104Sjkim } 358197104Sjkim break; 359197104Sjkim case REAUTH: 360197104Sjkim if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) { 361197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 362197104Sjkim "subtype %d", subtype); 363197104Sjkim return TRUE; 364197104Sjkim } 365197104Sjkim break; 366197104Sjkim case NOTIFICATION: 367197104Sjkim if (subtype != EAP_SIM_SUBTYPE_NOTIFICATION) { 368197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response " 369197104Sjkim "subtype %d", subtype); 370118611Snjl return TRUE; 371118611Snjl } 372197104Sjkim break; 373197104Sjkim default: 374197104Sjkim wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for " 375197104Sjkim "processing a response", data->state); 376197104Sjkim return TRUE; 377197104Sjkim } 378197104Sjkim 379197104Sjkim return FALSE; 380197104Sjkim} 381197104Sjkim 382197104Sjkim 383197104Sjkimstatic int eap_sim_supported_ver(struct eap_sim_data *data, int version) 384197104Sjkim{ 385197104Sjkim return version == EAP_SIM_VERSION; 386197104Sjkim} 387197104Sjkim 388197104Sjkim 389197104Sjkimstatic void eap_sim_process_start(struct eap_sm *sm, 390197104Sjkim struct eap_sim_data *data, 391197104Sjkim struct wpabuf *respData, 392197104Sjkim struct eap_sim_attrs *attr) 393197104Sjkim{ 394197104Sjkim const u8 *identity; 395197104Sjkim size_t identity_len; 396197104Sjkim u8 ver_list[2]; 397197104Sjkim 398197104Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response"); 399197104Sjkim 400197104Sjkim if (attr->identity) { 401197104Sjkim os_free(sm->identity); 402212761Sjkim sm->identity = os_malloc(attr->identity_len); 403197104Sjkim if (sm->identity) { 404197104Sjkim os_memcpy(sm->identity, attr->identity, 405118611Snjl attr->identity_len); 406118611Snjl sm->identity_len = attr->identity_len; 407197104Sjkim } 408118611Snjl } 409197104Sjkim 410197104Sjkim identity = NULL; 411197104Sjkim identity_len = 0; 412197104Sjkim 413197104Sjkim if (sm->identity && sm->identity_len > 0 && 414233250Sjkim sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) { 415197104Sjkim identity = sm->identity; 416197104Sjkim identity_len = sm->identity_len; 417197104Sjkim } else { 418197104Sjkim identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, 419233250Sjkim sm->identity, 420197104Sjkim sm->identity_len, 421197104Sjkim &identity_len); 422197104Sjkim if (identity == NULL) { 423197104Sjkim data->reauth = eap_sim_db_get_reauth_entry( 424233250Sjkim sm->eap_sim_db_priv, sm->identity, 425151937Sjkim sm->identity_len); 426151937Sjkim if (data->reauth) { 427151937Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast " 428151937Sjkim "re-authentication"); 429233250Sjkim identity = data->reauth->identity; 430118611Snjl identity_len = data->reauth->identity_len; 431118611Snjl data->counter = data->reauth->counter; 432237412Sjkim os_memcpy(data->mk, data->reauth->mk, 433118611Snjl EAP_SIM_MK_LEN); 434220663Sjkim } 435233250Sjkim } 436118611Snjl } 437118611Snjl 438118611Snjl if (identity == NULL) { 439118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent" 440118611Snjl " user name"); 441118611Snjl eap_sim_state(data, FAILURE); 442118611Snjl return; 443197104Sjkim } 444118611Snjl 445118611Snjl wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", 446118611Snjl identity, identity_len); 447118611Snjl 448118611Snjl if (data->reauth) { 449118611Snjl eap_sim_state(data, REAUTH); 450118611Snjl return; 451118611Snjl } 452118611Snjl 453207344Sjkim if (attr->nonce_mt == NULL || attr->selected_version < 0) { 454207344Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing " 455207344Sjkim "required attributes"); 456207344Sjkim eap_sim_state(data, FAILURE); 457207344Sjkim return; 458118611Snjl } 459207344Sjkim 460207344Sjkim if (!eap_sim_supported_ver(data, attr->selected_version)) { 461207344Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported " 462207344Sjkim "version %d", attr->selected_version); 463118611Snjl eap_sim_state(data, FAILURE); 464118611Snjl return; 465118611Snjl } 466233250Sjkim 467118611Snjl data->counter = 0; /* reset re-auth counter since this is full auth */ 468118611Snjl data->reauth = NULL; 469118611Snjl 470193529Sjkim data->num_chal = eap_sim_db_get_gsm_triplets( 471118611Snjl sm->eap_sim_db_priv, identity, identity_len, 472118611Snjl EAP_SIM_MAX_CHAL, 473210976Sjkim (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm); 474210976Sjkim if (data->num_chal == EAP_SIM_DB_PENDING) { 475210976Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets " 476210976Sjkim "not yet available - pending request"); 477210976Sjkim sm->method_pending = METHOD_PENDING_WAIT; 478118611Snjl return; 479118611Snjl } 480118611Snjl if (data->num_chal < 2) { 481118611Snjl wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM " 482118611Snjl "authentication triplets for the peer"); 483197104Sjkim eap_sim_state(data, FAILURE); 484118611Snjl return; 485118611Snjl } 486118611Snjl 487118611Snjl identity_len = sm->identity_len; 488118611Snjl while (identity_len > 0 && sm->identity[identity_len - 1] == '\0') { 489118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Workaround - drop last null " 490233250Sjkim "character from identity"); 491233250Sjkim identity_len--; 492233250Sjkim } 493233250Sjkim wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation", 494233250Sjkim sm->identity, identity_len); 495233250Sjkim 496212761Sjkim os_memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN); 497212761Sjkim WPA_PUT_BE16(ver_list, EAP_SIM_VERSION); 498212761Sjkim eap_sim_derive_mk(sm->identity, identity_len, attr->nonce_mt, 499212761Sjkim attr->selected_version, ver_list, sizeof(ver_list), 500212761Sjkim data->num_chal, (const u8 *) data->kc, data->mk); 501212761Sjkim eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk, 502118611Snjl data->emsk); 503118611Snjl 504118611Snjl eap_sim_state(data, CHALLENGE); 505233250Sjkim} 506233250Sjkim 507233250Sjkim 508118611Snjlstatic void eap_sim_process_challenge(struct eap_sm *sm, 509118611Snjl struct eap_sim_data *data, 510233250Sjkim struct wpabuf *respData, 511233250Sjkim struct eap_sim_attrs *attr) 512118611Snjl{ 513118611Snjl const u8 *identity; 514118611Snjl size_t identity_len; 515233250Sjkim 516118611Snjl if (attr->mac == NULL || 517118611Snjl eap_sim_verify_mac(data->k_aut, respData, attr->mac, 518193529Sjkim (u8 *) data->sres, 519118611Snjl data->num_chal * EAP_SIM_SRES_LEN)) { 520118611Snjl wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message " 521118611Snjl "did not include valid AT_MAC"); 522118611Snjl eap_sim_state(data, FAILURE); 523118611Snjl return; 524118611Snjl } 525118611Snjl 526237412Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the " 527118611Snjl "correct AT_MAC"); 528118611Snjl if (sm->eap_sim_aka_result_ind && attr->result_ind) { 529118611Snjl data->use_result_ind = 1; 530118611Snjl data->notification = EAP_SIM_SUCCESS; 531118611Snjl eap_sim_state(data, NOTIFICATION); 532118611Snjl } else 533237412Sjkim eap_sim_state(data, SUCCESS); 534237412Sjkim 535237412Sjkim identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity, 536237412Sjkim sm->identity_len, &identity_len); 537118611Snjl if (identity == NULL) { 538118611Snjl identity = sm->identity; 539118611Snjl identity_len = sm->identity_len; 540204773Sjkim } 541118611Snjl 542118611Snjl if (data->next_pseudonym) { 543209746Sjkim eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 544209746Sjkim identity_len, 545209746Sjkim data->next_pseudonym); 546209746Sjkim data->next_pseudonym = NULL; 547118611Snjl } 548118611Snjl if (data->next_reauth_id) { 549197104Sjkim eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 550118611Snjl identity_len, 551118611Snjl data->next_reauth_id, data->counter + 1, 552118611Snjl data->mk); 553233250Sjkim data->next_reauth_id = NULL; 554197104Sjkim } 555197104Sjkim} 556197104Sjkim 557197104Sjkim 558233250Sjkimstatic void eap_sim_process_reauth(struct eap_sm *sm, 559118611Snjl struct eap_sim_data *data, 560118611Snjl struct wpabuf *respData, 561118611Snjl struct eap_sim_attrs *attr) 562118611Snjl{ 563118611Snjl struct eap_sim_attrs eattr; 564118611Snjl u8 *decrypted = NULL; 565118611Snjl const u8 *identity, *id2; 566118611Snjl size_t identity_len, id2_len; 567118611Snjl 568118611Snjl if (attr->mac == NULL || 569118611Snjl eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s, 570118611Snjl EAP_SIM_NONCE_S_LEN)) { 571118611Snjl wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 572118611Snjl "did not include valid AT_MAC"); 573118611Snjl goto fail; 574118611Snjl } 575118611Snjl 576233250Sjkim if (attr->encr_data == NULL || attr->iv == NULL) { 577197104Sjkim wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication " 578118611Snjl "message did not include encrypted data"); 579118611Snjl goto fail; 580118611Snjl } 581118611Snjl 582233250Sjkim decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data, 583118611Snjl attr->encr_data_len, attr->iv, &eattr, 584118611Snjl 0); 585118611Snjl if (decrypted == NULL) { 586118611Snjl wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted " 587118611Snjl "data from reauthentication message"); 588118611Snjl goto fail; 589118611Snjl } 590118611Snjl 591233250Sjkim if (eattr.counter != data->counter) { 592233250Sjkim wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message " 593233250Sjkim "used incorrect counter %u, expected %u", 594233250Sjkim eattr.counter, data->counter); 595233250Sjkim goto fail; 596233250Sjkim } 597118611Snjl os_free(decrypted); 598118611Snjl decrypted = NULL; 599118611Snjl 600118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes " 601118611Snjl "the correct AT_MAC"); 602118611Snjl if (sm->eap_sim_aka_result_ind && attr->result_ind) { 603118611Snjl data->use_result_ind = 1; 604118611Snjl data->notification = EAP_SIM_SUCCESS; 605118611Snjl eap_sim_state(data, NOTIFICATION); 606118611Snjl } else 607118611Snjl eap_sim_state(data, SUCCESS); 608118611Snjl 609118611Snjl if (data->reauth) { 610118611Snjl identity = data->reauth->identity; 611197104Sjkim identity_len = data->reauth->identity_len; 612118611Snjl } else { 613118611Snjl identity = sm->identity; 614118611Snjl identity_len = sm->identity_len; 615118611Snjl } 616233250Sjkim 617228110Sjkim id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity, 618228110Sjkim identity_len, &id2_len); 619228110Sjkim if (id2) { 620228110Sjkim identity = id2; 621233250Sjkim identity_len = id2_len; 622228110Sjkim } 623228110Sjkim 624228110Sjkim if (data->next_pseudonym) { 625228110Sjkim eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity, 626233250Sjkim identity_len, data->next_pseudonym); 627118611Snjl data->next_pseudonym = NULL; 628118611Snjl } 629118611Snjl if (data->next_reauth_id) { 630118611Snjl eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity, 631118611Snjl identity_len, data->next_reauth_id, 632118611Snjl data->counter + 1, data->mk); 633118611Snjl data->next_reauth_id = NULL; 634118611Snjl } else { 635118611Snjl eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 636118611Snjl data->reauth = NULL; 637118611Snjl } 638118611Snjl 639118611Snjl return; 640118611Snjl 641118611Snjlfail: 642118611Snjl eap_sim_state(data, FAILURE); 643118611Snjl eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth); 644118611Snjl data->reauth = NULL; 645118611Snjl os_free(decrypted); 646118611Snjl} 647118611Snjl 648118611Snjl 649118611Snjlstatic void eap_sim_process_client_error(struct eap_sm *sm, 650118611Snjl struct eap_sim_data *data, 651118611Snjl struct wpabuf *respData, 652118611Snjl struct eap_sim_attrs *attr) 653118611Snjl{ 654118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Client reported error %d", 655118611Snjl attr->client_error_code); 656118611Snjl if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 657118611Snjl eap_sim_state(data, SUCCESS); 658118611Snjl else 659118611Snjl eap_sim_state(data, FAILURE); 660118611Snjl} 661118611Snjl 662118611Snjl 663118611Snjlstatic void eap_sim_process_notification(struct eap_sm *sm, 664118611Snjl struct eap_sim_data *data, 665118611Snjl struct wpabuf *respData, 666118611Snjl struct eap_sim_attrs *attr) 667118611Snjl{ 668197104Sjkim wpa_printf(MSG_DEBUG, "EAP-SIM: Client replied to notification"); 669118611Snjl if (data->notification == EAP_SIM_SUCCESS && data->use_result_ind) 670118611Snjl eap_sim_state(data, SUCCESS); 671118611Snjl else 672118611Snjl eap_sim_state(data, FAILURE); 673234623Sjkim} 674234623Sjkim 675234623Sjkim 676234623Sjkimstatic void eap_sim_process(struct eap_sm *sm, void *priv, 677234623Sjkim struct wpabuf *respData) 678234623Sjkim{ 679234623Sjkim struct eap_sim_data *data = priv; 680234623Sjkim const u8 *pos, *end; 681234623Sjkim u8 subtype; 682234623Sjkim size_t len; 683234623Sjkim struct eap_sim_attrs attr; 684234623Sjkim 685234623Sjkim pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len); 686234623Sjkim if (pos == NULL || len < 3) 687234623Sjkim return; 688234623Sjkim 689233250Sjkim end = pos + len; 690118611Snjl subtype = *pos; 691118611Snjl pos += 3; 692233250Sjkim 693118611Snjl if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) { 694118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes"); 695118611Snjl eap_sim_state(data, FAILURE); 696118611Snjl return; 697118611Snjl } 698233250Sjkim 699138287Smarks if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR) { 700118611Snjl eap_sim_process_client_error(sm, data, respData, &attr); 701118611Snjl return; 702118611Snjl } 703233250Sjkim 704118611Snjl switch (data->state) { 705118611Snjl case START: 706118611Snjl eap_sim_process_start(sm, data, respData, &attr); 707118611Snjl break; 708118611Snjl case CHALLENGE: 709118611Snjl eap_sim_process_challenge(sm, data, respData, &attr); 710118611Snjl break; 711118611Snjl case REAUTH: 712118611Snjl eap_sim_process_reauth(sm, data, respData, &attr); 713118611Snjl break; 714118611Snjl case NOTIFICATION: 715118611Snjl eap_sim_process_notification(sm, data, respData, &attr); 716118611Snjl break; 717118611Snjl default: 718118611Snjl wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in " 719118611Snjl "process", data->state); 720118611Snjl break; 721118611Snjl } 722197104Sjkim} 723118611Snjl 724118611Snjl 725118611Snjlstatic Boolean eap_sim_isDone(struct eap_sm *sm, void *priv) 726118611Snjl{ 727233250Sjkim struct eap_sim_data *data = priv; 728118611Snjl return data->state == SUCCESS || data->state == FAILURE; 729118611Snjl} 730118611Snjl 731118611Snjl 732118611Snjlstatic u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len) 733118611Snjl{ 734118611Snjl struct eap_sim_data *data = priv; 735118611Snjl u8 *key; 736118611Snjl 737118611Snjl if (data->state != SUCCESS) 738207344Sjkim return NULL; 739207344Sjkim 740207344Sjkim key = os_malloc(EAP_SIM_KEYING_DATA_LEN); 741207344Sjkim if (key == NULL) 742118611Snjl return NULL; 743118611Snjl os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN); 744197104Sjkim *len = EAP_SIM_KEYING_DATA_LEN; 745118611Snjl return key; 746118611Snjl} 747118611Snjl 748118611Snjl 749233250Sjkimstatic u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 750209746Sjkim{ 751209746Sjkim struct eap_sim_data *data = priv; 752209746Sjkim u8 *key; 753209746Sjkim 754209746Sjkim if (data->state != SUCCESS) 755238381Sjkim return NULL; 756118611Snjl 757118611Snjl key = os_malloc(EAP_EMSK_LEN); 758238381Sjkim if (key == NULL) 759238381Sjkim return NULL; 760238381Sjkim os_memcpy(key, data->emsk, EAP_EMSK_LEN); 761238381Sjkim *len = EAP_EMSK_LEN; 762193529Sjkim return key; 763193529Sjkim} 764193529Sjkim 765193529Sjkim 766193529Sjkimstatic Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv) 767193529Sjkim{ 768118611Snjl struct eap_sim_data *data = priv; 769235945Sjkim return data->state == SUCCESS; 770235945Sjkim} 771235945Sjkim 772235945Sjkim 773235945Sjkimint eap_server_sim_register(void) 774235945Sjkim{ 775235945Sjkim struct eap_method *eap; 776235945Sjkim int ret; 777235945Sjkim 778118611Snjl eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 779235945Sjkim EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM"); 780235945Sjkim if (eap == NULL) 781118611Snjl return -1; 782118611Snjl 783118611Snjl eap->init = eap_sim_init; 784118611Snjl eap->reset = eap_sim_reset; 785118611Snjl eap->buildReq = eap_sim_buildReq; 786118611Snjl eap->check = eap_sim_check; 787118611Snjl eap->process = eap_sim_process; 788118611Snjl eap->isDone = eap_sim_isDone; 789118611Snjl eap->getKey = eap_sim_getKey; 790118611Snjl eap->isSuccess = eap_sim_isSuccess; 791118611Snjl eap->get_emsk = eap_sim_get_emsk; 792193529Sjkim 793118611Snjl ret = eap_server_method_register(eap); 794118611Snjl if (ret) 795209746Sjkim eap_server_method_free(eap); 796209746Sjkim return ret; 797209746Sjkim} 798209746Sjkim