aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2008-05-28 06:57:17 (GMT)
committerJouni Malinen <j@w1.fi>2008-05-28 06:57:17 (GMT)
commit34f564dbd5168626da55a7119b04832e98793160 (patch)
tree097c083caf15d41953b0e455356c6f875883d9ac
parentab17e3f2b7d036abc5d0883f32841095a85aaf75 (diff)
downloadhostap-06-34f564dbd5168626da55a7119b04832e98793160.zip
hostap-06-34f564dbd5168626da55a7119b04832e98793160.tar.gz
hostap-06-34f564dbd5168626da55a7119b04832e98793160.tar.bz2
Redesigned EAP-TLS/PEAP/TTLS/FAST fragmentation/reassembly
Fragmentation is now done as a separate step to clean up the design and to allow the same code to be used in both Phase 1 and Phase 2. This adds support for fragmenting EAP-PEAP/TTLS/FAST Phase 2 (tunneled) data.
-rw-r--r--hostapd/ChangeLog2
-rw-r--r--src/eap_server/eap_fast.c175
-rw-r--r--src/eap_server/eap_peap.c180
-rw-r--r--src/eap_server/eap_tls.c72
-rw-r--r--src/eap_server/eap_tls_common.c360
-rw-r--r--src/eap_server/eap_tls_common.h34
-rw-r--r--src/eap_server/eap_ttls.c209
7 files changed, 447 insertions, 585 deletions
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 56673de..5146d1a 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -10,6 +10,8 @@ ChangeLog for hostapd
and IF-TNCCS interfaces from TNCS)
* added support for optional cryptobinding with PEAPv0
* added fragmentation support for EAP-TNC
+ * added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
+ data
2008-02-22 - v0.6.3
* fixed Reassociation Response callback processing when using internal
diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_fast.c
index c50ffd2..6bcfabc 100644
--- a/src/eap_server/eap_fast.c
+++ b/src/eap_server/eap_fast.c
@@ -533,63 +533,6 @@ static int eap_fast_phase1_done(struct eap_sm *sm, struct eap_fast_data *data)
}
-static struct wpabuf * eap_fast_build_req(struct eap_sm *sm,
- struct eap_fast_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_FAST,
- data->fast_version, id, &req);
-
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- if (eap_fast_phase1_done(sm, data) < 0) {
- os_free(req);
- return NULL;
- }
- }
-
- if (res == 1)
- return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
- data->fast_version);
- return req;
-}
-
-
-static struct wpabuf * eap_fast_encrypt(struct eap_sm *sm,
- struct eap_fast_data *data,
- u8 id, u8 *plain, size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->fast_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
struct eap_fast_data *data,
u8 id)
@@ -827,16 +770,28 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_fast_data *data = priv;
- struct wpabuf *req;
+ struct wpabuf *req = NULL;
struct wpabuf *encr;
- if (data->state == START)
- return eap_fast_build_start(sm, data, id);
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
+ data->fast_version);
+ }
- if (data->state == PHASE1)
- return eap_fast_build_req(sm, data, id);
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id);
+ }
switch (data->state) {
+ case START:
+ return eap_fast_build_start(sm, data, id);
+ case PHASE1:
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ if (eap_fast_phase1_done(sm, data) < 0)
+ return NULL;
+ }
+ break;
case PHASE2_ID:
case PHASE2_METHOD:
req = eap_fast_build_phase2_req(sm, data, id);
@@ -864,16 +819,21 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
return NULL;
}
- if (req == NULL)
- return NULL;
+ if (req) {
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 "
+ "TLVs", req);
+ encr = eap_server_tls_encrypt(sm, &data->ssl,
+ wpabuf_mhead(req),
+ wpabuf_len(req));
+ wpabuf_free(req);
- wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
- req);
- encr = eap_fast_encrypt(sm, data, id, wpabuf_mhead(req),
- wpabuf_len(req));
- wpabuf_free(req);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = encr;
+ }
- return encr;
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+ data->fast_version, id);
}
@@ -1305,11 +1265,16 @@ static void eap_fast_process_phase2_tlvs(struct eap_sm *sm,
static void eap_fast_process_phase2(struct eap_sm *sm,
struct eap_fast_data *data,
- const u8 *in_data, size_t in_len)
+ struct wpabuf *in_buf)
{
u8 *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
size_t buf_len;
+ u8 *in_data;
+ size_t in_len;
+
+ in_data = wpabuf_mhead(in_buf);
+ in_len = wpabuf_len(in_buf);
wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1325,15 +1290,7 @@ static void eap_fast_process_phase2(struct eap_sm *sm,
return;
}
- /* FIX: get rid of const -> non-const typecast */
- res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &in_data,
- &in_len);
- if (res < 0 || res == 1)
- return;
-
buf_len = in_len;
- if (data->ssl.tls_in_total > buf_len)
- buf_len = data->ssl.tls_in_total;
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
@@ -1344,9 +1301,6 @@ static void eap_fast_process_phase2(struct eap_sm *sm,
buf_len *= 3;
in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory "
"for decryption");
return;
@@ -1355,9 +1309,6 @@ static void eap_fast_process_phase2(struct eap_sm *sm,
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
in_decrypted, buf_len);
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
if (len_decrypted < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
"data");
@@ -1407,49 +1358,17 @@ static int eap_fast_process_version(struct eap_fast_data *data,
}
-static int eap_fast_process_length(struct eap_fast_data *data,
- const u8 **pos, size_t *left)
-{
- u32 tls_msg_len;
-
- if (*left < 4) {
- wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
- "length");
- eap_fast_state(data, FAILURE);
- return -1;
- }
-
- tls_msg_len = WPA_GET_BE32(*pos);
- wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
- tls_msg_len);
-
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
-
- *pos += 4;
- *left -= 4;
-
- return 0;
-}
-
-
static int eap_fast_process_phase1(struct eap_sm *sm,
- struct eap_fast_data *data,
- const u8 *pos, size_t left)
+ struct eap_fast_data *data)
{
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
eap_fast_state(data, FAILURE);
return -1;
}
if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
- data->ssl.tls_out_len > 0)
+ wpabuf_len(data->ssl.out_buf) > 0)
return 1;
/*
@@ -1504,6 +1423,7 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
const u8 *pos;
u8 flags;
size_t left;
+ int ret;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData,
&left);
@@ -1518,13 +1438,16 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
if (eap_fast_process_version(data, flags & EAP_PEAP_VERSION_MASK))
return;
- if ((flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) &&
- eap_fast_process_length(data, &pos, &left))
+ ret = eap_server_tls_reassemble(&data->ssl, flags, &pos, &left);
+ if (ret < 0) {
+ eap_fast_state(data, FAILURE);
+ return;
+ } else if (ret == 1)
return;
switch (data->state) {
case PHASE1:
- if (eap_fast_process_phase1(sm, data, pos, left))
+ if (eap_fast_process_phase1(sm, data))
break;
/* fall through to PHASE2_START */
@@ -1535,7 +1458,7 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
case PHASE2_METHOD:
case CRYPTO_BINDING:
case REQUEST_PAC:
- eap_fast_process_phase2(sm, data, pos, left);
+ eap_fast_process_phase2(sm, data, data->ssl.in_buf);
break;
default:
wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
@@ -1548,6 +1471,8 @@ static void eap_fast_process(struct eap_sm *sm, void *priv,
"in TLS processing");
eap_fast_state(data, FAILURE);
}
+
+ eap_server_tls_free_in_buf(&data->ssl);
}
diff --git a/src/eap_server/eap_peap.c b/src/eap_server/eap_peap.c
index 77c254a..4f0248c 100644
--- a/src/eap_server/eap_peap.c
+++ b/src/eap_server/eap_peap.c
@@ -230,64 +230,6 @@ static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
}
-static struct wpabuf * eap_peap_build_req(struct eap_sm *sm,
- struct eap_peap_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
- data->peap_version, id, &req);
-
- if (data->peap_version < 2 &&
- tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, starting "
- "Phase2");
- eap_peap_state(data, PHASE2_START);
- }
-
- if (res == 1)
- return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
- data->peap_version);
- return req;
-}
-
-
-static struct wpabuf * eap_peap_encrypt(struct eap_sm *sm,
- struct eap_peap_data *data,
- u8 id, const u8 *plain,
- size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->peap_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
struct eap_peap_data *data,
u8 id)
@@ -317,7 +259,7 @@ static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
req_len -= sizeof(struct eap_hdr);
}
- encr_req = eap_peap_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
wpabuf_free(buf);
return encr_req;
@@ -355,7 +297,7 @@ static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
req += sizeof(struct eap_hdr);
req_len -= sizeof(struct eap_hdr);
- encr_req = eap_peap_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
wpabuf_free(buf);
return encr_req;
@@ -577,8 +519,8 @@ static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
buf);
- encr_req = eap_peap_encrypt(sm, data, id, wpabuf_head(buf),
- wpabuf_len(buf));
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return encr_req;
@@ -605,7 +547,7 @@ static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
(u8 *) hdr, req_len);
- encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len);
os_free(hdr);
return encr_req;
@@ -616,30 +558,66 @@ static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_peap_data *data = priv;
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
+ data->peap_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id);
+ }
+
switch (data->state) {
case START:
return eap_peap_build_start(sm, data, id);
case PHASE1:
case PHASE1_ID2:
- return eap_peap_build_req(sm, data, id);
+ if (data->peap_version < 2 &&
+ tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
+ "starting Phase2");
+ eap_peap_state(data, PHASE2_START);
+ }
+ break;
case PHASE2_ID:
case PHASE2_METHOD:
- return eap_peap_build_phase2_req(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_req(sm, data, id);
+ break;
#ifdef EAP_TNC
case PHASE2_SOH:
- return eap_peap_build_phase2_soh(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_soh(sm, data, id);
+ break;
#endif /* EAP_TNC */
case PHASE2_TLV:
- return eap_peap_build_phase2_tlv(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_tlv(sm, data, id);
+ break;
case SUCCESS_REQ:
- return eap_peap_build_phase2_term(sm, data, id, 1);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+ 1);
+ break;
case FAILURE_REQ:
- return eap_peap_build_phase2_term(sm, data, id, 0);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+ 0);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+ data->peap_version, id);
}
@@ -1135,7 +1113,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
const u8 *in_data, size_t in_len)
{
struct wpabuf *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
const struct eap_hdr *hdr;
size_t buf_len, len;
@@ -1152,15 +1130,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
return;
}
- /* FIX: get rid of const -> non-const typecast */
- res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &in_data,
- &in_len);
- if (res < 0 || res == 1)
- return;
-
buf_len = in_len;
- if (data->ssl.tls_in_total > buf_len)
- buf_len = data->ssl.tls_in_total;
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
@@ -1171,9 +1141,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
buf_len *= 3;
in_decrypted = wpabuf_alloc(buf_len);
if (in_decrypted == NULL) {
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
"for decryption");
return;
@@ -1183,9 +1150,6 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
in_data, in_len,
wpabuf_mhead(in_decrypted),
buf_len);
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
if (len_decrypted < 0) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
"data");
@@ -1315,7 +1279,6 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm,
{
struct wpabuf *buf, *buf2;
int res;
- u8 *tls_out;
wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
"payload in the same message");
@@ -1358,18 +1321,11 @@ static int eap_peapv2_start_phase2(struct eap_sm *sm,
buf);
/* Append TLS data into the pending buffer after the Server Finished */
- tls_out = os_realloc(data->ssl.tls_out,
- data->ssl.tls_out_len + wpabuf_len(buf));
- if (tls_out == NULL) {
+ if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
wpabuf_free(buf);
return -1;
}
-
- os_memcpy(tls_out + data->ssl.tls_out_len, wpabuf_head(buf),
- wpabuf_len(buf));
- data->ssl.tls_out = tls_out;
- data->ssl.tls_out_len += wpabuf_len(buf);
-
+ wpabuf_put_buf(data->ssl.out_buf, buf);
wpabuf_free(buf);
return 0;
@@ -1383,8 +1339,8 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
const u8 *pos;
u8 flags;
size_t left;
- unsigned int tls_msg_len;
int peer_version;
+ int ret;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData,
&left);
@@ -1409,33 +1365,17 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
peer_version, data->peap_version, peer_version);
data->peap_version = peer_version;
}
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
- "length");
- eap_peap_state(data, FAILURE);
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
+
+ ret = eap_server_tls_reassemble(&data->ssl, flags, &pos, &left);
+ if (ret < 0) {
+ eap_peap_state(data, FAILURE);
+ return;
+ } else if (ret == 1)
+ return;
switch (data->state) {
case PHASE1:
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
- 0) {
- wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
- "failed");
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
eap_peap_state(data, FAILURE);
break;
}
@@ -1476,6 +1416,8 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
"in TLS processing");
eap_peap_state(data, FAILURE);
}
+
+ eap_server_tls_free_in_buf(&data->ssl);
}
diff --git a/src/eap_server/eap_tls.c b/src/eap_server/eap_tls.c
index 2bc96bd..c52ec5a 100644
--- a/src/eap_server/eap_tls.c
+++ b/src/eap_server/eap_tls.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-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
@@ -80,40 +80,36 @@ static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
}
-static struct wpabuf * eap_tls_build_req(struct eap_sm *sm,
- struct eap_tls_data *data, u8 id)
+static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
- int res;
- struct wpabuf *req;
+ struct eap_tls_data *data = priv;
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TLS, 0,
- id, &req);
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
- data->state = SUCCESS;
- }
-
- if (res == 1)
+ if (data->ssl.state == FRAG_ACK) {
return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
- return req;
-}
-
+ }
-static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
- struct eap_tls_data *data = priv;
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
+ id);
+ }
switch (data->state) {
case START:
return eap_tls_build_start(sm, data, id);
case CONTINUE:
- return eap_tls_build_req(sm, data, id);
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+ data->state = SUCCESS;
+ }
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
}
@@ -140,50 +136,34 @@ static void eap_tls_process(struct eap_sm *sm, void *priv,
const u8 *pos;
u8 flags;
size_t left;
- unsigned int tls_msg_len;
+ int ret;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &left);
if (pos == NULL || left < 1)
return; /* Should not happen - frame already validated */
-
flags = *pos++;
left--;
wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) wpabuf_len(respData),
flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
- "length");
- data->state = FAILURE;
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
- wpa_printf(MSG_INFO, "EAP-TLS: TLS processing failed");
+ ret = eap_server_tls_reassemble(&data->ssl, flags, &pos, &left);
+ if (ret < 0) {
data->state = FAILURE;
return;
- }
+ } else if (ret == 1)
+ return;
+
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+ data->state = FAILURE;
if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
wpa_printf(MSG_INFO, "EAP-TLS: Locally detected fatal error "
"in TLS processing");
data->state = FAILURE;
- return;
}
+
+ eap_server_tls_free_in_buf(&data->ssl);
}
diff --git a/src/eap_server/eap_tls_common.c b/src/eap_server/eap_tls_common.c
index f741133..7cd1d03 100644
--- a/src/eap_server/eap_tls_common.c
+++ b/src/eap_server/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-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
@@ -58,8 +58,8 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
tls_connection_deinit(sm->ssl_ctx, data->conn);
- os_free(data->tls_in);
- os_free(data->tls_out);
+ os_free(data->in_buf);
+ os_free(data->out_buf);
}
@@ -106,188 +106,252 @@ fail:
}
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
- struct eap_ssl_data *data,
- u8 **in_data, size_t *in_len)
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+ int eap_type, int peap_version, u8 id)
{
- u8 *buf;
-
- if (data->tls_in_left > *in_len || data->tls_in) {
- if (*in_len == 0) {
- wpa_printf(MSG_INFO, "SSL: Empty fragment when trying "
- "to reassemble");
- return -1;
- }
- if (data->tls_in_len + *in_len > 65536) {
- /* Limit length to avoid rogue peers from causing large
- * memory allocations. */
- os_free(data->tls_in);
- data->tls_in = NULL;
- data->tls_in_len = 0;
- wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
- " over 64 kB)");
- return -1;
- }
- buf = os_realloc(data->tls_in, data->tls_in_len + *in_len);
- if (buf == NULL) {
- os_free(data->tls_in);
- data->tls_in = NULL;
- data->tls_in_len = 0;
- wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
- "for TLS data");
- return -1;
- }
- os_memcpy(buf + data->tls_in_len, *in_data, *in_len);
- data->tls_in = buf;
- data->tls_in_len += *in_len;
- if (*in_len > data->tls_in_left) {
- wpa_printf(MSG_INFO, "SSL: more data than TLS message "
- "length indicated");
- data->tls_in_left = 0;
- return -1;
- }
- data->tls_in_left -= *in_len;
- if (data->tls_in_left > 0) {
- wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
- "data", (unsigned long) data->tls_in_left);
- return 1;
+ struct wpabuf *req;
+ u8 flags;
+ size_t send_len, plen;
+
+ wpa_printf(MSG_DEBUG, "SSL: Generating Request");
+
+ flags = peap_version;
+ send_len = wpabuf_len(data->out_buf) - data->out_used;
+ if (1 + send_len > data->tls_out_limit) {
+ send_len = data->tls_out_limit - 1;
+ flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ if (data->out_used == 0) {
+ flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+ send_len -= 4;
}
+ }
- *in_data = data->tls_in;
- *in_len = data->tls_in_len;
- } else
- data->tls_in_left = 0;
+ plen = 1 + send_len;
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+ plen += 4;
- return 0;
+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
+ EAP_CODE_REQUEST, id);
+ if (req == NULL)
+ return NULL;
+
+ wpabuf_put_u8(req, flags); /* Flags */
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+ wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+ wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+ send_len);
+ data->out_used += send_len;
+
+ if (data->out_used == wpabuf_len(data->out_buf)) {
+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+ "(message sent completely)",
+ (unsigned long) send_len);
+ wpabuf_free(data->out_buf);
+ data->out_buf = NULL;
+ data->out_used = 0;
+ data->state = MSG;
+ } else {
+ wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+ "(%lu more to send)", (unsigned long) send_len,
+ (unsigned long) wpabuf_len(data->out_buf) -
+ data->out_used);
+ data->state = WAIT_FRAG_ACK;
+ }
+
+ return req;
}
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- const u8 *in_data, size_t in_len)
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int peap_version)
{
- WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
-
- if (data->tls_out_len == 0) {
- u8 *_in_data = (u8 *) in_data; /* FIX: get rid of the typecast
- */
- /* No more data to send out - expect to receive more data from
- * the peer. */
- int res = eap_server_tls_data_reassemble(sm, data, &_in_data,
- &in_len);
- if (res < 0 || res == 1) {
- wpa_printf(MSG_DEBUG, "SSL: data reassembly failed");
- return res;
- }
- /* Full TLS message reassembled - continue handshake processing
- */
- if (data->tls_out) {
- /* This should not happen.. */
- wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
- "pending tls_out data even though "
- "tls_out_len = 0");
- os_free(data->tls_out);
- WPA_ASSERT(data->tls_out == NULL);
- }
- data->tls_out = tls_connection_server_handshake(
- sm->ssl_ctx, data->conn, _in_data, in_len,
- &data->tls_out_len);
-
- /* Clear reassembled input data (if the buffer was needed). */
- data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
- os_free(data->tls_in);
- data->tls_in = NULL;
+ struct wpabuf *req;
+
+ req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
+ id);
+ if (req == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+ wpabuf_put_u8(req, peap_version); /* Flags */
+ return req;
+}
+
+
+static int eap_server_tls_process_cont(struct eap_ssl_data *data,
+ const u8 *buf, size_t len)
+{
+ /* Process continuation of a pending message */
+ if (len > wpabuf_tailroom(data->in_buf)) {
+ wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
+ return -1;
}
- if (data->tls_out == NULL) {
- wpa_printf(MSG_DEBUG, "SSL: failed to generate output data");
- data->tls_out_len = 0;
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
+ "bytes more", (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
+
+ return 0;
+}
+
+
+static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
+ u8 flags, u32 message_length,
+ const u8 *buf, size_t len)
+{
+ /* Process a fragment that is not the last one of the message */
+ if (data->in_buf == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
+ wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
+ "fragmented packet");
return -1;
}
- if (data->tls_out_len == 0) {
- /* TLS negotiation should now be complete since all other cases
- * needing more that should have been catched above based on
- * the TLS Message Length field. */
- wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
- os_free(data->tls_out);
- data->tls_out = NULL;
-
- if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) {
- wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal "
- "alert - abort handshake");
+
+ if (data->in_buf == NULL) {
+ /* First fragment of the message */
+
+ /* Limit length to avoid rogue peers from causing large
+ * memory allocations. */
+ if (message_length > 65536) {
+ wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
+ " over 64 kB)");
return -1;
}
- return 1;
+ data->in_buf = wpabuf_alloc(message_length);
+ if (data->in_buf == NULL) {
+ wpa_printf(MSG_DEBUG, "SSL: No memory for message");
+ return -1;
+ }
+ wpabuf_put_data(data->in_buf, buf, len);
+ wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
+ "fragment, waiting for %lu bytes more",
+ (unsigned long) len,
+ (unsigned long) wpabuf_tailroom(data->in_buf));
}
- wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
- "%lu bytes)",
- (unsigned long) data->tls_out_len - data->tls_out_pos,
- (unsigned long) data->tls_out_len);
+ return 0;
+}
+
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+ u8 *next;
+ size_t next_len;
+
+ next = tls_connection_server_handshake(
+ sm->ssl_ctx, data->conn,
+ wpabuf_mhead(data->in_buf),
+ wpabuf_len(data->in_buf),
+ &next_len);
+ if (next == NULL) {
+ wpa_printf(MSG_INFO, "SSL: TLS processing failed");
+ return -1;
+ }
+ if (data->out_buf) {
+ /* This should not happen.. */
+ wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
+ "processing new message");
+ os_free(data->out_buf);
+ WPA_ASSERT(data->out_buf == NULL);
+ }
+ data->out_buf = wpabuf_alloc_ext_data(next, next_len);
+ if (data->out_buf == NULL) {
+ os_free(next);
+ return -1;
+ }
return 0;
}
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
- struct eap_ssl_data *data,
- int eap_type, int peap_version, u8 id,
- struct wpabuf **out_data)
+int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
+ const u8 **pos, size_t *left)
{
- size_t len;
- u8 *flags;
- struct wpabuf *req;
- int incl_len;
+ unsigned int tls_msg_len = 0;
+ const u8 *end = *pos + *left;
- incl_len = data->tls_out_pos == 0 &&
- data->tls_out_len > data->tls_out_limit;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
- 1 + (incl_len ? 4 : 0) + data->tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (req == NULL) {
- *out_data = NULL;
- return -1;
+ if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (*left < 4) {
+ wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+ "length");
+ return -1;
+ }
+ tls_msg_len = WPA_GET_BE32(*pos);
+ wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
+ tls_msg_len);
+ *pos += 4;
+ *left -= 4;
}
- flags = wpabuf_put(req, 1);
- *flags = peap_version;
- if (incl_len) {
- *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
- wpabuf_put_be32(req, data->tls_out_len);
+
+ wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
+ "Message Length %u", flags, tls_msg_len);
+
+ if (data->state == WAIT_FRAG_ACK) {
+ if (*left != 0) {
+ wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
+ "WAIT_FRAG_ACK state");
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
+ return 1;
}
- len = data->tls_out_len - data->tls_out_pos;
- if (len > data->tls_out_limit) {
- *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
- len = data->tls_out_limit;
- wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
- "will follow", (unsigned long) len);
+ if (data->in_buf &&
+ eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
+ return -1;
+
+ if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
+ if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
+ *pos, end - *pos) < 0)
+ return -1;
+
+ data->state = FRAG_ACK;
+ return 1;
}
- wpabuf_put_data(req, &data->tls_out[data->tls_out_pos], len);
- data->tls_out_pos += len;
- eap_update_len(req);
- *out_data = req;
+ if (data->state == FRAG_ACK) {
+ wpa_printf(MSG_DEBUG, "SSL: All fragments received");
+ data->state = MSG;
+ }
- if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
- data->tls_out_len = 0;
- data->tls_out_pos = 0;
- os_free(data->tls_out);
- data->tls_out = NULL;
+ if (data->in_buf == NULL) {
+ /* Wrap unfragmented messages as wpabuf without extra copy */
+ wpabuf_set(&data->tmpbuf, *pos, end - *pos);
+ data->in_buf = &data->tmpbuf;
}
return 0;
}
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int peap_version)
+void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
{
- struct wpabuf *req;
+ if (data->in_buf != &data->tmpbuf)
+ wpabuf_free(data->in_buf);
+ data->in_buf = NULL;
+}
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
- id);
- if (req == NULL)
+
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ const u8 *plain, size_t plain_len)
+{
+ int res;
+ struct wpabuf *buf;
+ size_t buf_len;
+
+ /* reserve some extra room for encryption overhead */
+ buf_len = plain_len + 200;
+ buf = wpabuf_alloc(buf_len);
+ res = tls_connection_encrypt(sm->ssl_ctx, data->conn,
+ plain, plain_len, wpabuf_put(buf, 0),
+ buf_len);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
+ wpabuf_free(buf);
return NULL;
- wpa_printf(MSG_DEBUG, "SSL: Building ACK");
- wpabuf_put_u8(req, peap_version); /* Flags */
- return req;
+ }
+
+ wpabuf_put(buf, res);
+
+ return buf;
}
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 2470faa..4d89f77 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-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
@@ -18,18 +18,17 @@
struct eap_ssl_data {
struct tls_connection *conn;
- u8 *tls_out;
- size_t tls_out_len;
- size_t tls_out_pos;
size_t tls_out_limit;
- u8 *tls_in;
- size_t tls_in_len;
- size_t tls_in_left;
- size_t tls_in_total;
int phase2;
struct eap_sm *eap;
+
+ enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
+ struct wpabuf *in_buf;
+ struct wpabuf *out_buf;
+ size_t out_used;
+ struct wpabuf tmpbuf;
};
@@ -48,16 +47,17 @@ int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len);
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
- struct eap_ssl_data *data,
- u8 **in_data, size_t *in_len);
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- const u8 *in_data, size_t in_len);
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
- struct eap_ssl_data *data,
- int eap_type, int peap_version, u8 id,
- struct wpabuf **out_data);
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+ int eap_type, int peap_version,
+ u8 id);
struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type,
int peap_version);
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data);
+int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
+ const u8 **pos, size_t *left);
+void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ const u8 *plain, size_t plain_len);
#endif /* EAP_TLS_COMMON_H */
diff --git a/src/eap_server/eap_ttls.c b/src/eap_server/eap_ttls.c
index 4c71b5f..dab1b26 100644
--- a/src/eap_server/eap_ttls.c
+++ b/src/eap_server/eap_ttls.c
@@ -445,62 +445,6 @@ static struct wpabuf * eap_ttls_build_start(struct eap_sm *sm,
}
-static struct wpabuf * eap_ttls_build_req(struct eap_sm *sm,
- struct eap_ttls_data *data, u8 id)
-{
- int res;
- struct wpabuf *req;
-
- res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TTLS,
- data->ttls_version, id, &req);
-
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, starting "
- "Phase2");
- eap_ttls_state(data, PHASE2_START);
- }
-
- if (res == 1)
- return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
- data->ttls_version);
- return req;
-}
-
-
-static struct wpabuf * eap_ttls_encrypt(struct eap_sm *sm,
- struct eap_ttls_data *data,
- u8 id, u8 *plain, size_t plain_len)
-{
- int res;
- struct wpabuf *buf;
-
- /* TODO: add support for fragmentation, if needed. This will need to
- * add TLS Message Length field, if the frame is fragmented. */
- buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
- 1 + data->ssl.tls_out_limit,
- EAP_CODE_REQUEST, id);
- if (buf == NULL)
- return NULL;
-
- wpabuf_put_u8(buf, data->ttls_version);
-
- res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
- plain, plain_len, wpabuf_put(buf, 0),
- data->ssl.tls_out_limit);
- if (res < 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
- "data");
- wpabuf_free(buf);
- return NULL;
- }
-
- wpabuf_put(buf, res);
- eap_update_len(buf);
-
- return buf;
-}
-
-
static struct wpabuf * eap_ttls_build_phase2_eap_req(
struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
{
@@ -528,7 +472,7 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req(
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase "
"2 data", req, req_len);
- encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
wpabuf_free(buf);
return encr_req;
@@ -536,7 +480,7 @@ static struct wpabuf * eap_ttls_build_phase2_eap_req(
static struct wpabuf * eap_ttls_build_phase2_mschapv2(
- struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
+ struct eap_sm *sm, struct eap_ttls_data *data)
{
struct wpabuf *encr_req;
u8 *req, *pos, *end;
@@ -570,7 +514,7 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
"data", req, req_len);
- encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+ encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
os_free(req);
return encr_req;
@@ -578,20 +522,16 @@ static struct wpabuf * eap_ttls_build_phase2_mschapv2(
static struct wpabuf * eap_ttls_build_phase_finished(
- struct eap_sm *sm, struct eap_ttls_data *data, u8 id, int final)
+ struct eap_sm *sm, struct eap_ttls_data *data, int final)
{
int len;
struct wpabuf *req;
const int max_len = 300;
- len = 1 + max_len;
- req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, len,
- EAP_CODE_REQUEST, id);
+ req = wpabuf_alloc(max_len);
if (req == NULL)
return NULL;
- wpabuf_put_u8(req, data->ttls_version);
-
len = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
data->ssl.conn, final,
wpabuf_mhead(req),
@@ -601,7 +541,6 @@ static struct wpabuf * eap_ttls_build_phase_finished(
return NULL;
}
wpabuf_put(req, len);
- eap_update_len(req);
return req;
}
@@ -611,22 +550,50 @@ static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_ttls_data *data = priv;
+ if (data->ssl.state == FRAG_ACK) {
+ return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
+ data->ttls_version);
+ }
+
+ if (data->ssl.state == WAIT_FRAG_ACK) {
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id);
+ }
+
switch (data->state) {
case START:
return eap_ttls_build_start(sm, data, id);
case PHASE1:
- return eap_ttls_build_req(sm, data, id);
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
+ "starting Phase2");
+ eap_ttls_state(data, PHASE2_START);
+ }
+ break;
case PHASE2_METHOD:
- return eap_ttls_build_phase2_eap_req(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase2_eap_req(sm, data,
+ id);
+ break;
case PHASE2_MSCHAPV2_RESP:
- return eap_ttls_build_phase2_mschapv2(sm, data, id);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase2_mschapv2(sm, data);
+ break;
case PHASE_FINISHED:
- return eap_ttls_build_phase_finished(sm, data, id, 1);
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = eap_ttls_build_phase_finished(sm, data, 1);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
__func__, data->state);
return NULL;
}
+
+ return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id);
}
@@ -1148,12 +1115,17 @@ static void eap_ttls_process_phase2_eap(struct eap_sm *sm,
static void eap_ttls_process_phase2(struct eap_sm *sm,
struct eap_ttls_data *data,
- u8 *in_data, size_t in_len)
+ struct wpabuf *in_buf)
{
u8 *in_decrypted;
- int len_decrypted, res;
+ int len_decrypted;
struct eap_ttls_avp parse;
size_t buf_len;
+ u8 *in_data;
+ size_t in_len;
+
+ in_data = wpabuf_mhead(in_buf);
+ in_len = wpabuf_len(in_buf);
wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1169,14 +1141,7 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
return;
}
- res = eap_server_tls_data_reassemble(sm, &data->ssl, &in_data,
- &in_len);
- if (res < 0 || res == 1)
- return;
-
buf_len = in_len;
- if (data->ssl.tls_in_total > buf_len)
- buf_len = data->ssl.tls_in_total;
/*
* Even though we try to disable TLS compression, it is possible that
* this cannot be done with all TLS libraries. Add extra buffer space
@@ -1187,9 +1152,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
buf_len *= 3;
in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory "
"for decryption");
return;
@@ -1198,9 +1160,6 @@ static void eap_ttls_process_phase2(struct eap_sm *sm,
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
in_data, in_len,
in_decrypted, buf_len);
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
if (len_decrypted < 0) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
"data");
@@ -1313,6 +1272,29 @@ static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
}
+static void eap_ttls_process_version(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ int peer_version)
+{
+ if (peer_version < data->ttls_version) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
+ "use version %d",
+ peer_version, data->ttls_version, peer_version);
+ data->ttls_version = peer_version;
+ }
+
+ if (data->ttls_version > 0 && !data->tls_ia_configured) {
+ if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
+ "TLS/IA");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+ data->tls_ia_configured = 1;
+ }
+}
+
+
static void eap_ttls_process(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
@@ -1320,8 +1302,7 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
const u8 *pos;
u8 flags;
size_t left;
- unsigned int tls_msg_len;
- int peer_version;
+ int ret;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData,
&left);
@@ -1332,59 +1313,25 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
"Flags 0x%02x", (unsigned long) wpabuf_len(respData),
flags);
- peer_version = flags & EAP_PEAP_VERSION_MASK;
- if (peer_version < data->ttls_version) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
- "use version %d",
- peer_version, data->ttls_version, peer_version);
- data->ttls_version = peer_version;
- }
- if (data->ttls_version > 0 && !data->tls_ia_configured) {
- if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
- "TLS/IA");
- eap_ttls_state(data, FAILURE);
- return;
- }
- data->tls_ia_configured = 1;
- }
+ eap_ttls_process_version(sm, data, flags & EAP_PEAP_VERSION_MASK);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
- "length");
- eap_ttls_state(data, FAILURE);
- return;
- }
- tls_msg_len = WPA_GET_BE32(pos);
- wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- os_free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
+ ret = eap_server_tls_reassemble(&data->ssl, flags, &pos, &left);
+ if (ret < 0) {
+ eap_ttls_state(data, FAILURE);
+ return;
+ } else if (ret == 1)
+ return;
switch (data->state) {
case PHASE1:
- if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
- 0) {
- wpa_printf(MSG_INFO, "EAP-TTLS: TLS processing "
- "failed");
+ if (eap_server_tls_phase1(sm, &data->ssl) < 0)
eap_ttls_state(data, FAILURE);
- }
break;
case PHASE2_START:
case PHASE2_METHOD:
case PHASE_FINISHED:
- /* FIX: get rid of const->non-const typecast */
- eap_ttls_process_phase2(sm, data, (u8 *) pos, left);
+ eap_ttls_process_phase2(sm, data, data->ssl.in_buf);
eap_ttls_start_tnc(sm, data);
break;
case PHASE2_MSCHAPV2_RESP:
@@ -1417,6 +1364,8 @@ static void eap_ttls_process(struct eap_sm *sm, void *priv,
"in TLS processing");
eap_ttls_state(data, FAILURE);
}
+
+ eap_server_tls_free_in_buf(&data->ssl);
}