aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/ChangeLog1
-rw-r--r--src/eap_peer/eap_fast.c178
-rw-r--r--src/eap_server/eap_fast.c72
-rw-r--r--src/utils/wpabuf.c39
-rw-r--r--src/utils/wpabuf.h1
-rw-r--r--wpa_supplicant/ChangeLog3
6 files changed, 189 insertions, 105 deletions
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 5e124ab..9601112 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 a94ed6c..bf94e0f 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.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.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) {
- resp = eap_fast_process_eap_payload_tlv(
+ tmp = 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) {
- 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);
+ 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);
+ }
+
+ 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);
}
- 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);
+ 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 a7ade96..170f3fa 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;
- }
- /* 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 || 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);
+ }
+
+ 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 5b50b30..3719aae 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
*
* 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 22f2794..724412e 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 969b858..8e80802 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,