diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index 5e124abd5..960111258 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -3,6 +3,7 @@ ChangeLog for hostapd ????-??-?? - v0.6.4 * added peer identity into EAP-FAST PAC-Opaque and skip Phase 2 Identity Request if identity is already known + * added support for EAP Sequences in EAP-FAST Phase 2 2008-02-22 - v0.6.3 * fixed Reassociation Response callback processing when using internal diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index a94ed6c4f..bf94e0f0c 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -706,17 +706,16 @@ static u8 * eap_fast_write_pac_request(u8 *pos, u16 pac_type) static struct wpabuf * eap_fast_process_crypto_binding( struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, - struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len, int final) + struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len) { struct wpabuf *resp; u8 *pos; - struct eap_tlv_intermediate_result_tlv *rresult; u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN]; - int res, req_tunnel_pac = 0; + int res; size_t len; if (eap_fast_validate_crypto_binding(_bind) < 0) - return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1); + return NULL; if (eap_fast_get_cmk(sm, data, cmk) < 0) return NULL; @@ -735,9 +734,8 @@ static struct wpabuf * eap_fast_process_crypto_binding( _bind->compound_mac, sizeof(cmac)); if (res != 0) { wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match"); - resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1); os_memcpy(_bind->compound_mac, cmac, sizeof(cmac)); - return resp; + return NULL; } /* @@ -745,73 +743,25 @@ static struct wpabuf * eap_fast_process_crypto_binding( * crypto binding to allow server to complete authentication. */ - if (data->current_pac == NULL && data->provisioning && - !data->anon_provisioning) { - /* - * Need to request Tunnel PAC when using authenticated - * provisioning. - */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC"); - req_tunnel_pac = 1; - } - - len = sizeof(*rresult) + sizeof(struct eap_tlv_crypto_binding_tlv); - if (req_tunnel_pac) - len += sizeof(struct eap_tlv_hdr) + - sizeof(struct eap_tlv_request_action_tlv) + - sizeof(struct eap_tlv_pac_type_tlv); + len = sizeof(struct eap_tlv_crypto_binding_tlv); resp = wpabuf_alloc(len); if (resp == NULL) return NULL; - /* - * Both intermediate and final Result TLVs are identical, so ok to use - * the same structure definition for them. - */ - rresult = wpabuf_put(resp, sizeof(*rresult)); - rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | - (final ? EAP_TLV_RESULT_TLV : - EAP_TLV_INTERMEDIATE_RESULT_TLV)); - rresult->length = host_to_be16(2); - rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); - if (!data->anon_provisioning && data->phase2_success && eap_fast_derive_msk(data) < 0) { wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK"); ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; - rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE); data->phase2_success = 0; + wpabuf_free(resp); + return NULL; } pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv)); eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *) pos, _bind, cmk); - if (req_tunnel_pac) { - u8 *pos2; - pos = wpabuf_put(resp, 0); - pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC); - wpabuf_put(resp, pos2 - pos); - } - - if (final && data->phase2_success) { - if (data->anon_provisioning) { - wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated " - "provisioning completed successfully."); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - } else { - wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " - "completed successfully."); - if (data->provisioning) - ret->methodState = METHOD_MAY_CONT; - else - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - } - } - return resp; } @@ -1028,7 +978,7 @@ static struct wpabuf * eap_fast_process_pac(struct eap_sm *sm, os_memset(&entry, 0, sizeof(entry)); if (eap_fast_process_pac_tlv(&entry, pac, pac_len) || eap_fast_process_pac_info(&entry)) - return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); + return NULL; eap_fast_add_pac(&data->pac, &data->current_pac, &entry); eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len); @@ -1140,6 +1090,24 @@ static int eap_fast_encrypt_response(struct eap_sm *sm, } +static struct wpabuf * eap_fast_pac_request(void) +{ + struct wpabuf *tmp; + u8 *pos, *pos2; + + tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) + + sizeof(struct eap_tlv_request_action_tlv) + + sizeof(struct eap_tlv_pac_type_tlv)); + if (tmp == NULL) + return NULL; + + pos = wpabuf_put(tmp, 0); + pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC); + wpabuf_put(tmp, pos2 - pos); + return tmp; +} + + static int eap_fast_process_decrypted(struct eap_sm *sm, struct eap_fast_data *data, struct eap_method_ret *ret, @@ -1147,8 +1115,9 @@ static int eap_fast_process_decrypted(struct eap_sm *sm, struct wpabuf *decrypted, struct wpabuf **out_data) { - struct wpabuf *resp = NULL; + struct wpabuf *resp = NULL, *tmp; struct eap_fast_tlv_parse tlv; + int failed = 0; if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0) return 0; @@ -1168,43 +1137,84 @@ static int eap_fast_process_decrypted(struct eap_sm *sm, req->identifier, out_data); } - if (tlv.eap_payload_tlv) { - resp = eap_fast_process_eap_payload_tlv( - sm, data, ret, req, tlv.eap_payload_tlv, - tlv.eap_payload_tlv_len); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); + if (tlv.crypto_binding) { + tmp = eap_fast_process_crypto_binding(sm, data, ret, + tlv.crypto_binding, + tlv.crypto_binding_len); + if (tmp == NULL) + failed = 1; + else + resp = wpabuf_concat(resp, tmp); } - if (tlv.crypto_binding) { - int final = tlv.result == EAP_TLV_RESULT_SUCCESS; - resp = eap_fast_process_crypto_binding(sm, data, ret, - tlv.crypto_binding, - tlv.crypto_binding_len, - final); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); + if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) { + tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE : + EAP_TLV_RESULT_SUCCESS, 1); + resp = wpabuf_concat(resp, tmp); + } + + if (tlv.eap_payload_tlv) { + tmp = eap_fast_process_eap_payload_tlv( + sm, data, ret, req, tlv.eap_payload_tlv, + tlv.eap_payload_tlv_len); + resp = wpabuf_concat(resp, tmp); } if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) { wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV " "acknowledging success"); - resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); + failed = 1; + } else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) { + tmp = eap_fast_process_pac(sm, data, ret, tlv.pac, + tlv.pac_len); + resp = wpabuf_concat(resp, tmp); } - if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) { - resp = eap_fast_process_pac(sm, data, ret, tlv.pac, - tlv.pac_len); - return eap_fast_encrypt_response(sm, data, resp, - req->identifier, out_data); + if (data->current_pac == NULL && data->provisioning && + !data->anon_provisioning) { + /* + * Need to request Tunnel PAC when using authenticated + * provisioning. + */ + wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC"); + tmp = eap_fast_pac_request(); + resp = wpabuf_concat(resp, tmp); } - wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send " - "empty response packet"); - return eap_fast_encrypt_response(sm, data, wpabuf_alloc(1), - req->identifier, out_data); + if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) { + tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0); + resp = wpabuf_concat(resp, tmp); + } else if (failed) { + tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0); + resp = wpabuf_concat(resp, tmp); + } + + if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed && + tlv.crypto_binding && data->phase2_success) { + if (data->anon_provisioning) { + wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated " + "provisioning completed successfully."); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + } else { + wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " + "completed successfully."); + if (data->provisioning) + ret->methodState = METHOD_MAY_CONT; + else + ret->methodState = METHOD_DONE; + ret->decision = DECISION_UNCOND_SUCC; + } + } + + if (resp == NULL) { + wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send " + "empty response packet"); + resp = wpabuf_alloc(1); + } + + return eap_fast_encrypt_response(sm, data, resp, req->identifier, + out_data); } diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_fast.c index a7ade965d..170f3faf6 100644 --- a/src/eap_server/eap_fast.c +++ b/src/eap_server/eap_fast.c @@ -74,6 +74,7 @@ struct eap_fast_data { struct wpabuf *pending_phase2_resp; u8 *identity; /* from PAC-Opaque */ size_t identity_len; + int eap_seq; }; @@ -614,26 +615,39 @@ static struct wpabuf * eap_fast_build_crypto_binding( struct wpabuf *buf; struct eap_tlv_result_tlv *result; struct eap_tlv_crypto_binding_tlv *binding; - int type; - buf = wpabuf_alloc(sizeof(*result) + sizeof(*binding)); + buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding)); if (buf == NULL) return NULL; - if (data->send_new_pac || data->anon_provisioning) { - type = EAP_TLV_INTERMEDIATE_RESULT_TLV; + if (data->send_new_pac || data->anon_provisioning || + data->phase2_method) data->final_result = 0; - } else { - type = EAP_TLV_RESULT_TLV; + else data->final_result = 1; + + if (!data->final_result || data->eap_seq > 1) { + /* Intermediate-Result */ + wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV " + "(status=SUCCESS)"); + result = wpabuf_put(buf, sizeof(*result)); + result->tlv_type = host_to_be16( + EAP_TLV_TYPE_MANDATORY | + EAP_TLV_INTERMEDIATE_RESULT_TLV); + result->length = host_to_be16(2); + result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); } - /* Result TLV */ - wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)"); - result = wpabuf_put(buf, sizeof(*result)); - result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | type); - result->length = host_to_be16(2); - result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); + if (data->final_result) { + /* Result TLV */ + wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV " + "(status=SUCCESS)"); + result = wpabuf_put(buf, sizeof(*result)); + result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | + EAP_TLV_RESULT_TLV); + result->length = host_to_be16(2); + result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS); + } /* Crypto-Binding TLV */ binding = wpabuf_put(buf, sizeof(*binding)); @@ -828,6 +842,16 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id) break; case CRYPTO_BINDING: req = eap_fast_build_crypto_binding(sm, data); + if (data->phase2_method) { + /* + * Include the start of the next EAP method in the + * sequence in the same message with Crypto-Binding to + * save a round-trip. + */ + struct wpabuf *eap; + eap = eap_fast_build_phase2_req(sm, data, id); + req = wpabuf_concat(req, eap); + } break; case REQUEST_PAC: req = eap_fast_build_pac(sm, data); @@ -981,9 +1005,13 @@ static void eap_fast_process_phase2_response(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type); break; case PHASE2_METHOD: + case CRYPTO_BINDING: eap_fast_update_icmk(sm, data); eap_fast_state(data, CRYPTO_BINDING); + data->eap_seq++; next_type = EAP_TYPE_NONE; + /* TODO: could start another EAP method in sequence by setting + * next_type to the selected method */ break; case FAILURE: break; @@ -1199,11 +1227,6 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, return; } - if (tlv.eap_payload_tlv) { - eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, - tlv.eap_payload_tlv_len); - } - if (check_crypto_binding) { if (tlv.crypto_binding == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding " @@ -1235,7 +1258,11 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, } wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV " - "received - authentication completed successfully"); + "received"); + if (data->final_result) { + wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication " + "completed successfully"); + } if (data->anon_provisioning || (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV && @@ -1248,9 +1275,14 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered " "re-keying of Tunnel PAC"); eap_fast_state(data, REQUEST_PAC); - } else + } else if (data->final_result) eap_fast_state(data, SUCCESS); } + + if (tlv.eap_payload_tlv) { + eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv, + tlv.eap_payload_tlv_len); + } } diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c index 5b50b30b0..3719aaeed 100644 --- a/src/utils/wpabuf.c +++ b/src/utils/wpabuf.c @@ -1,6 +1,6 @@ /* * Dynamic data buffer - * Copyright (c) 2007, Jouni Malinen + * Copyright (c) 2007-2008, Jouni Malinen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -123,3 +123,40 @@ void * wpabuf_put(struct wpabuf *buf, size_t len) } return tmp; } + + +/** + * wpabuf_concat - Concatenate two buffers into a newly allocated one + * @a: First buffer + * @b: Second buffer + * Returns: wpabuf with concatenated a + b data or %NULL on failure + * + * Both buffers a and b will be freed regardless of the return value. Input + * buffers can be %NULL which is interpreted as an empty buffer. + */ +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) +{ + struct wpabuf *n = NULL; + size_t len = 0; + + if (b == NULL) + return a; + + if (a) + len += wpabuf_len(a); + if (b) + len += wpabuf_len(b); + + n = wpabuf_alloc(len); + if (n) { + if (a) + wpabuf_put_buf(n, a); + if (b) + wpabuf_put_buf(n, b); + } + + wpabuf_free(a); + wpabuf_free(b); + + return n; +} diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h index 22f27946e..724412e31 100644 --- a/src/utils/wpabuf.h +++ b/src/utils/wpabuf.h @@ -36,6 +36,7 @@ struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); struct wpabuf * wpabuf_dup(const struct wpabuf *src); void wpabuf_free(struct wpabuf *buf); void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); /** diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog index 969b858a1..8e80802ef 100644 --- a/wpa_supplicant/ChangeLog +++ b/wpa_supplicant/ChangeLog @@ -1,5 +1,8 @@ ChangeLog for wpa_supplicant +????-??-?? - v0.6.4 + * added support for EAP Sequences in EAP-FAST Phase 2 + 2008-02-22 - v0.6.3 * removed 'nai' and 'eappsk' network configuration variables that were previously used for configuring user identity and key for EAP-PSK,