FT RRB: Add msg replay and msg delay protection

This adds a counter and adds sequence numbering to FT RRB packets. The
sequence number is checked against r0kh/r1kh sequence number cache.

Special attention is needed in case the remote AP reboots and thus loses
its state. I prefer it to recover automatically even without synchronized
clocks. Therefore an identifier called dom is generated randomly along the
initial sequence number. If the dom transmitted does not match or the
sequence number is not in the range currently expected, the sender is asked
for a fresh confirmation of its currently used sequence numbers. The packet
that triggered this is cached and processed again later.

Additionally, in order to ensure freshness, the remote AP includes an
timestamp with its messages. It is then verified that the received
messages are indeed fresh by comparing it to the older timestamps
received and the time elapsed since then. Therefore FT_RRB_TIMESTAMP is
no longer needed.

This assigns new OUI 00:13:74 vendor-specific subtype 0x0001 subtypes:
4 (SEQ_REQ) and 5 (SEQ_RESP).

This breaks backward compatibility, i.e., hostapd needs to be updated
on all APs at the same time to allow FT to remain functional.

Signed-off-by: Michael Braun <michael-dev@fami-braun.de>
This commit is contained in:
Michael Braun 2017-04-02 14:52:51 +02:00 committed by Jouni Malinen
parent c95dd8e48b
commit eefe863015
5 changed files with 796 additions and 73 deletions

View file

@ -520,6 +520,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache); wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
wpa_auth->ft_pmk_cache = NULL; wpa_auth->ft_pmk_cache = NULL;
wpa_ft_deinit(wpa_auth);
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
#ifdef CONFIG_P2P #ifdef CONFIG_P2P

View file

@ -43,6 +43,8 @@ struct ft_rrb_frame {
#define FT_PACKET_R0KH_R1KH_PULL 0x01 #define FT_PACKET_R0KH_R1KH_PULL 0x01
#define FT_PACKET_R0KH_R1KH_RESP 0x02 #define FT_PACKET_R0KH_R1KH_RESP 0x02
#define FT_PACKET_R0KH_R1KH_PUSH 0x03 #define FT_PACKET_R0KH_R1KH_PUSH 0x03
#define FT_PACKET_R0KH_R1KH_SEQ_REQ 0x04
#define FT_PACKET_R0KH_R1KH_SEQ_RESP 0x05
/* packet layout /* packet layout
* IEEE 802 extended OUI ethertype frame header * IEEE 802 extended OUI ethertype frame header
@ -61,6 +63,7 @@ struct ft_rrb_frame {
#define FT_RRB_LAST_EMPTY 0 /* placeholder or padding */ #define FT_RRB_LAST_EMPTY 0 /* placeholder or padding */
#define FT_RRB_SEQ 1 /* struct ft_rrb_seq */
#define FT_RRB_NONCE 2 /* size FT_RRB_NONCE_LEN */ #define FT_RRB_NONCE 2 /* size FT_RRB_NONCE_LEN */
#define FT_RRB_TIMESTAMP 3 /* le32 unix seconds */ #define FT_RRB_TIMESTAMP 3 /* le32 unix seconds */
@ -81,26 +84,40 @@ struct ft_rrb_tlv {
/* followed by data of length len */ /* followed by data of length len */
} STRUCT_PACKED; } STRUCT_PACKED;
struct ft_rrb_seq {
le32 dom;
le32 seq;
le32 ts;
} STRUCT_PACKED;
/* session TLVs: /* session TLVs:
* required: PMK_R1, PMK_R1_NAME, PAIRWISE * required: PMK_R1, PMK_R1_NAME, PAIRWISE
* *
* pull frame TLVs: * pull frame TLVs:
* auth: * auth:
* required: NONCE, R0KH_ID, R1KH_ID * required: SEQ, NONCE, R0KH_ID, R1KH_ID
* encrypted: * encrypted:
* required: PMK_R0_NAME, S1KH_ID * required: PMK_R0_NAME, S1KH_ID
* *
* response frame TLVs: * response frame TLVs:
* auth: * auth:
* required: NONCE, R0KH_ID, R1KH_ID * required: SEQ, NONCE, R0KH_ID, R1KH_ID
* encrypted: * encrypted:
* required: S1KH_ID, session TLVs * required: S1KH_ID, session TLVs
* *
* push frame TLVs: * push frame TLVs:
* auth: * auth:
* required: TIMESTAMP, R0KH_ID, R1KH_ID * required: SEQ, R0KH_ID, R1KH_ID
* encrypted: * encrypted:
* required: S1KH_ID, PMK_R0_NAME, session TLVs * required: S1KH_ID, PMK_R0_NAME, session TLVs
*
* sequence number request frame TLVs:
* auth:
* required: R0KH_ID, R1KH_ID, NONCE
*
* sequence number response frame TLVs:
* auth:
* required: SEQ, NONCE, R0KH_ID, R1KH_ID
*/ */
#ifdef _MSC_VER #ifdef _MSC_VER
@ -114,6 +131,7 @@ struct wpa_authenticator;
struct wpa_state_machine; struct wpa_state_machine;
struct rsn_pmksa_cache_entry; struct rsn_pmksa_cache_entry;
struct eapol_state_machine; struct eapol_state_machine;
struct ft_remote_seq;
struct ft_remote_r0kh { struct ft_remote_r0kh {
@ -122,6 +140,7 @@ struct ft_remote_r0kh {
u8 id[FT_R0KH_ID_MAX_LEN]; u8 id[FT_R0KH_ID_MAX_LEN];
size_t id_len; size_t id_len;
u8 key[32]; u8 key[32];
struct ft_remote_seq *seq;
}; };
@ -130,6 +149,7 @@ struct ft_remote_r1kh {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 id[FT_R1KH_ID_LEN]; u8 id[FT_R1KH_ID_LEN];
u8 key[32]; u8 key[32];
struct ft_remote_seq *seq;
}; };
@ -349,6 +369,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *dst_addr, u8 oui_suffix, const u8 *data, const u8 *dst_addr, u8 oui_suffix, const u8 *data,
size_t data_len); size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr); void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
void wpa_ft_deinit(struct wpa_authenticator *wpa_auth);
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);

File diff suppressed because it is too large Load diff

View file

@ -578,6 +578,10 @@ static struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd,
return hapd->oui_resp; return hapd->oui_resp;
case FT_PACKET_R0KH_R1KH_PUSH: case FT_PACKET_R0KH_R1KH_PUSH:
return hapd->oui_push; return hapd->oui_push;
case FT_PACKET_R0KH_R1KH_SEQ_REQ:
return hapd->oui_sreq;
case FT_PACKET_R0KH_R1KH_SEQ_RESP:
return hapd->oui_sresp;
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */
default: default:
return NULL; return NULL;
@ -836,6 +840,18 @@ static int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd,
if (!hapd->oui_push) if (!hapd->oui_push)
return -1; return -1;
hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface,
FT_PACKET_R0KH_R1KH_SEQ_REQ,
hostapd_rrb_oui_receive, hapd);
if (!hapd->oui_sreq)
return -1;
hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface,
FT_PACKET_R0KH_R1KH_SEQ_RESP,
hostapd_rrb_oui_receive, hapd);
if (!hapd->oui_sresp)
return -1;
return 0; return 0;
} }
@ -848,6 +864,10 @@ static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd)
hapd->oui_resp = NULL; hapd->oui_resp = NULL;
eth_p_oui_unregister(hapd->oui_push); eth_p_oui_unregister(hapd->oui_push);
hapd->oui_push = NULL; hapd->oui_push = NULL;
eth_p_oui_unregister(hapd->oui_sreq);
hapd->oui_sreq = NULL;
eth_p_oui_unregister(hapd->oui_sresp);
hapd->oui_sresp = NULL;
} }
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */

View file

@ -9,6 +9,8 @@
#ifndef WPA_AUTH_I_H #ifndef WPA_AUTH_I_H
#define WPA_AUTH_I_H #define WPA_AUTH_I_H
#include "utils/list.h"
/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */ /* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
#define RSNA_MAX_EAPOL_RETRIES 4 #define RSNA_MAX_EAPOL_RETRIES 4
@ -211,6 +213,38 @@ struct wpa_authenticator {
}; };
#ifdef CONFIG_IEEE80211R_AP
#define FT_REMOTE_SEQ_BACKLOG 16
struct ft_remote_seq_rx {
u32 dom;
struct os_reltime time_offset; /* local time - offset = remote time */
/* accepted sequence numbers: (offset ... offset + 0x40000000]
* (except those in last)
* dropped sequence numbers: (offset - 0x40000000 ... offset]
* all others trigger SEQ_REQ message (except first message)
*/
u32 last[FT_REMOTE_SEQ_BACKLOG];
unsigned int num_last;
u32 offsetidx;
struct dl_list queue; /* send nonces + rrb msgs awaiting seq resp */
};
struct ft_remote_seq_tx {
u32 dom; /* non zero if initialized */
u32 seq;
};
struct ft_remote_seq {
struct ft_remote_seq_rx rx;
struct ft_remote_seq_tx tx;
};
#endif /* CONFIG_IEEE80211R_AP */
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid); const u8 *pmkid);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,