1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * EAP-FAST server (RFC 4851) 3e28a4053SRui Paulo * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "common.h" 12e28a4053SRui Paulo #include "crypto/aes_wrap.h" 13e28a4053SRui Paulo #include "crypto/sha1.h" 14e28a4053SRui Paulo #include "crypto/tls.h" 15f05cddf9SRui Paulo #include "crypto/random.h" 16e28a4053SRui Paulo #include "eap_common/eap_tlv_common.h" 17e28a4053SRui Paulo #include "eap_common/eap_fast_common.h" 18e28a4053SRui Paulo #include "eap_i.h" 19e28a4053SRui Paulo #include "eap_tls_common.h" 20e28a4053SRui Paulo 21e28a4053SRui Paulo 22e28a4053SRui Paulo static void eap_fast_reset(struct eap_sm *sm, void *priv); 23e28a4053SRui Paulo 24e28a4053SRui Paulo 25e28a4053SRui Paulo /* Private PAC-Opaque TLV types */ 26e28a4053SRui Paulo #define PAC_OPAQUE_TYPE_PAD 0 27e28a4053SRui Paulo #define PAC_OPAQUE_TYPE_KEY 1 28e28a4053SRui Paulo #define PAC_OPAQUE_TYPE_LIFETIME 2 29e28a4053SRui Paulo #define PAC_OPAQUE_TYPE_IDENTITY 3 30e28a4053SRui Paulo 31e28a4053SRui Paulo struct eap_fast_data { 32e28a4053SRui Paulo struct eap_ssl_data ssl; 33e28a4053SRui Paulo enum { 34e28a4053SRui Paulo START, PHASE1, PHASE2_START, PHASE2_ID, PHASE2_METHOD, 35e28a4053SRui Paulo CRYPTO_BINDING, REQUEST_PAC, SUCCESS, FAILURE 36e28a4053SRui Paulo } state; 37e28a4053SRui Paulo 38e28a4053SRui Paulo int fast_version; 39e28a4053SRui Paulo const struct eap_method *phase2_method; 40e28a4053SRui Paulo void *phase2_priv; 41e28a4053SRui Paulo int force_version; 42e28a4053SRui Paulo int peer_version; 43e28a4053SRui Paulo 44e28a4053SRui Paulo u8 crypto_binding_nonce[32]; 45e28a4053SRui Paulo int final_result; 46e28a4053SRui Paulo 47e28a4053SRui Paulo struct eap_fast_key_block_provisioning *key_block_p; 48e28a4053SRui Paulo 49e28a4053SRui Paulo u8 simck[EAP_FAST_SIMCK_LEN]; 50e28a4053SRui Paulo u8 cmk[EAP_FAST_CMK_LEN]; 51e28a4053SRui Paulo int simck_idx; 52e28a4053SRui Paulo 53e28a4053SRui Paulo u8 pac_opaque_encr[16]; 54e28a4053SRui Paulo u8 *srv_id; 55e28a4053SRui Paulo size_t srv_id_len; 56e28a4053SRui Paulo char *srv_id_info; 57e28a4053SRui Paulo 58e28a4053SRui Paulo int anon_provisioning; 59e28a4053SRui Paulo int send_new_pac; /* server triggered re-keying of Tunnel PAC */ 60e28a4053SRui Paulo struct wpabuf *pending_phase2_resp; 61e28a4053SRui Paulo u8 *identity; /* from PAC-Opaque */ 62e28a4053SRui Paulo size_t identity_len; 63e28a4053SRui Paulo int eap_seq; 64e28a4053SRui Paulo int tnc_started; 65e28a4053SRui Paulo 66e28a4053SRui Paulo int pac_key_lifetime; 67e28a4053SRui Paulo int pac_key_refresh_time; 68e28a4053SRui Paulo }; 69e28a4053SRui Paulo 70e28a4053SRui Paulo 71e28a4053SRui Paulo static int eap_fast_process_phase2_start(struct eap_sm *sm, 72e28a4053SRui Paulo struct eap_fast_data *data); 73e28a4053SRui Paulo 74e28a4053SRui Paulo 75e28a4053SRui Paulo static const char * eap_fast_state_txt(int state) 76e28a4053SRui Paulo { 77e28a4053SRui Paulo switch (state) { 78e28a4053SRui Paulo case START: 79e28a4053SRui Paulo return "START"; 80e28a4053SRui Paulo case PHASE1: 81e28a4053SRui Paulo return "PHASE1"; 82e28a4053SRui Paulo case PHASE2_START: 83e28a4053SRui Paulo return "PHASE2_START"; 84e28a4053SRui Paulo case PHASE2_ID: 85e28a4053SRui Paulo return "PHASE2_ID"; 86e28a4053SRui Paulo case PHASE2_METHOD: 87e28a4053SRui Paulo return "PHASE2_METHOD"; 88e28a4053SRui Paulo case CRYPTO_BINDING: 89e28a4053SRui Paulo return "CRYPTO_BINDING"; 90e28a4053SRui Paulo case REQUEST_PAC: 91e28a4053SRui Paulo return "REQUEST_PAC"; 92e28a4053SRui Paulo case SUCCESS: 93e28a4053SRui Paulo return "SUCCESS"; 94e28a4053SRui Paulo case FAILURE: 95e28a4053SRui Paulo return "FAILURE"; 96e28a4053SRui Paulo default: 97e28a4053SRui Paulo return "Unknown?!"; 98e28a4053SRui Paulo } 99e28a4053SRui Paulo } 100e28a4053SRui Paulo 101e28a4053SRui Paulo 102e28a4053SRui Paulo static void eap_fast_state(struct eap_fast_data *data, int state) 103e28a4053SRui Paulo { 104e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: %s -> %s", 105e28a4053SRui Paulo eap_fast_state_txt(data->state), 106e28a4053SRui Paulo eap_fast_state_txt(state)); 107e28a4053SRui Paulo data->state = state; 108e28a4053SRui Paulo } 109e28a4053SRui Paulo 110e28a4053SRui Paulo 111c1d255d3SCy Schubert static enum eap_type eap_fast_req_failure(struct eap_sm *sm, 112e28a4053SRui Paulo struct eap_fast_data *data) 113e28a4053SRui Paulo { 114e28a4053SRui Paulo /* TODO: send Result TLV(FAILURE) */ 115e28a4053SRui Paulo eap_fast_state(data, FAILURE); 116e28a4053SRui Paulo return EAP_TYPE_NONE; 117e28a4053SRui Paulo } 118e28a4053SRui Paulo 119e28a4053SRui Paulo 120e28a4053SRui Paulo static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, 121e28a4053SRui Paulo const u8 *client_random, 122e28a4053SRui Paulo const u8 *server_random, 123e28a4053SRui Paulo u8 *master_secret) 124e28a4053SRui Paulo { 125e28a4053SRui Paulo struct eap_fast_data *data = ctx; 126e28a4053SRui Paulo const u8 *pac_opaque; 127e28a4053SRui Paulo size_t pac_opaque_len; 128e28a4053SRui Paulo u8 *buf, *pos, *end, *pac_key = NULL; 129e28a4053SRui Paulo os_time_t lifetime = 0; 130e28a4053SRui Paulo struct os_time now; 131e28a4053SRui Paulo u8 *identity = NULL; 132e28a4053SRui Paulo size_t identity_len = 0; 133e28a4053SRui Paulo 134e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback"); 135e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)", 136e28a4053SRui Paulo ticket, len); 137e28a4053SRui Paulo 138e28a4053SRui Paulo if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) { 139e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid " 140e28a4053SRui Paulo "SessionTicket"); 141e28a4053SRui Paulo return 0; 142e28a4053SRui Paulo } 143e28a4053SRui Paulo 144e28a4053SRui Paulo pac_opaque_len = WPA_GET_BE16(ticket + 2); 145e28a4053SRui Paulo pac_opaque = ticket + 4; 146e28a4053SRui Paulo if (pac_opaque_len < 8 || pac_opaque_len % 8 || 147e28a4053SRui Paulo pac_opaque_len > len - 4) { 148e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid PAC-Opaque " 149e28a4053SRui Paulo "(len=%lu left=%lu)", 150e28a4053SRui Paulo (unsigned long) pac_opaque_len, 151e28a4053SRui Paulo (unsigned long) len); 152e28a4053SRui Paulo return 0; 153e28a4053SRui Paulo } 154e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-FAST: Received PAC-Opaque", 155e28a4053SRui Paulo pac_opaque, pac_opaque_len); 156e28a4053SRui Paulo 157e28a4053SRui Paulo buf = os_malloc(pac_opaque_len - 8); 158e28a4053SRui Paulo if (buf == NULL) { 159e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory " 160e28a4053SRui Paulo "for decrypting PAC-Opaque"); 161e28a4053SRui Paulo return 0; 162e28a4053SRui Paulo } 163e28a4053SRui Paulo 1645b9c547cSRui Paulo if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), 1655b9c547cSRui Paulo (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) { 166e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt " 167e28a4053SRui Paulo "PAC-Opaque"); 168e28a4053SRui Paulo os_free(buf); 169e28a4053SRui Paulo /* 170e28a4053SRui Paulo * This may have been caused by server changing the PAC-Opaque 171e28a4053SRui Paulo * encryption key, so just ignore this PAC-Opaque instead of 172e28a4053SRui Paulo * failing the authentication completely. Provisioning can now 173e28a4053SRui Paulo * be used to provision a new PAC. 174e28a4053SRui Paulo */ 175e28a4053SRui Paulo return 0; 176e28a4053SRui Paulo } 177e28a4053SRui Paulo 178e28a4053SRui Paulo end = buf + pac_opaque_len - 8; 179e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Decrypted PAC-Opaque", 180e28a4053SRui Paulo buf, end - buf); 181e28a4053SRui Paulo 182e28a4053SRui Paulo pos = buf; 183780fb4a2SCy Schubert while (end - pos > 1) { 184780fb4a2SCy Schubert u8 id, elen; 185780fb4a2SCy Schubert 186780fb4a2SCy Schubert id = *pos++; 187780fb4a2SCy Schubert elen = *pos++; 188780fb4a2SCy Schubert if (elen > end - pos) 189e28a4053SRui Paulo break; 190e28a4053SRui Paulo 191780fb4a2SCy Schubert switch (id) { 192e28a4053SRui Paulo case PAC_OPAQUE_TYPE_PAD: 1935b9c547cSRui Paulo goto done; 194e28a4053SRui Paulo case PAC_OPAQUE_TYPE_KEY: 195780fb4a2SCy Schubert if (elen != EAP_FAST_PAC_KEY_LEN) { 196780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 197780fb4a2SCy Schubert "EAP-FAST: Invalid PAC-Key length %d", 198780fb4a2SCy Schubert elen); 199e28a4053SRui Paulo os_free(buf); 200e28a4053SRui Paulo return -1; 201e28a4053SRui Paulo } 202780fb4a2SCy Schubert pac_key = pos; 203e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: PAC-Key from " 204e28a4053SRui Paulo "decrypted PAC-Opaque", 205e28a4053SRui Paulo pac_key, EAP_FAST_PAC_KEY_LEN); 206e28a4053SRui Paulo break; 207e28a4053SRui Paulo case PAC_OPAQUE_TYPE_LIFETIME: 208780fb4a2SCy Schubert if (elen != 4) { 209e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " 210e28a4053SRui Paulo "PAC-Key lifetime length %d", 211780fb4a2SCy Schubert elen); 212e28a4053SRui Paulo os_free(buf); 213e28a4053SRui Paulo return -1; 214e28a4053SRui Paulo } 215780fb4a2SCy Schubert lifetime = WPA_GET_BE32(pos); 216e28a4053SRui Paulo break; 217e28a4053SRui Paulo case PAC_OPAQUE_TYPE_IDENTITY: 218780fb4a2SCy Schubert identity = pos; 219780fb4a2SCy Schubert identity_len = elen; 220e28a4053SRui Paulo break; 221e28a4053SRui Paulo } 222e28a4053SRui Paulo 223780fb4a2SCy Schubert pos += elen; 224e28a4053SRui Paulo } 2255b9c547cSRui Paulo done: 226e28a4053SRui Paulo 227e28a4053SRui Paulo if (pac_key == NULL) { 228e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in " 229e28a4053SRui Paulo "PAC-Opaque"); 230e28a4053SRui Paulo os_free(buf); 231e28a4053SRui Paulo return -1; 232e28a4053SRui Paulo } 233e28a4053SRui Paulo 234e28a4053SRui Paulo if (identity) { 235e28a4053SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from " 236e28a4053SRui Paulo "PAC-Opaque", identity, identity_len); 237e28a4053SRui Paulo os_free(data->identity); 238e28a4053SRui Paulo data->identity = os_malloc(identity_len); 239e28a4053SRui Paulo if (data->identity) { 240e28a4053SRui Paulo os_memcpy(data->identity, identity, identity_len); 241e28a4053SRui Paulo data->identity_len = identity_len; 242e28a4053SRui Paulo } 243e28a4053SRui Paulo } 244e28a4053SRui Paulo 245e28a4053SRui Paulo if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) { 246e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore " 247e28a4053SRui Paulo "(lifetime=%ld now=%ld)", lifetime, now.sec); 248e28a4053SRui Paulo data->send_new_pac = 2; 249e28a4053SRui Paulo /* 250e28a4053SRui Paulo * Allow PAC to be used to allow a PAC update with some level 251e28a4053SRui Paulo * of server authentication (i.e., do not fall back to full TLS 252e28a4053SRui Paulo * handshake since we cannot be sure that the peer would be 253e28a4053SRui Paulo * able to validate server certificate now). However, reject 254e28a4053SRui Paulo * the authentication since the PAC was not valid anymore. Peer 255e28a4053SRui Paulo * can connect again with the newly provisioned PAC after this. 256e28a4053SRui Paulo */ 257e28a4053SRui Paulo } else if (lifetime - now.sec < data->pac_key_refresh_time) { 258e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key soft timeout; send " 259e28a4053SRui Paulo "an update if authentication succeeds"); 260e28a4053SRui Paulo data->send_new_pac = 1; 261e28a4053SRui Paulo } 262e28a4053SRui Paulo 263e28a4053SRui Paulo eap_fast_derive_master_secret(pac_key, server_random, client_random, 264e28a4053SRui Paulo master_secret); 265e28a4053SRui Paulo 266e28a4053SRui Paulo os_free(buf); 267e28a4053SRui Paulo 268e28a4053SRui Paulo return 1; 269e28a4053SRui Paulo } 270e28a4053SRui Paulo 271e28a4053SRui Paulo 272e28a4053SRui Paulo static void eap_fast_derive_key_auth(struct eap_sm *sm, 273e28a4053SRui Paulo struct eap_fast_data *data) 274e28a4053SRui Paulo { 275e28a4053SRui Paulo u8 *sks; 276e28a4053SRui Paulo 277e28a4053SRui Paulo /* RFC 4851, Section 5.1: 278e28a4053SRui Paulo * Extra key material after TLS key_block: session_key_seed[40] 279e28a4053SRui Paulo */ 280e28a4053SRui Paulo 281c1d255d3SCy Schubert sks = eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn, 282e28a4053SRui Paulo EAP_FAST_SKS_LEN); 283e28a4053SRui Paulo if (sks == NULL) { 284e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive " 285e28a4053SRui Paulo "session_key_seed"); 286e28a4053SRui Paulo return; 287e28a4053SRui Paulo } 288e28a4053SRui Paulo 289e28a4053SRui Paulo /* 290e28a4053SRui Paulo * RFC 4851, Section 5.2: 291e28a4053SRui Paulo * S-IMCK[0] = session_key_seed 292e28a4053SRui Paulo */ 293e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, 294e28a4053SRui Paulo "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", 295e28a4053SRui Paulo sks, EAP_FAST_SKS_LEN); 296e28a4053SRui Paulo data->simck_idx = 0; 297e28a4053SRui Paulo os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN); 298e28a4053SRui Paulo os_free(sks); 299e28a4053SRui Paulo } 300e28a4053SRui Paulo 301e28a4053SRui Paulo 302e28a4053SRui Paulo static void eap_fast_derive_key_provisioning(struct eap_sm *sm, 303e28a4053SRui Paulo struct eap_fast_data *data) 304e28a4053SRui Paulo { 305e28a4053SRui Paulo os_free(data->key_block_p); 306e28a4053SRui Paulo data->key_block_p = (struct eap_fast_key_block_provisioning *) 307c1d255d3SCy Schubert eap_fast_derive_key(sm->cfg->ssl_ctx, data->ssl.conn, 308e28a4053SRui Paulo sizeof(*data->key_block_p)); 309e28a4053SRui Paulo if (data->key_block_p == NULL) { 310e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block"); 311e28a4053SRui Paulo return; 312e28a4053SRui Paulo } 313e28a4053SRui Paulo /* 314e28a4053SRui Paulo * RFC 4851, Section 5.2: 315e28a4053SRui Paulo * S-IMCK[0] = session_key_seed 316e28a4053SRui Paulo */ 317e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, 318e28a4053SRui Paulo "EAP-FAST: session_key_seed (SKS = S-IMCK[0])", 319e28a4053SRui Paulo data->key_block_p->session_key_seed, 320e28a4053SRui Paulo sizeof(data->key_block_p->session_key_seed)); 321e28a4053SRui Paulo data->simck_idx = 0; 322e28a4053SRui Paulo os_memcpy(data->simck, data->key_block_p->session_key_seed, 323e28a4053SRui Paulo EAP_FAST_SIMCK_LEN); 324e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge", 325e28a4053SRui Paulo data->key_block_p->server_challenge, 326e28a4053SRui Paulo sizeof(data->key_block_p->server_challenge)); 327e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge", 328e28a4053SRui Paulo data->key_block_p->client_challenge, 329e28a4053SRui Paulo sizeof(data->key_block_p->client_challenge)); 330e28a4053SRui Paulo } 331e28a4053SRui Paulo 332e28a4053SRui Paulo 333e28a4053SRui Paulo static int eap_fast_get_phase2_key(struct eap_sm *sm, 334e28a4053SRui Paulo struct eap_fast_data *data, 335e28a4053SRui Paulo u8 *isk, size_t isk_len) 336e28a4053SRui Paulo { 337e28a4053SRui Paulo u8 *key; 338e28a4053SRui Paulo size_t key_len; 339e28a4053SRui Paulo 340e28a4053SRui Paulo os_memset(isk, 0, isk_len); 341e28a4053SRui Paulo 342e28a4053SRui Paulo if (data->phase2_method == NULL || data->phase2_priv == NULL) { 343e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " 344e28a4053SRui Paulo "available"); 345e28a4053SRui Paulo return -1; 346e28a4053SRui Paulo } 347e28a4053SRui Paulo 348e28a4053SRui Paulo if (data->phase2_method->getKey == NULL) 349e28a4053SRui Paulo return 0; 350e28a4053SRui Paulo 351e28a4053SRui Paulo if ((key = data->phase2_method->getKey(sm, data->phase2_priv, 352e28a4053SRui Paulo &key_len)) == NULL) { 353e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Could not get key material " 354e28a4053SRui Paulo "from Phase 2"); 355e28a4053SRui Paulo return -1; 356e28a4053SRui Paulo } 357e28a4053SRui Paulo 358e28a4053SRui Paulo if (key_len > isk_len) 359e28a4053SRui Paulo key_len = isk_len; 360e28a4053SRui Paulo os_memcpy(isk, key, key_len); 361e28a4053SRui Paulo os_free(key); 362e28a4053SRui Paulo 363e28a4053SRui Paulo return 0; 364e28a4053SRui Paulo } 365e28a4053SRui Paulo 366e28a4053SRui Paulo 367e28a4053SRui Paulo static int eap_fast_update_icmk(struct eap_sm *sm, struct eap_fast_data *data) 368e28a4053SRui Paulo { 369e28a4053SRui Paulo u8 isk[32], imck[60]; 370e28a4053SRui Paulo 371e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Deriving ICMK[%d] (S-IMCK and CMK)", 372e28a4053SRui Paulo data->simck_idx + 1); 373e28a4053SRui Paulo 374e28a4053SRui Paulo /* 375e28a4053SRui Paulo * RFC 4851, Section 5.2: 376e28a4053SRui Paulo * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys", 377e28a4053SRui Paulo * MSK[j], 60) 378e28a4053SRui Paulo * S-IMCK[j] = first 40 octets of IMCK[j] 379e28a4053SRui Paulo * CMK[j] = last 20 octets of IMCK[j] 380e28a4053SRui Paulo */ 381e28a4053SRui Paulo 382e28a4053SRui Paulo if (eap_fast_get_phase2_key(sm, data, isk, sizeof(isk)) < 0) 383e28a4053SRui Paulo return -1; 384e28a4053SRui Paulo wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk)); 385e28a4053SRui Paulo sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN, 386e28a4053SRui Paulo "Inner Methods Compound Keys", 387e28a4053SRui Paulo isk, sizeof(isk), imck, sizeof(imck)); 388e28a4053SRui Paulo data->simck_idx++; 389e28a4053SRui Paulo os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN); 390e28a4053SRui Paulo wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]", 391e28a4053SRui Paulo data->simck, EAP_FAST_SIMCK_LEN); 392e28a4053SRui Paulo os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN); 393e28a4053SRui Paulo wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", 394e28a4053SRui Paulo data->cmk, EAP_FAST_CMK_LEN); 395e28a4053SRui Paulo 396e28a4053SRui Paulo return 0; 397e28a4053SRui Paulo } 398e28a4053SRui Paulo 399e28a4053SRui Paulo 400e28a4053SRui Paulo static void * eap_fast_init(struct eap_sm *sm) 401e28a4053SRui Paulo { 402e28a4053SRui Paulo struct eap_fast_data *data; 403780fb4a2SCy Schubert u8 ciphers[7] = { 404e28a4053SRui Paulo TLS_CIPHER_ANON_DH_AES128_SHA, 405e28a4053SRui Paulo TLS_CIPHER_AES128_SHA, 406e28a4053SRui Paulo TLS_CIPHER_RSA_DHE_AES128_SHA, 407e28a4053SRui Paulo TLS_CIPHER_RC4_SHA, 408780fb4a2SCy Schubert TLS_CIPHER_RSA_DHE_AES256_SHA, 409780fb4a2SCy Schubert TLS_CIPHER_AES256_SHA, 410e28a4053SRui Paulo TLS_CIPHER_NONE 411e28a4053SRui Paulo }; 412e28a4053SRui Paulo 413e28a4053SRui Paulo data = os_zalloc(sizeof(*data)); 414e28a4053SRui Paulo if (data == NULL) 415e28a4053SRui Paulo return NULL; 416e28a4053SRui Paulo data->fast_version = EAP_FAST_VERSION; 417e28a4053SRui Paulo data->force_version = -1; 418e28a4053SRui Paulo if (sm->user && sm->user->force_version >= 0) { 419e28a4053SRui Paulo data->force_version = sm->user->force_version; 420e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: forcing version %d", 421e28a4053SRui Paulo data->force_version); 422e28a4053SRui Paulo data->fast_version = data->force_version; 423e28a4053SRui Paulo } 424e28a4053SRui Paulo data->state = START; 425e28a4053SRui Paulo 426325151a3SRui Paulo if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_TYPE_FAST)) { 427e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL."); 428e28a4053SRui Paulo eap_fast_reset(sm, data); 429e28a4053SRui Paulo return NULL; 430e28a4053SRui Paulo } 431e28a4053SRui Paulo 432c1d255d3SCy Schubert if (tls_connection_set_cipher_list(sm->cfg->ssl_ctx, data->ssl.conn, 433e28a4053SRui Paulo ciphers) < 0) { 434e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Failed to set TLS cipher " 435e28a4053SRui Paulo "suites"); 436e28a4053SRui Paulo eap_fast_reset(sm, data); 437e28a4053SRui Paulo return NULL; 438e28a4053SRui Paulo } 439e28a4053SRui Paulo 440c1d255d3SCy Schubert if (tls_connection_set_session_ticket_cb(sm->cfg->ssl_ctx, 441c1d255d3SCy Schubert data->ssl.conn, 442e28a4053SRui Paulo eap_fast_session_ticket_cb, 443e28a4053SRui Paulo data) < 0) { 444e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket " 445e28a4053SRui Paulo "callback"); 446e28a4053SRui Paulo eap_fast_reset(sm, data); 447e28a4053SRui Paulo return NULL; 448e28a4053SRui Paulo } 449e28a4053SRui Paulo 450c1d255d3SCy Schubert if (sm->cfg->pac_opaque_encr_key == NULL) { 451e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: No PAC-Opaque encryption key " 452e28a4053SRui Paulo "configured"); 453e28a4053SRui Paulo eap_fast_reset(sm, data); 454e28a4053SRui Paulo return NULL; 455e28a4053SRui Paulo } 456c1d255d3SCy Schubert os_memcpy(data->pac_opaque_encr, sm->cfg->pac_opaque_encr_key, 457e28a4053SRui Paulo sizeof(data->pac_opaque_encr)); 458e28a4053SRui Paulo 459c1d255d3SCy Schubert if (sm->cfg->eap_fast_a_id == NULL) { 460e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: No A-ID configured"); 461e28a4053SRui Paulo eap_fast_reset(sm, data); 462e28a4053SRui Paulo return NULL; 463e28a4053SRui Paulo } 464c1d255d3SCy Schubert data->srv_id = os_memdup(sm->cfg->eap_fast_a_id, 465c1d255d3SCy Schubert sm->cfg->eap_fast_a_id_len); 466e28a4053SRui Paulo if (data->srv_id == NULL) { 467e28a4053SRui Paulo eap_fast_reset(sm, data); 468e28a4053SRui Paulo return NULL; 469e28a4053SRui Paulo } 470c1d255d3SCy Schubert data->srv_id_len = sm->cfg->eap_fast_a_id_len; 471e28a4053SRui Paulo 472c1d255d3SCy Schubert if (sm->cfg->eap_fast_a_id_info == NULL) { 473e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: No A-ID-Info configured"); 474e28a4053SRui Paulo eap_fast_reset(sm, data); 475e28a4053SRui Paulo return NULL; 476e28a4053SRui Paulo } 477c1d255d3SCy Schubert data->srv_id_info = os_strdup(sm->cfg->eap_fast_a_id_info); 478e28a4053SRui Paulo if (data->srv_id_info == NULL) { 479e28a4053SRui Paulo eap_fast_reset(sm, data); 480e28a4053SRui Paulo return NULL; 481e28a4053SRui Paulo } 482e28a4053SRui Paulo 483e28a4053SRui Paulo /* PAC-Key lifetime in seconds (hard limit) */ 484c1d255d3SCy Schubert data->pac_key_lifetime = sm->cfg->pac_key_lifetime; 485e28a4053SRui Paulo 486e28a4053SRui Paulo /* 487e28a4053SRui Paulo * PAC-Key refresh time in seconds (soft limit on remaining hard 488e28a4053SRui Paulo * limit). The server will generate a new PAC-Key when this number of 489e28a4053SRui Paulo * seconds (or fewer) of the lifetime remains. 490e28a4053SRui Paulo */ 491c1d255d3SCy Schubert data->pac_key_refresh_time = sm->cfg->pac_key_refresh_time; 492e28a4053SRui Paulo 493e28a4053SRui Paulo return data; 494e28a4053SRui Paulo } 495e28a4053SRui Paulo 496e28a4053SRui Paulo 497e28a4053SRui Paulo static void eap_fast_reset(struct eap_sm *sm, void *priv) 498e28a4053SRui Paulo { 499e28a4053SRui Paulo struct eap_fast_data *data = priv; 500e28a4053SRui Paulo if (data == NULL) 501e28a4053SRui Paulo return; 502e28a4053SRui Paulo if (data->phase2_priv && data->phase2_method) 503e28a4053SRui Paulo data->phase2_method->reset(sm, data->phase2_priv); 504e28a4053SRui Paulo eap_server_tls_ssl_deinit(sm, &data->ssl); 505e28a4053SRui Paulo os_free(data->srv_id); 506e28a4053SRui Paulo os_free(data->srv_id_info); 507e28a4053SRui Paulo os_free(data->key_block_p); 508e28a4053SRui Paulo wpabuf_free(data->pending_phase2_resp); 509e28a4053SRui Paulo os_free(data->identity); 5105b9c547cSRui Paulo bin_clear_free(data, sizeof(*data)); 511e28a4053SRui Paulo } 512e28a4053SRui Paulo 513e28a4053SRui Paulo 514e28a4053SRui Paulo static struct wpabuf * eap_fast_build_start(struct eap_sm *sm, 515e28a4053SRui Paulo struct eap_fast_data *data, u8 id) 516e28a4053SRui Paulo { 517e28a4053SRui Paulo struct wpabuf *req; 518e28a4053SRui Paulo 519e28a4053SRui Paulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST, 520e28a4053SRui Paulo 1 + sizeof(struct pac_tlv_hdr) + data->srv_id_len, 521e28a4053SRui Paulo EAP_CODE_REQUEST, id); 522e28a4053SRui Paulo if (req == NULL) { 523e28a4053SRui Paulo wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for" 524e28a4053SRui Paulo " request"); 525e28a4053SRui Paulo eap_fast_state(data, FAILURE); 526e28a4053SRui Paulo return NULL; 527e28a4053SRui Paulo } 528e28a4053SRui Paulo 529e28a4053SRui Paulo wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version); 530e28a4053SRui Paulo 531e28a4053SRui Paulo /* RFC 4851, 4.1.1. Authority ID Data */ 532e28a4053SRui Paulo eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); 533e28a4053SRui Paulo 534e28a4053SRui Paulo eap_fast_state(data, PHASE1); 535e28a4053SRui Paulo 536e28a4053SRui Paulo return req; 537e28a4053SRui Paulo } 538e28a4053SRui Paulo 539e28a4053SRui Paulo 540e28a4053SRui Paulo static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data) 541e28a4053SRui Paulo { 542e28a4053SRui Paulo char cipher[64]; 543e28a4053SRui Paulo 544e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase1 done, starting Phase2"); 545e28a4053SRui Paulo 546c1d255d3SCy Schubert if (tls_get_cipher(sm->cfg->ssl_ctx, data->ssl.conn, 547c1d255d3SCy Schubert cipher, sizeof(cipher)) < 0) { 548e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to get cipher " 549e28a4053SRui Paulo "information"); 550e28a4053SRui Paulo eap_fast_state(data, FAILURE); 551e28a4053SRui Paulo return -1; 552e28a4053SRui Paulo } 553e28a4053SRui Paulo data->anon_provisioning = os_strstr(cipher, "ADH") != NULL; 554e28a4053SRui Paulo 555e28a4053SRui Paulo if (data->anon_provisioning) { 556e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Anonymous provisioning"); 557e28a4053SRui Paulo eap_fast_derive_key_provisioning(sm, data); 558e28a4053SRui Paulo } else 559e28a4053SRui Paulo eap_fast_derive_key_auth(sm, data); 560e28a4053SRui Paulo 561e28a4053SRui Paulo eap_fast_state(data, PHASE2_START); 562e28a4053SRui Paulo 563e28a4053SRui Paulo return 0; 564e28a4053SRui Paulo } 565e28a4053SRui Paulo 566e28a4053SRui Paulo 567e28a4053SRui Paulo static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm, 568e28a4053SRui Paulo struct eap_fast_data *data, 569e28a4053SRui Paulo u8 id) 570e28a4053SRui Paulo { 571e28a4053SRui Paulo struct wpabuf *req; 572e28a4053SRui Paulo 573e28a4053SRui Paulo if (data->phase2_priv == NULL) { 574e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not " 575e28a4053SRui Paulo "initialized"); 576e28a4053SRui Paulo return NULL; 577e28a4053SRui Paulo } 578e28a4053SRui Paulo req = data->phase2_method->buildReq(sm, data->phase2_priv, id); 579e28a4053SRui Paulo if (req == NULL) 580e28a4053SRui Paulo return NULL; 581e28a4053SRui Paulo 582e28a4053SRui Paulo wpa_hexdump_buf_key(MSG_MSGDUMP, "EAP-FAST: Phase 2 EAP-Request", req); 583e28a4053SRui Paulo return eap_fast_tlv_eap_payload(req); 584e28a4053SRui Paulo } 585e28a4053SRui Paulo 586e28a4053SRui Paulo 587e28a4053SRui Paulo static struct wpabuf * eap_fast_build_crypto_binding( 588e28a4053SRui Paulo struct eap_sm *sm, struct eap_fast_data *data) 589e28a4053SRui Paulo { 590e28a4053SRui Paulo struct wpabuf *buf; 591e28a4053SRui Paulo struct eap_tlv_result_tlv *result; 592e28a4053SRui Paulo struct eap_tlv_crypto_binding_tlv *binding; 593e28a4053SRui Paulo 594e28a4053SRui Paulo buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding)); 595e28a4053SRui Paulo if (buf == NULL) 596e28a4053SRui Paulo return NULL; 597e28a4053SRui Paulo 598e28a4053SRui Paulo if (data->send_new_pac || data->anon_provisioning || 599e28a4053SRui Paulo data->phase2_method) 600e28a4053SRui Paulo data->final_result = 0; 601e28a4053SRui Paulo else 602e28a4053SRui Paulo data->final_result = 1; 603e28a4053SRui Paulo 604e28a4053SRui Paulo if (!data->final_result || data->eap_seq > 1) { 605e28a4053SRui Paulo /* Intermediate-Result */ 606e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV " 607e28a4053SRui Paulo "(status=SUCCESS)"); 608e28a4053SRui Paulo result = wpabuf_put(buf, sizeof(*result)); 609e28a4053SRui Paulo result->tlv_type = host_to_be16( 610e28a4053SRui Paulo EAP_TLV_TYPE_MANDATORY | 611e28a4053SRui Paulo EAP_TLV_INTERMEDIATE_RESULT_TLV); 612e28a4053SRui Paulo result->length = host_to_be16(2); 613e28a4053SRui Paulo result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); 614e28a4053SRui Paulo } 615e28a4053SRui Paulo 616e28a4053SRui Paulo if (data->final_result) { 617e28a4053SRui Paulo /* Result TLV */ 618e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV " 619e28a4053SRui Paulo "(status=SUCCESS)"); 620e28a4053SRui Paulo result = wpabuf_put(buf, sizeof(*result)); 621e28a4053SRui Paulo result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | 622e28a4053SRui Paulo EAP_TLV_RESULT_TLV); 623e28a4053SRui Paulo result->length = host_to_be16(2); 624e28a4053SRui Paulo result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); 625e28a4053SRui Paulo } 626e28a4053SRui Paulo 627e28a4053SRui Paulo /* Crypto-Binding TLV */ 628e28a4053SRui Paulo binding = wpabuf_put(buf, sizeof(*binding)); 629e28a4053SRui Paulo binding->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | 630e28a4053SRui Paulo EAP_TLV_CRYPTO_BINDING_TLV); 631e28a4053SRui Paulo binding->length = host_to_be16(sizeof(*binding) - 632e28a4053SRui Paulo sizeof(struct eap_tlv_hdr)); 633e28a4053SRui Paulo binding->version = EAP_FAST_VERSION; 634e28a4053SRui Paulo binding->received_version = data->peer_version; 635e28a4053SRui Paulo binding->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST; 636f05cddf9SRui Paulo if (random_get_bytes(binding->nonce, sizeof(binding->nonce)) < 0) { 637e28a4053SRui Paulo wpabuf_free(buf); 638e28a4053SRui Paulo return NULL; 639e28a4053SRui Paulo } 640e28a4053SRui Paulo 641e28a4053SRui Paulo /* 642e28a4053SRui Paulo * RFC 4851, Section 4.2.8: 643e28a4053SRui Paulo * The nonce in a request MUST have its least significant bit set to 0. 644e28a4053SRui Paulo */ 645e28a4053SRui Paulo binding->nonce[sizeof(binding->nonce) - 1] &= ~0x01; 646e28a4053SRui Paulo 647e28a4053SRui Paulo os_memcpy(data->crypto_binding_nonce, binding->nonce, 648e28a4053SRui Paulo sizeof(binding->nonce)); 649e28a4053SRui Paulo 650e28a4053SRui Paulo /* 651e28a4053SRui Paulo * RFC 4851, Section 5.3: 652e28a4053SRui Paulo * CMK = CMK[j] 653e28a4053SRui Paulo * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV ) 654e28a4053SRui Paulo */ 655e28a4053SRui Paulo 656e28a4053SRui Paulo hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, 657e28a4053SRui Paulo (u8 *) binding, sizeof(*binding), 658e28a4053SRui Paulo binding->compound_mac); 659e28a4053SRui Paulo 660e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d " 661e28a4053SRui Paulo "Received Version %d SubType %d", 662e28a4053SRui Paulo binding->version, binding->received_version, 663e28a4053SRui Paulo binding->subtype); 664e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", 665e28a4053SRui Paulo binding->nonce, sizeof(binding->nonce)); 666e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", 667e28a4053SRui Paulo binding->compound_mac, sizeof(binding->compound_mac)); 668e28a4053SRui Paulo 669e28a4053SRui Paulo return buf; 670e28a4053SRui Paulo } 671e28a4053SRui Paulo 672e28a4053SRui Paulo 673e28a4053SRui Paulo static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, 674e28a4053SRui Paulo struct eap_fast_data *data) 675e28a4053SRui Paulo { 676e28a4053SRui Paulo u8 pac_key[EAP_FAST_PAC_KEY_LEN]; 677e28a4053SRui Paulo u8 *pac_buf, *pac_opaque; 678e28a4053SRui Paulo struct wpabuf *buf; 679e28a4053SRui Paulo u8 *pos; 680e28a4053SRui Paulo size_t buf_len, srv_id_info_len, pac_len; 681e28a4053SRui Paulo struct eap_tlv_hdr *pac_tlv; 682e28a4053SRui Paulo struct pac_tlv_hdr *pac_info; 683e28a4053SRui Paulo struct eap_tlv_result_tlv *result; 684e28a4053SRui Paulo struct os_time now; 685e28a4053SRui Paulo 686f05cddf9SRui Paulo if (random_get_bytes(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 || 687e28a4053SRui Paulo os_get_time(&now) < 0) 688e28a4053SRui Paulo return NULL; 689e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key", 690e28a4053SRui Paulo pac_key, EAP_FAST_PAC_KEY_LEN); 691e28a4053SRui Paulo 692e28a4053SRui Paulo pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) + 693e28a4053SRui Paulo (2 + sm->identity_len) + 8; 694e28a4053SRui Paulo pac_buf = os_malloc(pac_len); 695e28a4053SRui Paulo if (pac_buf == NULL) 696e28a4053SRui Paulo return NULL; 697e28a4053SRui Paulo 698e28a4053SRui Paulo srv_id_info_len = os_strlen(data->srv_id_info); 699e28a4053SRui Paulo 700e28a4053SRui Paulo pos = pac_buf; 701e28a4053SRui Paulo *pos++ = PAC_OPAQUE_TYPE_KEY; 702e28a4053SRui Paulo *pos++ = EAP_FAST_PAC_KEY_LEN; 703e28a4053SRui Paulo os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN); 704e28a4053SRui Paulo pos += EAP_FAST_PAC_KEY_LEN; 705e28a4053SRui Paulo 706e28a4053SRui Paulo *pos++ = PAC_OPAQUE_TYPE_LIFETIME; 707e28a4053SRui Paulo *pos++ = 4; 708e28a4053SRui Paulo WPA_PUT_BE32(pos, now.sec + data->pac_key_lifetime); 709e28a4053SRui Paulo pos += 4; 710e28a4053SRui Paulo 711e28a4053SRui Paulo if (sm->identity) { 712e28a4053SRui Paulo *pos++ = PAC_OPAQUE_TYPE_IDENTITY; 713e28a4053SRui Paulo *pos++ = sm->identity_len; 714e28a4053SRui Paulo os_memcpy(pos, sm->identity, sm->identity_len); 715e28a4053SRui Paulo pos += sm->identity_len; 716e28a4053SRui Paulo } 717e28a4053SRui Paulo 718e28a4053SRui Paulo pac_len = pos - pac_buf; 719e28a4053SRui Paulo while (pac_len % 8) { 720e28a4053SRui Paulo *pos++ = PAC_OPAQUE_TYPE_PAD; 721e28a4053SRui Paulo pac_len++; 722e28a4053SRui Paulo } 723e28a4053SRui Paulo 724e28a4053SRui Paulo pac_opaque = os_malloc(pac_len + 8); 725e28a4053SRui Paulo if (pac_opaque == NULL) { 726e28a4053SRui Paulo os_free(pac_buf); 727e28a4053SRui Paulo return NULL; 728e28a4053SRui Paulo } 7295b9c547cSRui Paulo if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), 7305b9c547cSRui Paulo pac_len / 8, pac_buf, pac_opaque) < 0) { 731e28a4053SRui Paulo os_free(pac_buf); 732e28a4053SRui Paulo os_free(pac_opaque); 733e28a4053SRui Paulo return NULL; 734e28a4053SRui Paulo } 735e28a4053SRui Paulo os_free(pac_buf); 736e28a4053SRui Paulo 737e28a4053SRui Paulo pac_len += 8; 738e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque", 739e28a4053SRui Paulo pac_opaque, pac_len); 740e28a4053SRui Paulo 741e28a4053SRui Paulo buf_len = sizeof(*pac_tlv) + 742e28a4053SRui Paulo sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN + 743e28a4053SRui Paulo sizeof(struct pac_tlv_hdr) + pac_len + 744e28a4053SRui Paulo data->srv_id_len + srv_id_info_len + 100 + sizeof(*result); 745e28a4053SRui Paulo buf = wpabuf_alloc(buf_len); 746e28a4053SRui Paulo if (buf == NULL) { 747e28a4053SRui Paulo os_free(pac_opaque); 748e28a4053SRui Paulo return NULL; 749e28a4053SRui Paulo } 750e28a4053SRui Paulo 751e28a4053SRui Paulo /* Result TLV */ 752e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)"); 753e28a4053SRui Paulo result = wpabuf_put(buf, sizeof(*result)); 754e28a4053SRui Paulo WPA_PUT_BE16((u8 *) &result->tlv_type, 755e28a4053SRui Paulo EAP_TLV_TYPE_MANDATORY | EAP_TLV_RESULT_TLV); 756e28a4053SRui Paulo WPA_PUT_BE16((u8 *) &result->length, 2); 757e28a4053SRui Paulo WPA_PUT_BE16((u8 *) &result->status, EAP_TLV_RESULT_SUCCESS); 758e28a4053SRui Paulo 759e28a4053SRui Paulo /* PAC TLV */ 760e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV"); 761e28a4053SRui Paulo pac_tlv = wpabuf_put(buf, sizeof(*pac_tlv)); 762e28a4053SRui Paulo pac_tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | 763e28a4053SRui Paulo EAP_TLV_PAC_TLV); 764e28a4053SRui Paulo 765e28a4053SRui Paulo /* PAC-Key */ 766e28a4053SRui Paulo eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN); 767e28a4053SRui Paulo 768e28a4053SRui Paulo /* PAC-Opaque */ 769e28a4053SRui Paulo eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len); 770e28a4053SRui Paulo os_free(pac_opaque); 771e28a4053SRui Paulo 772e28a4053SRui Paulo /* PAC-Info */ 773e28a4053SRui Paulo pac_info = wpabuf_put(buf, sizeof(*pac_info)); 774e28a4053SRui Paulo pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO); 775e28a4053SRui Paulo 776e28a4053SRui Paulo /* PAC-Lifetime (inside PAC-Info) */ 777e28a4053SRui Paulo eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4); 778e28a4053SRui Paulo wpabuf_put_be32(buf, now.sec + data->pac_key_lifetime); 779e28a4053SRui Paulo 780e28a4053SRui Paulo /* A-ID (inside PAC-Info) */ 781e28a4053SRui Paulo eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, data->srv_id_len); 782e28a4053SRui Paulo 783e28a4053SRui Paulo /* Note: headers may be misaligned after A-ID */ 784e28a4053SRui Paulo 785e28a4053SRui Paulo if (sm->identity) { 786e28a4053SRui Paulo eap_fast_put_tlv(buf, PAC_TYPE_I_ID, sm->identity, 787e28a4053SRui Paulo sm->identity_len); 788e28a4053SRui Paulo } 789e28a4053SRui Paulo 790e28a4053SRui Paulo /* A-ID-Info (inside PAC-Info) */ 791e28a4053SRui Paulo eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id_info, 792e28a4053SRui Paulo srv_id_info_len); 793e28a4053SRui Paulo 794e28a4053SRui Paulo /* PAC-Type (inside PAC-Info) */ 795e28a4053SRui Paulo eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2); 796e28a4053SRui Paulo wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC); 797e28a4053SRui Paulo 798e28a4053SRui Paulo /* Update PAC-Info and PAC TLV Length fields */ 799e28a4053SRui Paulo pos = wpabuf_put(buf, 0); 800e28a4053SRui Paulo pac_info->len = host_to_be16(pos - (u8 *) (pac_info + 1)); 801e28a4053SRui Paulo pac_tlv->length = host_to_be16(pos - (u8 *) (pac_tlv + 1)); 802e28a4053SRui Paulo 803e28a4053SRui Paulo return buf; 804e28a4053SRui Paulo } 805e28a4053SRui Paulo 806e28a4053SRui Paulo 807e28a4053SRui Paulo static int eap_fast_encrypt_phase2(struct eap_sm *sm, 808e28a4053SRui Paulo struct eap_fast_data *data, 809e28a4053SRui Paulo struct wpabuf *plain, int piggyback) 810e28a4053SRui Paulo { 811e28a4053SRui Paulo struct wpabuf *encr; 812e28a4053SRui Paulo 813e28a4053SRui Paulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs", 814e28a4053SRui Paulo plain); 815e28a4053SRui Paulo encr = eap_server_tls_encrypt(sm, &data->ssl, plain); 816e28a4053SRui Paulo wpabuf_free(plain); 817e28a4053SRui Paulo 8185b9c547cSRui Paulo if (!encr) 8195b9c547cSRui Paulo return -1; 8205b9c547cSRui Paulo 821e28a4053SRui Paulo if (data->ssl.tls_out && piggyback) { 822e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data " 823e28a4053SRui Paulo "(len=%d) with last Phase 1 Message (len=%d " 824e28a4053SRui Paulo "used=%d)", 825e28a4053SRui Paulo (int) wpabuf_len(encr), 826e28a4053SRui Paulo (int) wpabuf_len(data->ssl.tls_out), 827e28a4053SRui Paulo (int) data->ssl.tls_out_pos); 828e28a4053SRui Paulo if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) { 829e28a4053SRui Paulo wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize " 830e28a4053SRui Paulo "output buffer"); 831e28a4053SRui Paulo wpabuf_free(encr); 832e28a4053SRui Paulo return -1; 833e28a4053SRui Paulo } 834e28a4053SRui Paulo wpabuf_put_buf(data->ssl.tls_out, encr); 835e28a4053SRui Paulo wpabuf_free(encr); 836e28a4053SRui Paulo } else { 837e28a4053SRui Paulo wpabuf_free(data->ssl.tls_out); 838e28a4053SRui Paulo data->ssl.tls_out_pos = 0; 839e28a4053SRui Paulo data->ssl.tls_out = encr; 840e28a4053SRui Paulo } 841e28a4053SRui Paulo 842e28a4053SRui Paulo return 0; 843e28a4053SRui Paulo } 844e28a4053SRui Paulo 845e28a4053SRui Paulo 846e28a4053SRui Paulo static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id) 847e28a4053SRui Paulo { 848e28a4053SRui Paulo struct eap_fast_data *data = priv; 849e28a4053SRui Paulo struct wpabuf *req = NULL; 850e28a4053SRui Paulo int piggyback = 0; 851e28a4053SRui Paulo 852e28a4053SRui Paulo if (data->ssl.state == FRAG_ACK) { 853e28a4053SRui Paulo return eap_server_tls_build_ack(id, EAP_TYPE_FAST, 854e28a4053SRui Paulo data->fast_version); 855e28a4053SRui Paulo } 856e28a4053SRui Paulo 857e28a4053SRui Paulo if (data->ssl.state == WAIT_FRAG_ACK) { 858e28a4053SRui Paulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, 859e28a4053SRui Paulo data->fast_version, id); 860e28a4053SRui Paulo } 861e28a4053SRui Paulo 862e28a4053SRui Paulo switch (data->state) { 863e28a4053SRui Paulo case START: 864e28a4053SRui Paulo return eap_fast_build_start(sm, data, id); 865e28a4053SRui Paulo case PHASE1: 866c1d255d3SCy Schubert if (tls_connection_established(sm->cfg->ssl_ctx, 867c1d255d3SCy Schubert data->ssl.conn)) { 868e28a4053SRui Paulo if (eap_fast_phase1_done(sm, data) < 0) 869e28a4053SRui Paulo return NULL; 870e28a4053SRui Paulo if (data->state == PHASE2_START) { 871e28a4053SRui Paulo /* 872e28a4053SRui Paulo * Try to generate Phase 2 data to piggyback 873e28a4053SRui Paulo * with the end of Phase 1 to avoid extra 874e28a4053SRui Paulo * roundtrip. 875e28a4053SRui Paulo */ 876e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start " 877e28a4053SRui Paulo "Phase 2"); 878e28a4053SRui Paulo if (eap_fast_process_phase2_start(sm, data)) 879e28a4053SRui Paulo break; 880e28a4053SRui Paulo req = eap_fast_build_phase2_req(sm, data, id); 881e28a4053SRui Paulo piggyback = 1; 882e28a4053SRui Paulo } 883e28a4053SRui Paulo } 884e28a4053SRui Paulo break; 885e28a4053SRui Paulo case PHASE2_ID: 886e28a4053SRui Paulo case PHASE2_METHOD: 887e28a4053SRui Paulo req = eap_fast_build_phase2_req(sm, data, id); 888e28a4053SRui Paulo break; 889e28a4053SRui Paulo case CRYPTO_BINDING: 890e28a4053SRui Paulo req = eap_fast_build_crypto_binding(sm, data); 891e28a4053SRui Paulo if (data->phase2_method) { 892e28a4053SRui Paulo /* 893e28a4053SRui Paulo * Include the start of the next EAP method in the 894e28a4053SRui Paulo * sequence in the same message with Crypto-Binding to 895e28a4053SRui Paulo * save a round-trip. 896e28a4053SRui Paulo */ 897e28a4053SRui Paulo struct wpabuf *eap; 898e28a4053SRui Paulo eap = eap_fast_build_phase2_req(sm, data, id); 899e28a4053SRui Paulo req = wpabuf_concat(req, eap); 900e28a4053SRui Paulo eap_fast_state(data, PHASE2_METHOD); 901e28a4053SRui Paulo } 902e28a4053SRui Paulo break; 903e28a4053SRui Paulo case REQUEST_PAC: 904e28a4053SRui Paulo req = eap_fast_build_pac(sm, data); 905e28a4053SRui Paulo break; 906e28a4053SRui Paulo default: 907e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", 908e28a4053SRui Paulo __func__, data->state); 909e28a4053SRui Paulo return NULL; 910e28a4053SRui Paulo } 911e28a4053SRui Paulo 912e28a4053SRui Paulo if (req && 913e28a4053SRui Paulo eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0) 914e28a4053SRui Paulo return NULL; 915e28a4053SRui Paulo 916e28a4053SRui Paulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST, 917e28a4053SRui Paulo data->fast_version, id); 918e28a4053SRui Paulo } 919e28a4053SRui Paulo 920e28a4053SRui Paulo 921c1d255d3SCy Schubert static bool eap_fast_check(struct eap_sm *sm, void *priv, 922e28a4053SRui Paulo struct wpabuf *respData) 923e28a4053SRui Paulo { 924e28a4053SRui Paulo const u8 *pos; 925e28a4053SRui Paulo size_t len; 926e28a4053SRui Paulo 927e28a4053SRui Paulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData, &len); 928e28a4053SRui Paulo if (pos == NULL || len < 1) { 929e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame"); 930c1d255d3SCy Schubert return true; 931e28a4053SRui Paulo } 932e28a4053SRui Paulo 933c1d255d3SCy Schubert return false; 934e28a4053SRui Paulo } 935e28a4053SRui Paulo 936e28a4053SRui Paulo 937e28a4053SRui Paulo static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, 938c1d255d3SCy Schubert int vendor, enum eap_type eap_type) 939e28a4053SRui Paulo { 940e28a4053SRui Paulo if (data->phase2_priv && data->phase2_method) { 941e28a4053SRui Paulo data->phase2_method->reset(sm, data->phase2_priv); 942e28a4053SRui Paulo data->phase2_method = NULL; 943e28a4053SRui Paulo data->phase2_priv = NULL; 944e28a4053SRui Paulo } 945c1d255d3SCy Schubert data->phase2_method = eap_server_get_eap_method(vendor, eap_type); 946e28a4053SRui Paulo if (!data->phase2_method) 947e28a4053SRui Paulo return -1; 948e28a4053SRui Paulo 949e28a4053SRui Paulo if (data->key_block_p) { 950e28a4053SRui Paulo sm->auth_challenge = data->key_block_p->server_challenge; 951e28a4053SRui Paulo sm->peer_challenge = data->key_block_p->client_challenge; 952e28a4053SRui Paulo } 953*a90b9d01SCy Schubert sm->eap_fast_mschapv2 = true; 954e28a4053SRui Paulo sm->init_phase2 = 1; 955e28a4053SRui Paulo data->phase2_priv = data->phase2_method->init(sm); 956e28a4053SRui Paulo sm->init_phase2 = 0; 957e28a4053SRui Paulo sm->auth_challenge = NULL; 958e28a4053SRui Paulo sm->peer_challenge = NULL; 959e28a4053SRui Paulo 960e28a4053SRui Paulo return data->phase2_priv == NULL ? -1 : 0; 961e28a4053SRui Paulo } 962e28a4053SRui Paulo 963e28a4053SRui Paulo 964e28a4053SRui Paulo static void eap_fast_process_phase2_response(struct eap_sm *sm, 965e28a4053SRui Paulo struct eap_fast_data *data, 966e28a4053SRui Paulo u8 *in_data, size_t in_len) 967e28a4053SRui Paulo { 968c1d255d3SCy Schubert int next_vendor = EAP_VENDOR_IETF; 969c1d255d3SCy Schubert enum eap_type next_type = EAP_TYPE_NONE; 970e28a4053SRui Paulo struct eap_hdr *hdr; 971e28a4053SRui Paulo u8 *pos; 972e28a4053SRui Paulo size_t left; 973e28a4053SRui Paulo struct wpabuf buf; 974e28a4053SRui Paulo const struct eap_method *m = data->phase2_method; 975e28a4053SRui Paulo void *priv = data->phase2_priv; 976e28a4053SRui Paulo 977e28a4053SRui Paulo if (priv == NULL) { 978e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: %s - Phase2 not " 979e28a4053SRui Paulo "initialized?!", __func__); 980e28a4053SRui Paulo return; 981e28a4053SRui Paulo } 982e28a4053SRui Paulo 983e28a4053SRui Paulo hdr = (struct eap_hdr *) in_data; 984e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 985e28a4053SRui Paulo 986e28a4053SRui Paulo if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { 987e28a4053SRui Paulo left = in_len - sizeof(*hdr); 988e28a4053SRui Paulo wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; " 989e28a4053SRui Paulo "allowed types", pos + 1, left - 1); 990e28a4053SRui Paulo #ifdef EAP_SERVER_TNC 991e28a4053SRui Paulo if (m && m->vendor == EAP_VENDOR_IETF && 992e28a4053SRui Paulo m->method == EAP_TYPE_TNC) { 993e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required " 994e28a4053SRui Paulo "TNC negotiation"); 995c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 996e28a4053SRui Paulo next_type = eap_fast_req_failure(sm, data); 997c1d255d3SCy Schubert eap_fast_phase2_init(sm, data, next_vendor, next_type); 998e28a4053SRui Paulo return; 999e28a4053SRui Paulo } 1000e28a4053SRui Paulo #endif /* EAP_SERVER_TNC */ 1001e28a4053SRui Paulo eap_sm_process_nak(sm, pos + 1, left - 1); 1002e28a4053SRui Paulo if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 1003e28a4053SRui Paulo sm->user->methods[sm->user_eap_method_index].method != 1004e28a4053SRui Paulo EAP_TYPE_NONE) { 1005c1d255d3SCy Schubert next_vendor = sm->user->methods[ 1006c1d255d3SCy Schubert sm->user_eap_method_index].vendor; 1007e28a4053SRui Paulo next_type = sm->user->methods[ 1008e28a4053SRui Paulo sm->user_eap_method_index++].method; 1009c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u", 1010c1d255d3SCy Schubert next_vendor, next_type); 1011e28a4053SRui Paulo } else { 1012c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1013e28a4053SRui Paulo next_type = eap_fast_req_failure(sm, data); 1014e28a4053SRui Paulo } 1015c1d255d3SCy Schubert eap_fast_phase2_init(sm, data, next_vendor, next_type); 1016e28a4053SRui Paulo return; 1017e28a4053SRui Paulo } 1018e28a4053SRui Paulo 1019e28a4053SRui Paulo wpabuf_set(&buf, in_data, in_len); 1020e28a4053SRui Paulo 1021e28a4053SRui Paulo if (m->check(sm, priv, &buf)) { 1022e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to " 1023e28a4053SRui Paulo "ignore the packet"); 10245b9c547cSRui Paulo eap_fast_req_failure(sm, data); 1025e28a4053SRui Paulo return; 1026e28a4053SRui Paulo } 1027e28a4053SRui Paulo 1028e28a4053SRui Paulo m->process(sm, priv, &buf); 1029e28a4053SRui Paulo 1030e28a4053SRui Paulo if (!m->isDone(sm, priv)) 1031e28a4053SRui Paulo return; 1032e28a4053SRui Paulo 1033e28a4053SRui Paulo if (!m->isSuccess(sm, priv)) { 1034e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method failed"); 1035c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1036e28a4053SRui Paulo next_type = eap_fast_req_failure(sm, data); 1037c1d255d3SCy Schubert eap_fast_phase2_init(sm, data, next_vendor, next_type); 1038e28a4053SRui Paulo return; 1039e28a4053SRui Paulo } 1040e28a4053SRui Paulo 1041e28a4053SRui Paulo switch (data->state) { 1042e28a4053SRui Paulo case PHASE2_ID: 1043e28a4053SRui Paulo if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 1044e28a4053SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Phase2 " 1045e28a4053SRui Paulo "Identity not found in the user " 1046e28a4053SRui Paulo "database", 1047e28a4053SRui Paulo sm->identity, sm->identity_len); 1048c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1049e28a4053SRui Paulo next_type = eap_fast_req_failure(sm, data); 1050e28a4053SRui Paulo break; 1051e28a4053SRui Paulo } 1052e28a4053SRui Paulo 1053e28a4053SRui Paulo eap_fast_state(data, PHASE2_METHOD); 1054e28a4053SRui Paulo if (data->anon_provisioning) { 1055e28a4053SRui Paulo /* 1056e28a4053SRui Paulo * Only EAP-MSCHAPv2 is allowed for anonymous 1057e28a4053SRui Paulo * provisioning. 1058e28a4053SRui Paulo */ 1059c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1060e28a4053SRui Paulo next_type = EAP_TYPE_MSCHAPV2; 1061e28a4053SRui Paulo sm->user_eap_method_index = 0; 1062e28a4053SRui Paulo } else { 1063c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor; 1064e28a4053SRui Paulo next_type = sm->user->methods[0].method; 1065e28a4053SRui Paulo sm->user_eap_method_index = 1; 1066e28a4053SRui Paulo } 1067c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %u:%u", 1068c1d255d3SCy Schubert next_vendor, next_type); 1069e28a4053SRui Paulo break; 1070e28a4053SRui Paulo case PHASE2_METHOD: 1071e28a4053SRui Paulo case CRYPTO_BINDING: 1072e28a4053SRui Paulo eap_fast_update_icmk(sm, data); 1073e28a4053SRui Paulo eap_fast_state(data, CRYPTO_BINDING); 1074e28a4053SRui Paulo data->eap_seq++; 1075c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1076e28a4053SRui Paulo next_type = EAP_TYPE_NONE; 1077e28a4053SRui Paulo #ifdef EAP_SERVER_TNC 1078c1d255d3SCy Schubert if (sm->cfg->tnc && !data->tnc_started) { 1079e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC"); 1080c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1081e28a4053SRui Paulo next_type = EAP_TYPE_TNC; 1082e28a4053SRui Paulo data->tnc_started = 1; 1083e28a4053SRui Paulo } 1084e28a4053SRui Paulo #endif /* EAP_SERVER_TNC */ 1085e28a4053SRui Paulo break; 1086e28a4053SRui Paulo case FAILURE: 1087e28a4053SRui Paulo break; 1088e28a4053SRui Paulo default: 1089e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: %s - unexpected state %d", 1090e28a4053SRui Paulo __func__, data->state); 1091e28a4053SRui Paulo break; 1092e28a4053SRui Paulo } 1093e28a4053SRui Paulo 1094c1d255d3SCy Schubert eap_fast_phase2_init(sm, data, next_vendor, next_type); 1095e28a4053SRui Paulo } 1096e28a4053SRui Paulo 1097e28a4053SRui Paulo 1098e28a4053SRui Paulo static void eap_fast_process_phase2_eap(struct eap_sm *sm, 1099e28a4053SRui Paulo struct eap_fast_data *data, 1100e28a4053SRui Paulo u8 *in_data, size_t in_len) 1101e28a4053SRui Paulo { 1102e28a4053SRui Paulo struct eap_hdr *hdr; 1103e28a4053SRui Paulo size_t len; 1104e28a4053SRui Paulo 1105e28a4053SRui Paulo hdr = (struct eap_hdr *) in_data; 1106e28a4053SRui Paulo if (in_len < (int) sizeof(*hdr)) { 1107e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 " 1108e28a4053SRui Paulo "EAP frame (len=%lu)", (unsigned long) in_len); 1109e28a4053SRui Paulo eap_fast_req_failure(sm, data); 1110e28a4053SRui Paulo return; 1111e28a4053SRui Paulo } 1112e28a4053SRui Paulo len = be_to_host16(hdr->length); 1113e28a4053SRui Paulo if (len > in_len) { 1114e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Length mismatch in " 1115e28a4053SRui Paulo "Phase 2 EAP frame (len=%lu hdr->length=%lu)", 1116e28a4053SRui Paulo (unsigned long) in_len, (unsigned long) len); 1117e28a4053SRui Paulo eap_fast_req_failure(sm, data); 1118e28a4053SRui Paulo return; 1119e28a4053SRui Paulo } 1120e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: code=%d " 1121e28a4053SRui Paulo "identifier=%d length=%lu", hdr->code, hdr->identifier, 1122e28a4053SRui Paulo (unsigned long) len); 1123e28a4053SRui Paulo switch (hdr->code) { 1124e28a4053SRui Paulo case EAP_CODE_RESPONSE: 1125e28a4053SRui Paulo eap_fast_process_phase2_response(sm, data, (u8 *) hdr, len); 1126e28a4053SRui Paulo break; 1127e28a4053SRui Paulo default: 1128e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in " 1129e28a4053SRui Paulo "Phase 2 EAP header", hdr->code); 1130e28a4053SRui Paulo break; 1131e28a4053SRui Paulo } 1132e28a4053SRui Paulo } 1133e28a4053SRui Paulo 1134e28a4053SRui Paulo 1135e28a4053SRui Paulo static int eap_fast_parse_tlvs(struct wpabuf *data, 1136e28a4053SRui Paulo struct eap_fast_tlv_parse *tlv) 1137e28a4053SRui Paulo { 11385b9c547cSRui Paulo int mandatory, tlv_type, res; 11395b9c547cSRui Paulo size_t len; 1140e28a4053SRui Paulo u8 *pos, *end; 1141e28a4053SRui Paulo 1142e28a4053SRui Paulo os_memset(tlv, 0, sizeof(*tlv)); 1143e28a4053SRui Paulo 1144e28a4053SRui Paulo pos = wpabuf_mhead(data); 1145e28a4053SRui Paulo end = pos + wpabuf_len(data); 1146780fb4a2SCy Schubert while (end - pos > 4) { 1147e28a4053SRui Paulo mandatory = pos[0] & 0x80; 1148e28a4053SRui Paulo tlv_type = WPA_GET_BE16(pos) & 0x3fff; 1149e28a4053SRui Paulo pos += 2; 1150e28a4053SRui Paulo len = WPA_GET_BE16(pos); 1151e28a4053SRui Paulo pos += 2; 11525b9c547cSRui Paulo if (len > (size_t) (end - pos)) { 1153e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); 1154e28a4053SRui Paulo return -1; 1155e28a4053SRui Paulo } 1156e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " 11575b9c547cSRui Paulo "TLV type %d length %u%s", 11585b9c547cSRui Paulo tlv_type, (unsigned int) len, 11595b9c547cSRui Paulo mandatory ? " (mandatory)" : ""); 1160e28a4053SRui Paulo 1161e28a4053SRui Paulo res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); 1162e28a4053SRui Paulo if (res == -2) 1163e28a4053SRui Paulo break; 1164e28a4053SRui Paulo if (res < 0) { 1165e28a4053SRui Paulo if (mandatory) { 1166e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Nak unknown " 1167e28a4053SRui Paulo "mandatory TLV type %d", tlv_type); 1168e28a4053SRui Paulo /* TODO: generate Nak TLV */ 1169e28a4053SRui Paulo break; 1170e28a4053SRui Paulo } else { 1171e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Ignored " 1172e28a4053SRui Paulo "unknown optional TLV type %d", 1173e28a4053SRui Paulo tlv_type); 1174e28a4053SRui Paulo } 1175e28a4053SRui Paulo } 1176e28a4053SRui Paulo 1177e28a4053SRui Paulo pos += len; 1178e28a4053SRui Paulo } 1179e28a4053SRui Paulo 1180e28a4053SRui Paulo return 0; 1181e28a4053SRui Paulo } 1182e28a4053SRui Paulo 1183e28a4053SRui Paulo 1184e28a4053SRui Paulo static int eap_fast_validate_crypto_binding( 1185e28a4053SRui Paulo struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b, 1186e28a4053SRui Paulo size_t bind_len) 1187e28a4053SRui Paulo { 1188e28a4053SRui Paulo u8 cmac[SHA1_MAC_LEN]; 1189e28a4053SRui Paulo 1190e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: " 1191e28a4053SRui Paulo "Version %d Received Version %d SubType %d", 1192e28a4053SRui Paulo b->version, b->received_version, b->subtype); 1193e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE", 1194e28a4053SRui Paulo b->nonce, sizeof(b->nonce)); 1195e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC", 1196e28a4053SRui Paulo b->compound_mac, sizeof(b->compound_mac)); 1197e28a4053SRui Paulo 1198e28a4053SRui Paulo if (b->version != EAP_FAST_VERSION || 1199e28a4053SRui Paulo b->received_version != EAP_FAST_VERSION) { 1200e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected version " 1201e28a4053SRui Paulo "in Crypto-Binding: version %d " 1202e28a4053SRui Paulo "received_version %d", b->version, 1203e28a4053SRui Paulo b->received_version); 1204e28a4053SRui Paulo return -1; 1205e28a4053SRui Paulo } 1206e28a4053SRui Paulo 1207e28a4053SRui Paulo if (b->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE) { 1208e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected subtype in " 1209e28a4053SRui Paulo "Crypto-Binding: %d", b->subtype); 1210e28a4053SRui Paulo return -1; 1211e28a4053SRui Paulo } 1212e28a4053SRui Paulo 12135b9c547cSRui Paulo if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 || 1214e28a4053SRui Paulo (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) { 1215e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in " 1216e28a4053SRui Paulo "Crypto-Binding"); 1217e28a4053SRui Paulo return -1; 1218e28a4053SRui Paulo } 1219e28a4053SRui Paulo 1220e28a4053SRui Paulo os_memcpy(cmac, b->compound_mac, sizeof(cmac)); 1221e28a4053SRui Paulo os_memset(b->compound_mac, 0, sizeof(cmac)); 1222e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for " 1223e28a4053SRui Paulo "Compound MAC calculation", 1224e28a4053SRui Paulo (u8 *) b, bind_len); 1225e28a4053SRui Paulo hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len, 1226e28a4053SRui Paulo b->compound_mac); 12275b9c547cSRui Paulo if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) { 1228e28a4053SRui Paulo wpa_hexdump(MSG_MSGDUMP, 1229e28a4053SRui Paulo "EAP-FAST: Calculated Compound MAC", 1230e28a4053SRui Paulo b->compound_mac, sizeof(cmac)); 1231e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not " 1232e28a4053SRui Paulo "match"); 1233e28a4053SRui Paulo return -1; 1234e28a4053SRui Paulo } 1235e28a4053SRui Paulo 1236e28a4053SRui Paulo return 0; 1237e28a4053SRui Paulo } 1238e28a4053SRui Paulo 1239e28a4053SRui Paulo 1240e28a4053SRui Paulo static int eap_fast_pac_type(u8 *pac, size_t len, u16 type) 1241e28a4053SRui Paulo { 1242e28a4053SRui Paulo struct eap_tlv_pac_type_tlv *tlv; 1243e28a4053SRui Paulo 1244e28a4053SRui Paulo if (pac == NULL || len != sizeof(*tlv)) 1245e28a4053SRui Paulo return 0; 1246e28a4053SRui Paulo 1247e28a4053SRui Paulo tlv = (struct eap_tlv_pac_type_tlv *) pac; 1248e28a4053SRui Paulo 1249e28a4053SRui Paulo return be_to_host16(tlv->tlv_type) == PAC_TYPE_PAC_TYPE && 1250e28a4053SRui Paulo be_to_host16(tlv->length) == 2 && 1251e28a4053SRui Paulo be_to_host16(tlv->pac_type) == type; 1252e28a4053SRui Paulo } 1253e28a4053SRui Paulo 1254e28a4053SRui Paulo 1255e28a4053SRui Paulo static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, 1256e28a4053SRui Paulo struct eap_fast_data *data, 1257e28a4053SRui Paulo struct wpabuf *in_data) 1258e28a4053SRui Paulo { 1259e28a4053SRui Paulo struct eap_fast_tlv_parse tlv; 1260e28a4053SRui Paulo int check_crypto_binding = data->state == CRYPTO_BINDING; 1261e28a4053SRui Paulo 1262e28a4053SRui Paulo if (eap_fast_parse_tlvs(in_data, &tlv) < 0) { 1263e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to parse received " 1264e28a4053SRui Paulo "Phase 2 TLVs"); 1265e28a4053SRui Paulo return; 1266e28a4053SRui Paulo } 1267e28a4053SRui Paulo 1268e28a4053SRui Paulo if (tlv.result == EAP_TLV_RESULT_FAILURE) { 1269e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Result TLV indicated " 1270e28a4053SRui Paulo "failure"); 1271e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1272e28a4053SRui Paulo return; 1273e28a4053SRui Paulo } 1274e28a4053SRui Paulo 1275e28a4053SRui Paulo if (data->state == REQUEST_PAC) { 1276e28a4053SRui Paulo u16 type, len, res; 1277e28a4053SRui Paulo if (tlv.pac == NULL || tlv.pac_len < 6) { 1278e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC " 1279e28a4053SRui Paulo "Acknowledgement received"); 1280e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1281e28a4053SRui Paulo return; 1282e28a4053SRui Paulo } 1283e28a4053SRui Paulo 1284e28a4053SRui Paulo type = WPA_GET_BE16(tlv.pac); 1285e28a4053SRui Paulo len = WPA_GET_BE16(tlv.pac + 2); 1286e28a4053SRui Paulo res = WPA_GET_BE16(tlv.pac + 4); 1287e28a4053SRui Paulo 1288e28a4053SRui Paulo if (type != PAC_TYPE_PAC_ACKNOWLEDGEMENT || len != 2 || 1289e28a4053SRui Paulo res != EAP_TLV_RESULT_SUCCESS) { 1290e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV did not " 1291e28a4053SRui Paulo "contain acknowledgement"); 1292e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1293e28a4053SRui Paulo return; 1294e28a4053SRui Paulo } 1295e28a4053SRui Paulo 1296e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Acknowledgement received " 1297e28a4053SRui Paulo "- PAC provisioning succeeded"); 1298e28a4053SRui Paulo eap_fast_state(data, (data->anon_provisioning || 1299e28a4053SRui Paulo data->send_new_pac == 2) ? 1300e28a4053SRui Paulo FAILURE : SUCCESS); 1301e28a4053SRui Paulo return; 1302e28a4053SRui Paulo } 1303e28a4053SRui Paulo 1304e28a4053SRui Paulo if (check_crypto_binding) { 1305e28a4053SRui Paulo if (tlv.crypto_binding == NULL) { 1306e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding " 1307e28a4053SRui Paulo "TLV received"); 1308e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1309e28a4053SRui Paulo return; 1310e28a4053SRui Paulo } 1311e28a4053SRui Paulo 1312e28a4053SRui Paulo if (data->final_result && 1313e28a4053SRui Paulo tlv.result != EAP_TLV_RESULT_SUCCESS) { 1314e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " 1315e28a4053SRui Paulo "without Success Result"); 1316e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1317e28a4053SRui Paulo return; 1318e28a4053SRui Paulo } 1319e28a4053SRui Paulo 1320e28a4053SRui Paulo if (!data->final_result && 1321e28a4053SRui Paulo tlv.iresult != EAP_TLV_RESULT_SUCCESS) { 1322e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV " 1323e28a4053SRui Paulo "without intermediate Success Result"); 1324e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1325e28a4053SRui Paulo return; 1326e28a4053SRui Paulo } 1327e28a4053SRui Paulo 1328e28a4053SRui Paulo if (eap_fast_validate_crypto_binding(data, tlv.crypto_binding, 1329e28a4053SRui Paulo tlv.crypto_binding_len)) { 1330e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1331e28a4053SRui Paulo return; 1332e28a4053SRui Paulo } 1333e28a4053SRui Paulo 1334e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV " 1335e28a4053SRui Paulo "received"); 1336e28a4053SRui Paulo if (data->final_result) { 1337e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " 1338e28a4053SRui Paulo "completed successfully"); 1339e28a4053SRui Paulo } 1340e28a4053SRui Paulo 1341e28a4053SRui Paulo if (data->anon_provisioning && 1342c1d255d3SCy Schubert sm->cfg->eap_fast_prov != ANON_PROV && 1343c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV) { 1344e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " 1345e28a4053SRui Paulo "use unauthenticated provisioning which is " 1346e28a4053SRui Paulo "disabled"); 1347e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1348e28a4053SRui Paulo return; 1349e28a4053SRui Paulo } 1350e28a4053SRui Paulo 1351c1d255d3SCy Schubert if (sm->cfg->eap_fast_prov != AUTH_PROV && 1352c1d255d3SCy Schubert sm->cfg->eap_fast_prov != BOTH_PROV && 1353e28a4053SRui Paulo tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && 1354e28a4053SRui Paulo eap_fast_pac_type(tlv.pac, tlv.pac_len, 1355e28a4053SRui Paulo PAC_TYPE_TUNNEL_PAC)) { 1356e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Client is trying to " 1357e28a4053SRui Paulo "use authenticated provisioning which is " 1358e28a4053SRui Paulo "disabled"); 1359e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1360e28a4053SRui Paulo return; 1361e28a4053SRui Paulo } 1362e28a4053SRui Paulo 1363e28a4053SRui Paulo if (data->anon_provisioning || 1364e28a4053SRui Paulo (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && 1365e28a4053SRui Paulo eap_fast_pac_type(tlv.pac, tlv.pac_len, 1366e28a4053SRui Paulo PAC_TYPE_TUNNEL_PAC))) { 1367e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Requested a new " 1368e28a4053SRui Paulo "Tunnel PAC"); 1369e28a4053SRui Paulo eap_fast_state(data, REQUEST_PAC); 1370e28a4053SRui Paulo } else if (data->send_new_pac) { 1371e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered " 1372e28a4053SRui Paulo "re-keying of Tunnel PAC"); 1373e28a4053SRui Paulo eap_fast_state(data, REQUEST_PAC); 1374e28a4053SRui Paulo } else if (data->final_result) 1375e28a4053SRui Paulo eap_fast_state(data, SUCCESS); 1376e28a4053SRui Paulo } 1377e28a4053SRui Paulo 1378e28a4053SRui Paulo if (tlv.eap_payload_tlv) { 1379e28a4053SRui Paulo eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, 1380e28a4053SRui Paulo tlv.eap_payload_tlv_len); 1381e28a4053SRui Paulo } 1382e28a4053SRui Paulo } 1383e28a4053SRui Paulo 1384e28a4053SRui Paulo 1385e28a4053SRui Paulo static void eap_fast_process_phase2(struct eap_sm *sm, 1386e28a4053SRui Paulo struct eap_fast_data *data, 1387e28a4053SRui Paulo struct wpabuf *in_buf) 1388e28a4053SRui Paulo { 1389e28a4053SRui Paulo struct wpabuf *in_decrypted; 1390e28a4053SRui Paulo 1391e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for" 1392e28a4053SRui Paulo " Phase 2", (unsigned long) wpabuf_len(in_buf)); 1393e28a4053SRui Paulo 1394e28a4053SRui Paulo if (data->pending_phase2_resp) { 1395e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " 1396e28a4053SRui Paulo "skip decryption and use old data"); 1397e28a4053SRui Paulo eap_fast_process_phase2_tlvs(sm, data, 1398e28a4053SRui Paulo data->pending_phase2_resp); 1399e28a4053SRui Paulo wpabuf_free(data->pending_phase2_resp); 1400e28a4053SRui Paulo data->pending_phase2_resp = NULL; 1401e28a4053SRui Paulo return; 1402e28a4053SRui Paulo } 1403e28a4053SRui Paulo 1404c1d255d3SCy Schubert in_decrypted = tls_connection_decrypt(sm->cfg->ssl_ctx, data->ssl.conn, 1405e28a4053SRui Paulo in_buf); 1406e28a4053SRui Paulo if (in_decrypted == NULL) { 1407e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 " 1408e28a4053SRui Paulo "data"); 1409e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1410e28a4053SRui Paulo return; 1411e28a4053SRui Paulo } 1412e28a4053SRui Paulo 1413e28a4053SRui Paulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Decrypted Phase 2 TLVs", 1414e28a4053SRui Paulo in_decrypted); 1415e28a4053SRui Paulo 1416e28a4053SRui Paulo eap_fast_process_phase2_tlvs(sm, data, in_decrypted); 1417e28a4053SRui Paulo 1418e28a4053SRui Paulo if (sm->method_pending == METHOD_PENDING_WAIT) { 1419e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 method is in " 1420e28a4053SRui Paulo "pending wait state - save decrypted response"); 1421e28a4053SRui Paulo wpabuf_free(data->pending_phase2_resp); 1422e28a4053SRui Paulo data->pending_phase2_resp = in_decrypted; 1423e28a4053SRui Paulo return; 1424e28a4053SRui Paulo } 1425e28a4053SRui Paulo 1426e28a4053SRui Paulo wpabuf_free(in_decrypted); 1427e28a4053SRui Paulo } 1428e28a4053SRui Paulo 1429e28a4053SRui Paulo 1430e28a4053SRui Paulo static int eap_fast_process_version(struct eap_sm *sm, void *priv, 1431e28a4053SRui Paulo int peer_version) 1432e28a4053SRui Paulo { 1433e28a4053SRui Paulo struct eap_fast_data *data = priv; 1434e28a4053SRui Paulo 1435e28a4053SRui Paulo data->peer_version = peer_version; 1436e28a4053SRui Paulo 1437e28a4053SRui Paulo if (data->force_version >= 0 && peer_version != data->force_version) { 1438e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced" 1439e28a4053SRui Paulo " version (forced=%d peer=%d) - reject", 1440e28a4053SRui Paulo data->force_version, peer_version); 1441e28a4053SRui Paulo return -1; 1442e28a4053SRui Paulo } 1443e28a4053SRui Paulo 1444e28a4053SRui Paulo if (peer_version < data->fast_version) { 1445e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; " 1446e28a4053SRui Paulo "use version %d", 1447e28a4053SRui Paulo peer_version, data->fast_version, peer_version); 1448e28a4053SRui Paulo data->fast_version = peer_version; 1449e28a4053SRui Paulo } 1450e28a4053SRui Paulo 1451e28a4053SRui Paulo return 0; 1452e28a4053SRui Paulo } 1453e28a4053SRui Paulo 1454e28a4053SRui Paulo 1455e28a4053SRui Paulo static int eap_fast_process_phase1(struct eap_sm *sm, 1456e28a4053SRui Paulo struct eap_fast_data *data) 1457e28a4053SRui Paulo { 1458e28a4053SRui Paulo if (eap_server_tls_phase1(sm, &data->ssl) < 0) { 1459e28a4053SRui Paulo wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed"); 1460e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1461e28a4053SRui Paulo return -1; 1462e28a4053SRui Paulo } 1463e28a4053SRui Paulo 1464c1d255d3SCy Schubert if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) || 1465e28a4053SRui Paulo wpabuf_len(data->ssl.tls_out) > 0) 1466e28a4053SRui Paulo return 1; 1467e28a4053SRui Paulo 1468e28a4053SRui Paulo /* 1469e28a4053SRui Paulo * Phase 1 was completed with the received message (e.g., when using 1470e28a4053SRui Paulo * abbreviated handshake), so Phase 2 can be started immediately 1471e28a4053SRui Paulo * without having to send through an empty message to the peer. 1472e28a4053SRui Paulo */ 1473e28a4053SRui Paulo 1474e28a4053SRui Paulo return eap_fast_phase1_done(sm, data); 1475e28a4053SRui Paulo } 1476e28a4053SRui Paulo 1477e28a4053SRui Paulo 1478e28a4053SRui Paulo static int eap_fast_process_phase2_start(struct eap_sm *sm, 1479e28a4053SRui Paulo struct eap_fast_data *data) 1480e28a4053SRui Paulo { 1481c1d255d3SCy Schubert int next_vendor; 1482c1d255d3SCy Schubert enum eap_type next_type; 1483e28a4053SRui Paulo 1484e28a4053SRui Paulo if (data->identity) { 1485e28a4053SRui Paulo os_free(sm->identity); 1486e28a4053SRui Paulo sm->identity = data->identity; 1487e28a4053SRui Paulo data->identity = NULL; 1488e28a4053SRui Paulo sm->identity_len = data->identity_len; 1489e28a4053SRui Paulo data->identity_len = 0; 1490e28a4053SRui Paulo sm->require_identity_match = 1; 1491e28a4053SRui Paulo if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 1492e28a4053SRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: " 1493e28a4053SRui Paulo "Phase2 Identity not found " 1494e28a4053SRui Paulo "in the user database", 1495e28a4053SRui Paulo sm->identity, sm->identity_len); 1496c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1497e28a4053SRui Paulo next_type = eap_fast_req_failure(sm, data); 1498e28a4053SRui Paulo } else { 1499e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already " 1500e28a4053SRui Paulo "known - skip Phase 2 Identity Request"); 1501c1d255d3SCy Schubert next_vendor = sm->user->methods[0].vendor; 1502e28a4053SRui Paulo next_type = sm->user->methods[0].method; 1503e28a4053SRui Paulo sm->user_eap_method_index = 1; 1504e28a4053SRui Paulo } 1505e28a4053SRui Paulo 1506e28a4053SRui Paulo eap_fast_state(data, PHASE2_METHOD); 1507e28a4053SRui Paulo } else { 1508e28a4053SRui Paulo eap_fast_state(data, PHASE2_ID); 1509c1d255d3SCy Schubert next_vendor = EAP_VENDOR_IETF; 1510e28a4053SRui Paulo next_type = EAP_TYPE_IDENTITY; 1511e28a4053SRui Paulo } 1512e28a4053SRui Paulo 1513c1d255d3SCy Schubert return eap_fast_phase2_init(sm, data, next_vendor, next_type); 1514e28a4053SRui Paulo } 1515e28a4053SRui Paulo 1516e28a4053SRui Paulo 1517e28a4053SRui Paulo static void eap_fast_process_msg(struct eap_sm *sm, void *priv, 1518e28a4053SRui Paulo const struct wpabuf *respData) 1519e28a4053SRui Paulo { 1520e28a4053SRui Paulo struct eap_fast_data *data = priv; 1521e28a4053SRui Paulo 1522e28a4053SRui Paulo switch (data->state) { 1523e28a4053SRui Paulo case PHASE1: 1524e28a4053SRui Paulo if (eap_fast_process_phase1(sm, data)) 1525e28a4053SRui Paulo break; 1526e28a4053SRui Paulo 152785732ac8SCy Schubert /* fall through */ 1528e28a4053SRui Paulo case PHASE2_START: 1529e28a4053SRui Paulo eap_fast_process_phase2_start(sm, data); 1530e28a4053SRui Paulo break; 1531e28a4053SRui Paulo case PHASE2_ID: 1532e28a4053SRui Paulo case PHASE2_METHOD: 1533e28a4053SRui Paulo case CRYPTO_BINDING: 1534e28a4053SRui Paulo case REQUEST_PAC: 1535e28a4053SRui Paulo eap_fast_process_phase2(sm, data, data->ssl.tls_in); 1536e28a4053SRui Paulo break; 1537e28a4053SRui Paulo default: 1538e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s", 1539e28a4053SRui Paulo data->state, __func__); 1540e28a4053SRui Paulo break; 1541e28a4053SRui Paulo } 1542e28a4053SRui Paulo } 1543e28a4053SRui Paulo 1544e28a4053SRui Paulo 1545e28a4053SRui Paulo static void eap_fast_process(struct eap_sm *sm, void *priv, 1546e28a4053SRui Paulo struct wpabuf *respData) 1547e28a4053SRui Paulo { 1548e28a4053SRui Paulo struct eap_fast_data *data = priv; 1549e28a4053SRui Paulo if (eap_server_tls_process(sm, &data->ssl, respData, data, 1550e28a4053SRui Paulo EAP_TYPE_FAST, eap_fast_process_version, 1551e28a4053SRui Paulo eap_fast_process_msg) < 0) 1552e28a4053SRui Paulo eap_fast_state(data, FAILURE); 1553e28a4053SRui Paulo } 1554e28a4053SRui Paulo 1555e28a4053SRui Paulo 1556c1d255d3SCy Schubert static bool eap_fast_isDone(struct eap_sm *sm, void *priv) 1557e28a4053SRui Paulo { 1558e28a4053SRui Paulo struct eap_fast_data *data = priv; 1559e28a4053SRui Paulo return data->state == SUCCESS || data->state == FAILURE; 1560e28a4053SRui Paulo } 1561e28a4053SRui Paulo 1562e28a4053SRui Paulo 1563e28a4053SRui Paulo static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len) 1564e28a4053SRui Paulo { 1565e28a4053SRui Paulo struct eap_fast_data *data = priv; 1566e28a4053SRui Paulo u8 *eapKeyData; 1567e28a4053SRui Paulo 1568e28a4053SRui Paulo if (data->state != SUCCESS) 1569e28a4053SRui Paulo return NULL; 1570e28a4053SRui Paulo 1571e28a4053SRui Paulo eapKeyData = os_malloc(EAP_FAST_KEY_LEN); 1572e28a4053SRui Paulo if (eapKeyData == NULL) 1573e28a4053SRui Paulo return NULL; 1574e28a4053SRui Paulo 1575780fb4a2SCy Schubert if (eap_fast_derive_eap_msk(data->simck, eapKeyData) < 0) { 1576780fb4a2SCy Schubert os_free(eapKeyData); 1577780fb4a2SCy Schubert return NULL; 1578780fb4a2SCy Schubert } 1579e28a4053SRui Paulo *len = EAP_FAST_KEY_LEN; 1580e28a4053SRui Paulo 1581e28a4053SRui Paulo return eapKeyData; 1582e28a4053SRui Paulo } 1583e28a4053SRui Paulo 1584e28a4053SRui Paulo 1585e28a4053SRui Paulo static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 1586e28a4053SRui Paulo { 1587e28a4053SRui Paulo struct eap_fast_data *data = priv; 1588e28a4053SRui Paulo u8 *eapKeyData; 1589e28a4053SRui Paulo 1590e28a4053SRui Paulo if (data->state != SUCCESS) 1591e28a4053SRui Paulo return NULL; 1592e28a4053SRui Paulo 1593e28a4053SRui Paulo eapKeyData = os_malloc(EAP_EMSK_LEN); 1594e28a4053SRui Paulo if (eapKeyData == NULL) 1595e28a4053SRui Paulo return NULL; 1596e28a4053SRui Paulo 1597780fb4a2SCy Schubert if (eap_fast_derive_eap_emsk(data->simck, eapKeyData) < 0) { 1598780fb4a2SCy Schubert os_free(eapKeyData); 1599780fb4a2SCy Schubert return NULL; 1600780fb4a2SCy Schubert } 1601e28a4053SRui Paulo *len = EAP_EMSK_LEN; 1602e28a4053SRui Paulo 1603e28a4053SRui Paulo return eapKeyData; 1604e28a4053SRui Paulo } 1605e28a4053SRui Paulo 1606e28a4053SRui Paulo 1607c1d255d3SCy Schubert static bool eap_fast_isSuccess(struct eap_sm *sm, void *priv) 1608e28a4053SRui Paulo { 1609e28a4053SRui Paulo struct eap_fast_data *data = priv; 1610e28a4053SRui Paulo return data->state == SUCCESS; 1611e28a4053SRui Paulo } 1612e28a4053SRui Paulo 1613e28a4053SRui Paulo 16145b9c547cSRui Paulo static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 16155b9c547cSRui Paulo { 16165b9c547cSRui Paulo struct eap_fast_data *data = priv; 16175b9c547cSRui Paulo 16185b9c547cSRui Paulo if (data->state != SUCCESS) 16195b9c547cSRui Paulo return NULL; 16205b9c547cSRui Paulo 16215b9c547cSRui Paulo return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST, 16225b9c547cSRui Paulo len); 16235b9c547cSRui Paulo } 16245b9c547cSRui Paulo 16255b9c547cSRui Paulo 1626e28a4053SRui Paulo int eap_server_fast_register(void) 1627e28a4053SRui Paulo { 1628e28a4053SRui Paulo struct eap_method *eap; 1629e28a4053SRui Paulo 1630e28a4053SRui Paulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1631e28a4053SRui Paulo EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST"); 1632e28a4053SRui Paulo if (eap == NULL) 1633e28a4053SRui Paulo return -1; 1634e28a4053SRui Paulo 1635e28a4053SRui Paulo eap->init = eap_fast_init; 1636e28a4053SRui Paulo eap->reset = eap_fast_reset; 1637e28a4053SRui Paulo eap->buildReq = eap_fast_buildReq; 1638e28a4053SRui Paulo eap->check = eap_fast_check; 1639e28a4053SRui Paulo eap->process = eap_fast_process; 1640e28a4053SRui Paulo eap->isDone = eap_fast_isDone; 1641e28a4053SRui Paulo eap->getKey = eap_fast_getKey; 1642e28a4053SRui Paulo eap->get_emsk = eap_fast_get_emsk; 1643e28a4053SRui Paulo eap->isSuccess = eap_fast_isSuccess; 16445b9c547cSRui Paulo eap->getSessionId = eap_fast_get_session_id; 1645e28a4053SRui Paulo 1646780fb4a2SCy Schubert return eap_server_method_register(eap); 1647e28a4053SRui Paulo } 1648