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