EAP-FAST: Cleaned up TLV processing and added support for EAP Sequences

Number of TLVs were processed in groups and these cases were now separated
into more flexible processing of one TLV at the time. wpabuf_concat()
function was added to make it easier to concatenate TLVs. EAP Sequences are
now supported in both server and peer code, but the server side is not
enabled by default.
master
Jouni Malinen 16 years ago
parent 2bab8ae401
commit 7914585fe0

@ -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

@ -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);
}

@ -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);
}
}

@ -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;
}

@ -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);
/**

@ -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,

Loading…
Cancel
Save