eapol: Propagate noencrypt and use it

We were not using or taking into account the noencrypt flag obtained
from the kernel via CONTROL_PORT events.  For the most part this still
worked as the kernel would never include NO_ENCRYPT flag (due to a bug).
However, this was actually incorrect and led to loss of synchronization
between the AP and STA 4-Way handshake state machines when certain
packets were lost and had to be re-transmitted.
This commit is contained in:
Denis Kenzior 2019-08-27 20:41:03 -05:00
parent ebad9bf9be
commit b3881b84c1
2 changed files with 59 additions and 23 deletions

View File

@ -833,8 +833,10 @@ struct eapol_sm {
bool use_eapol_start:1; bool use_eapol_start:1;
bool require_handshake:1; bool require_handshake:1;
bool eap_exchanged:1; bool eap_exchanged:1;
bool last_eap_unencrypted:1;
struct eap_state *eap; struct eap_state *eap;
struct eapol_frame *early_frame; struct eapol_frame *early_frame;
bool early_frame_unencrypted : 1;
uint32_t watch_id; uint32_t watch_id;
uint8_t installed_gtk_len; uint8_t installed_gtk_len;
uint8_t installed_gtk[CRYPTO_MAX_GTK_LEN]; uint8_t installed_gtk[CRYPTO_MAX_GTK_LEN];
@ -962,22 +964,32 @@ static void eapol_install_igtk(struct eapol_sm *sm, uint8_t igtk_key_index,
sm->installed_igtk_len = igtk_len - 6; sm->installed_igtk_len = igtk_len - 6;
} }
static void send_eapol_start(struct l_timeout *timeout, void *user_data) static void __send_eapol_start(struct eapol_sm *sm, bool noencrypt)
{ {
struct eapol_sm *sm = user_data;
uint8_t buf[sizeof(struct eapol_frame)]; uint8_t buf[sizeof(struct eapol_frame)];
struct eapol_frame *frame = (struct eapol_frame *) buf; struct eapol_frame *frame = (struct eapol_frame *) buf;
handshake_event(sm->handshake, HANDSHAKE_EVENT_STARTED, NULL); handshake_event(sm->handshake, HANDSHAKE_EVENT_STARTED, NULL);
l_timeout_remove(sm->eapol_start_timeout);
sm->eapol_start_timeout = NULL;
frame->header.protocol_version = EAPOL_PROTOCOL_VERSION_2001; frame->header.protocol_version = EAPOL_PROTOCOL_VERSION_2001;
frame->header.packet_type = 1; frame->header.packet_type = 1;
l_put_be16(0, &frame->header.packet_len); l_put_be16(0, &frame->header.packet_len);
eapol_sm_write(sm, frame, false); eapol_sm_write(sm, frame, noencrypt);
}
static void send_eapol_start(struct l_timeout *timeout, void *user_data)
{
struct eapol_sm *sm = user_data;
l_timeout_remove(sm->eapol_start_timeout);
sm->eapol_start_timeout = NULL;
/*
* AP is probably waiting for us to start, so always send unencrypted
* since the key hasn't been established yet
*/
__send_eapol_start(sm, true);
} }
static void eapol_set_key_timeout(struct eapol_sm *sm, static void eapol_set_key_timeout(struct eapol_sm *sm,
@ -1073,7 +1085,8 @@ static void eapol_ptk_1_of_4_retry(struct l_timeout *timeout, void *user_data)
} }
static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm, static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
const struct eapol_key *ek) const struct eapol_key *ek,
bool unencrypted)
{ {
const uint8_t *kck; const uint8_t *kck;
struct eapol_key *step2; struct eapol_key *step2;
@ -1133,7 +1146,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
* try that, otherwise give up. * try that, otherwise give up.
*/ */
if (sm->eap) { if (sm->eap) {
send_eapol_start(NULL, sm); __send_eapol_start(sm, unencrypted);
return; return;
} }
@ -1235,7 +1248,7 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
} }
} }
eapol_sm_write(sm, (struct eapol_frame *) step2, false); eapol_sm_write(sm, (struct eapol_frame *) step2, unencrypted);
l_free(step2); l_free(step2);
l_timeout_remove(sm->eapol_start_timeout); l_timeout_remove(sm->eapol_start_timeout);
@ -1477,7 +1490,8 @@ static const uint8_t *eapol_find_wpa_ie(const uint8_t *data, size_t data_len)
static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm, static void eapol_handle_ptk_3_of_4(struct eapol_sm *sm,
const struct eapol_key *ek, const struct eapol_key *ek,
const uint8_t *decrypted_key_data, const uint8_t *decrypted_key_data,
size_t decrypted_key_data_size) size_t decrypted_key_data_size,
bool unencrypted)
{ {
const uint8_t *kck; const uint8_t *kck;
const uint8_t *kek; const uint8_t *kek;
@ -1708,7 +1722,7 @@ retransmit:
} }
} }
eapol_sm_write(sm, (struct eapol_frame *) step4, false); eapol_sm_write(sm, (struct eapol_frame *) step4, unencrypted);
l_free(step4); l_free(step4);
if (sm->handshake->ptk_complete) if (sm->handshake->ptk_complete)
@ -1773,7 +1787,8 @@ static void eapol_handle_ptk_4_of_4(struct eapol_sm *sm,
static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm, static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm,
const struct eapol_key *ek, const struct eapol_key *ek,
const uint8_t *decrypted_key_data, const uint8_t *decrypted_key_data,
size_t decrypted_key_data_size) size_t decrypted_key_data_size,
bool unencrypted)
{ {
const uint8_t *kck; const uint8_t *kck;
struct eapol_key *step2; struct eapol_key *step2;
@ -1872,7 +1887,7 @@ static void eapol_handle_gtk_1_of_2(struct eapol_sm *sm,
} }
} }
eapol_sm_write(sm, (struct eapol_frame *) step2, false); eapol_sm_write(sm, (struct eapol_frame *) step2, unencrypted);
l_free(step2); l_free(step2);
eapol_install_gtk(sm, gtk_key_index, gtk, gtk_len, ek->key_rsc); eapol_install_gtk(sm, gtk_key_index, gtk, gtk_len, ek->key_rsc);
@ -1903,7 +1918,8 @@ static struct eapol_sm *eapol_find_sm(uint32_t ifindex, const uint8_t *aa)
} }
static void eapol_key_handle(struct eapol_sm *sm, static void eapol_key_handle(struct eapol_sm *sm,
const struct eapol_frame *frame) const struct eapol_frame *frame,
bool unencrypted)
{ {
const struct eapol_key *ek; const struct eapol_key *ek;
const uint8_t *kck; const uint8_t *kck;
@ -2004,13 +2020,13 @@ static void eapol_key_handle(struct eapol_sm *sm,
goto done; goto done;
eapol_handle_gtk_1_of_2(sm, ek, decrypted_key_data, eapol_handle_gtk_1_of_2(sm, ek, decrypted_key_data,
key_data_len); key_data_len, unencrypted);
goto done; goto done;
} }
/* If no MIC, then assume packet 1, otherwise packet 3 */ /* If no MIC, then assume packet 1, otherwise packet 3 */
if (!ek->key_mic && !ek->encrypted_key_data) if (!ek->key_mic && !ek->encrypted_key_data)
eapol_handle_ptk_1_of_4(sm, ek); eapol_handle_ptk_1_of_4(sm, ek, unencrypted);
else { else {
if (!key_data_len) if (!key_data_len)
goto done; goto done;
@ -2018,7 +2034,7 @@ static void eapol_key_handle(struct eapol_sm *sm,
eapol_handle_ptk_3_of_4(sm, ek, eapol_handle_ptk_3_of_4(sm, ek,
decrypted_key_data ?: decrypted_key_data ?:
EAPOL_KEY_DATA(ek, sm->mic_len), EAPOL_KEY_DATA(ek, sm->mic_len),
key_data_len); key_data_len, unencrypted);
} }
done: done:
@ -2042,7 +2058,7 @@ static void eapol_eap_msg_cb(const uint8_t *eap_data, size_t len,
memcpy(frame->data, eap_data, len); memcpy(frame->data, eap_data, len);
eapol_sm_write(sm, frame, false); eapol_sm_write(sm, frame, sm->last_eap_unencrypted);
} }
/* This respresentes the eapTimout, eapFail and eapSuccess messages */ /* This respresentes the eapTimout, eapFail and eapSuccess messages */
@ -2192,6 +2208,7 @@ static void eapol_auth_key_handle(struct eapol_sm *sm,
static void eapol_rx_auth_packet(uint16_t proto, const uint8_t *from, static void eapol_rx_auth_packet(uint16_t proto, const uint8_t *from,
const struct eapol_frame *frame, const struct eapol_frame *frame,
bool noencrypt,
void *user_data) void *user_data)
{ {
struct eapol_sm *sm = user_data; struct eapol_sm *sm = user_data;
@ -2214,6 +2231,7 @@ static void eapol_rx_auth_packet(uint16_t proto, const uint8_t *from,
static void eapol_rx_packet(uint16_t proto, const uint8_t *from, static void eapol_rx_packet(uint16_t proto, const uint8_t *from,
const struct eapol_frame *frame, const struct eapol_frame *frame,
bool unencrypted,
void *user_data) void *user_data)
{ {
struct eapol_sm *sm = user_data; struct eapol_sm *sm = user_data;
@ -2233,6 +2251,7 @@ static void eapol_rx_packet(uint16_t proto, const uint8_t *from,
return; return;
sm->early_frame = l_memdup(frame, len); sm->early_frame = l_memdup(frame, len);
sm->early_frame_unencrypted = unencrypted;
return; return;
} }
@ -2258,6 +2277,7 @@ static void eapol_rx_packet(uint16_t proto, const uint8_t *from,
} }
sm->eap_exchanged = true; sm->eap_exchanged = true;
sm->last_eap_unencrypted = unencrypted;
eap_rx_packet(sm->eap, frame->data, eap_rx_packet(sm->eap, frame->data,
L_BE16_TO_CPU(frame->header.packet_len)); L_BE16_TO_CPU(frame->header.packet_len));
@ -2275,13 +2295,16 @@ static void eapol_rx_packet(uint16_t proto, const uint8_t *from,
* use a cached PMK. We don't yet cache PMKs so * use a cached PMK. We don't yet cache PMKs so
* send an EAPOL-Start if we haven't sent one yet. * send an EAPOL-Start if we haven't sent one yet.
*/ */
if (sm->eapol_start_timeout) if (sm->eapol_start_timeout) {
send_eapol_start(NULL, sm); l_timeout_remove(sm->eapol_start_timeout);
sm->eapol_start_timeout = NULL;
__send_eapol_start(sm, unencrypted);
}
return; return;
} }
eapol_key_handle(sm, frame); eapol_key_handle(sm, frame, unencrypted);
break; break;
default: default:
@ -2397,7 +2420,8 @@ bool eapol_start(struct eapol_sm *sm)
/* Process any frames received early due to scheduling */ /* Process any frames received early due to scheduling */
if (sm->early_frame) { if (sm->early_frame) {
eapol_rx_packet(ETH_P_PAE, sm->handshake->aa, eapol_rx_packet(ETH_P_PAE, sm->handshake->aa,
sm->early_frame, sm); sm->early_frame, sm->early_frame_unencrypted,
sm);
l_free(sm->early_frame); l_free(sm->early_frame);
sm->early_frame = NULL; sm->early_frame = NULL;
} }
@ -2458,6 +2482,7 @@ static void preauth_frame(struct preauth_sm *sm, uint8_t packet_type,
static void preauth_rx_packet(uint16_t proto, const uint8_t *from, static void preauth_rx_packet(uint16_t proto, const uint8_t *from,
const struct eapol_frame *frame, const struct eapol_frame *frame,
bool unencrypted,
void *user_data) void *user_data)
{ {
struct preauth_sm *sm = user_data; struct preauth_sm *sm = user_data;
@ -2465,6 +2490,15 @@ static void preauth_rx_packet(uint16_t proto, const uint8_t *from,
if (proto != 0x88c7 || memcmp(from, sm->aa, 6)) if (proto != 0x88c7 || memcmp(from, sm->aa, 6))
return; return;
/*
* We do not expect any pre-auth packets to be unencrypted
* since we're authenticating via the currently connected AP
* and pre-authentication implies we are already connected
* and the keys are set
*/
if (L_WARN_ON(unencrypted))
return;
if (frame->header.packet_type != 0) /* EAPOL-EAP */ if (frame->header.packet_type != 0) /* EAPOL-EAP */
return; return;
@ -2651,7 +2685,8 @@ void __eapol_rx_packet(uint32_t ifindex, const uint8_t *src, uint16_t proto,
eapol_frame_watch_match_ifindex, eapol_frame_watch_match_ifindex,
L_UINT_TO_PTR(ifindex), L_UINT_TO_PTR(ifindex),
eapol_frame_watch_func_t, proto, src, eapol_frame_watch_func_t, proto, src,
(const struct eapol_frame *) eh); (const struct eapol_frame *) eh,
noencrypt);
} }
void __eapol_tx_packet(uint32_t ifindex, const uint8_t *dst, uint16_t proto, void __eapol_tx_packet(uint32_t ifindex, const uint8_t *dst, uint16_t proto,

View File

@ -49,6 +49,7 @@ typedef void (*eapol_preauth_cb_t)(const uint8_t *pmk, void *user_data);
typedef void (*eapol_preauth_destroy_func_t)(void *user_data); typedef void (*eapol_preauth_destroy_func_t)(void *user_data);
typedef void (*eapol_frame_watch_func_t)(uint16_t proto, const uint8_t *from, typedef void (*eapol_frame_watch_func_t)(uint16_t proto, const uint8_t *from,
const struct eapol_frame *frame, const struct eapol_frame *frame,
bool noencrypt,
void *user_data); void *user_data);
bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck, bool eapol_calculate_mic(enum ie_rsn_akm_suite akm, const uint8_t *kck,