@ -34,6 +34,8 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm,
const u8 * current_ap , const u8 * sta_addr ,
u16 status , const u8 * resp_ies ,
size_t resp_ies_len ) ;
static void ft_finish_pull ( struct wpa_state_machine * sm ) ;
static void wpa_ft_expire_pull ( void * eloop_ctx , void * timeout_ctx ) ;
static void wpa_ft_rrb_seq_timeout ( void * eloop_ctx , void * timeout_ctx ) ;
struct tlv_list {
@ -1008,21 +1010,27 @@ static int wpa_ft_rrb_init_r0kh_seq(struct ft_remote_r0kh *r0kh)
static void wpa_ft_rrb_lookup_r0kh ( struct wpa_authenticator * wpa_auth ,
const u8 * f_r0kh_id , size_t f_r0kh_id_len ,
struct ft_remote_r0kh * * r0kh_out )
struct ft_remote_r0kh * * r0kh_out ,
struct ft_remote_r0kh * * r0kh_wildcard )
{
struct ft_remote_r0kh * r0kh ;
* r0kh_wildcard = NULL ;
* r0kh_out = NULL ;
for ( r0kh = wpa_auth - > conf . r0kh_list ; r0kh ; r0kh = r0kh - > next ) {
if ( wpa_auth - > conf . r0kh_list )
r0kh = * wpa_auth - > conf . r0kh_list ;
else
r0kh = NULL ;
for ( ; r0kh ; r0kh = r0kh - > next ) {
if ( r0kh - > id_len = = 1 & & r0kh - > id [ 0 ] = = ' * ' )
* r0kh_wildcard = r0kh ;
if ( f_r0kh_id & & r0kh - > id_len = = f_r0kh_id_len & &
os_memcmp_const ( f_r0kh_id , r0kh - > id , f_r0kh_id_len ) = = 0 ) {
os_memcmp_const ( f_r0kh_id , r0kh - > id , f_r0kh_id_len ) = = 0 )
* r0kh_out = r0kh ;
break ;
}
}
if ( ! * r0kh_out )
if ( ! * r0kh_out & & ! * r0kh_wildcard )
wpa_printf ( MSG_DEBUG , " FT: No matching R0KH found " ) ;
if ( * r0kh_out & & wpa_ft_rrb_init_r0kh_seq ( * r0kh_out ) < 0 )
@ -1049,21 +1057,28 @@ static int wpa_ft_rrb_init_r1kh_seq(struct ft_remote_r1kh *r1kh)
static void wpa_ft_rrb_lookup_r1kh ( struct wpa_authenticator * wpa_auth ,
const u8 * f_r1kh_id ,
struct ft_remote_r1kh * * r1kh_out )
struct ft_remote_r1kh * * r1kh_out ,
struct ft_remote_r1kh * * r1kh_wildcard )
{
struct ft_remote_r1kh * r1kh ;
* r1kh_wildcard = NULL ;
* r1kh_out = NULL ;
for ( r1kh = wpa_auth - > conf . r1kh_list ; r1kh ; r1kh = r1kh - > next ) {
if ( wpa_auth - > conf . r1kh_list )
r1kh = * wpa_auth - > conf . r1kh_list ;
else
r1kh = NULL ;
for ( ; r1kh ; r1kh = r1kh - > next ) {
if ( is_zero_ether_addr ( r1kh - > addr ) & &
is_zero_ether_addr ( r1kh - > id ) )
* r1kh_wildcard = r1kh ;
if ( f_r1kh_id & &
os_memcmp_const ( r1kh - > id , f_r1kh_id , FT_R1KH_ID_LEN ) = = 0 ) {
os_memcmp_const ( r1kh - > id , f_r1kh_id , FT_R1KH_ID_LEN ) = = 0 )
* r1kh_out = r1kh ;
break ;
}
}
if ( ! * r1kh_out )
if ( ! * r1kh_out & & ! * r1kh_wildcard )
wpa_printf ( MSG_DEBUG , " FT: No matching R1KH found " ) ;
if ( * r1kh_out & & wpa_ft_rrb_init_r1kh_seq ( * r1kh_out ) < 0 )
@ -1094,6 +1109,163 @@ static int wpa_ft_rrb_check_r1kh(struct wpa_authenticator *wpa_auth,
}
static void wpa_ft_rrb_del_r0kh ( void * eloop_ctx , void * timeout_ctx )
{
struct wpa_authenticator * wpa_auth = eloop_ctx ;
struct ft_remote_r0kh * r0kh , * prev = NULL ;
if ( ! wpa_auth - > conf . r0kh_list )
return ;
for ( r0kh = * wpa_auth - > conf . r0kh_list ; r0kh ; r0kh = r0kh - > next ) {
if ( r0kh = = timeout_ctx )
break ;
prev = r0kh ;
}
if ( ! r0kh )
return ;
if ( prev )
prev - > next = r0kh - > next ;
else
* wpa_auth - > conf . r0kh_list = r0kh - > next ;
if ( r0kh - > seq )
wpa_ft_rrb_seq_flush ( wpa_auth , r0kh - > seq , 0 ) ;
os_free ( r0kh - > seq ) ;
os_free ( r0kh ) ;
}
static void wpa_ft_rrb_r0kh_replenish ( struct wpa_authenticator * wpa_auth ,
struct ft_remote_r0kh * r0kh , int timeout )
{
if ( timeout > 0 )
eloop_replenish_timeout ( timeout , 0 , wpa_ft_rrb_del_r0kh ,
wpa_auth , r0kh ) ;
}
static void wpa_ft_rrb_r0kh_timeout ( struct wpa_authenticator * wpa_auth ,
struct ft_remote_r0kh * r0kh , int timeout )
{
eloop_cancel_timeout ( wpa_ft_rrb_del_r0kh , wpa_auth , r0kh ) ;
if ( timeout > 0 )
eloop_register_timeout ( timeout , 0 , wpa_ft_rrb_del_r0kh ,
wpa_auth , r0kh ) ;
}
static struct ft_remote_r0kh *
wpa_ft_rrb_add_r0kh ( struct wpa_authenticator * wpa_auth ,
struct ft_remote_r0kh * r0kh_wildcard ,
const u8 * src_addr , const u8 * r0kh_id , size_t id_len ,
int timeout )
{
struct ft_remote_r0kh * r0kh ;
if ( ! wpa_auth - > conf . r0kh_list )
return NULL ;
r0kh = os_zalloc ( sizeof ( * r0kh ) ) ;
if ( ! r0kh )
return NULL ;
if ( src_addr )
os_memcpy ( r0kh - > addr , src_addr , sizeof ( r0kh - > addr ) ) ;
if ( id_len > FT_R0KH_ID_MAX_LEN )
id_len = FT_R0KH_ID_MAX_LEN ;
os_memcpy ( r0kh - > id , r0kh_id , id_len ) ;
r0kh - > id_len = id_len ;
os_memcpy ( r0kh - > key , r0kh_wildcard - > key , sizeof ( r0kh - > key ) ) ;
r0kh - > next = * wpa_auth - > conf . r0kh_list ;
* wpa_auth - > conf . r0kh_list = r0kh ;
if ( timeout > 0 )
eloop_register_timeout ( timeout , 0 , wpa_ft_rrb_del_r0kh ,
wpa_auth , r0kh ) ;
if ( wpa_ft_rrb_init_r0kh_seq ( r0kh ) < 0 )
return NULL ;
return r0kh ;
}
static void wpa_ft_rrb_del_r1kh ( void * eloop_ctx , void * timeout_ctx )
{
struct wpa_authenticator * wpa_auth = eloop_ctx ;
struct ft_remote_r1kh * r1kh , * prev = NULL ;
if ( ! wpa_auth - > conf . r1kh_list )
return ;
for ( r1kh = * wpa_auth - > conf . r1kh_list ; r1kh ; r1kh = r1kh - > next ) {
if ( r1kh = = timeout_ctx )
break ;
prev = r1kh ;
}
if ( ! r1kh )
return ;
if ( prev )
prev - > next = r1kh - > next ;
else
* wpa_auth - > conf . r1kh_list = r1kh - > next ;
if ( r1kh - > seq )
wpa_ft_rrb_seq_flush ( wpa_auth , r1kh - > seq , 0 ) ;
os_free ( r1kh - > seq ) ;
os_free ( r1kh ) ;
}
static void wpa_ft_rrb_r1kh_replenish ( struct wpa_authenticator * wpa_auth ,
struct ft_remote_r1kh * r1kh , int timeout )
{
if ( timeout > 0 )
eloop_replenish_timeout ( timeout , 0 , wpa_ft_rrb_del_r1kh ,
wpa_auth , r1kh ) ;
}
static struct ft_remote_r1kh *
wpa_ft_rrb_add_r1kh ( struct wpa_authenticator * wpa_auth ,
struct ft_remote_r1kh * r1kh_wildcard ,
const u8 * src_addr , const u8 * r1kh_id , int timeout )
{
struct ft_remote_r1kh * r1kh ;
if ( ! wpa_auth - > conf . r1kh_list )
return NULL ;
r1kh = os_zalloc ( sizeof ( * r1kh ) ) ;
if ( ! r1kh )
return NULL ;
os_memcpy ( r1kh - > addr , src_addr , sizeof ( r1kh - > addr ) ) ;
os_memcpy ( r1kh - > id , r1kh_id , sizeof ( r1kh - > id ) ) ;
os_memcpy ( r1kh - > key , r1kh_wildcard - > key , sizeof ( r1kh - > key ) ) ;
r1kh - > next = * wpa_auth - > conf . r1kh_list ;
* wpa_auth - > conf . r1kh_list = r1kh ;
if ( timeout > 0 )
eloop_register_timeout ( timeout , 0 , wpa_ft_rrb_del_r1kh ,
wpa_auth , r1kh ) ;
if ( wpa_ft_rrb_init_r1kh_seq ( r1kh ) < 0 )
return NULL ;
return r1kh ;
}
void wpa_ft_sta_deinit ( struct wpa_state_machine * sm )
{
eloop_cancel_timeout ( wpa_ft_expire_pull , sm , NULL ) ;
}
static void wpa_ft_deinit_seq ( struct wpa_authenticator * wpa_auth )
{
struct ft_remote_r0kh * r0kh ;
@ -1101,7 +1273,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
eloop_cancel_timeout ( wpa_ft_rrb_seq_timeout , wpa_auth , ELOOP_ALL_CTX ) ;
for ( r0kh = wpa_auth - > conf . r0kh_list ; r0kh ; r0kh = r0kh - > next ) {
if ( wpa_auth - > conf . r0kh_list )
r0kh = * wpa_auth - > conf . r0kh_list ;
else
r0kh = NULL ;
for ( ; r0kh ; r0kh = r0kh - > next ) {
if ( ! r0kh - > seq )
continue ;
wpa_ft_rrb_seq_flush ( wpa_auth , r0kh - > seq , 0 ) ;
@ -1109,7 +1285,11 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
r0kh - > seq = NULL ;
}
for ( r1kh = wpa_auth - > conf . r1kh_list ; r1kh ; r1kh = r1kh - > next ) {
if ( wpa_auth - > conf . r1kh_list )
r1kh = * wpa_auth - > conf . r1kh_list ;
else
r1kh = NULL ;
for ( ; r1kh ; r1kh = r1kh - > next ) {
if ( ! r1kh - > seq )
continue ;
wpa_ft_rrb_seq_flush ( wpa_auth , r1kh - > seq , 0 ) ;
@ -1119,9 +1299,100 @@ static void wpa_ft_deinit_seq(struct wpa_authenticator *wpa_auth)
}
static void wpa_ft_deinit_rkh_tmp ( struct wpa_authenticator * wpa_auth )
{
struct ft_remote_r0kh * r0kh , * r0kh_next , * r0kh_prev = NULL ;
struct ft_remote_r1kh * r1kh , * r1kh_next , * r1kh_prev = NULL ;
if ( wpa_auth - > conf . r0kh_list )
r0kh = * wpa_auth - > conf . r0kh_list ;
else
r0kh = NULL ;
while ( r0kh ) {
r0kh_next = r0kh - > next ;
if ( eloop_cancel_timeout ( wpa_ft_rrb_del_r0kh , wpa_auth ,
r0kh ) > 0 ) {
if ( r0kh_prev )
r0kh_prev - > next = r0kh_next ;
else
* wpa_auth - > conf . r0kh_list = r0kh_next ;
os_free ( r0kh ) ;
} else {
r0kh_prev = r0kh ;
}
r0kh = r0kh_next ;
}
if ( wpa_auth - > conf . r1kh_list )
r1kh = * wpa_auth - > conf . r1kh_list ;
else
r1kh = NULL ;
while ( r1kh ) {
r1kh_next = r1kh - > next ;
if ( eloop_cancel_timeout ( wpa_ft_rrb_del_r1kh , wpa_auth ,
r1kh ) > 0 ) {
if ( r1kh_prev )
r1kh_prev - > next = r1kh_next ;
else
* wpa_auth - > conf . r1kh_list = r1kh_next ;
os_free ( r1kh ) ;
} else {
r1kh_prev = r1kh ;
}
r1kh = r1kh_next ;
}
}
void wpa_ft_deinit ( struct wpa_authenticator * wpa_auth )
{
wpa_ft_deinit_seq ( wpa_auth ) ;
wpa_ft_deinit_rkh_tmp ( wpa_auth ) ;
}
static void wpa_ft_block_r0kh ( struct wpa_authenticator * wpa_auth ,
const u8 * f_r0kh_id , size_t f_r0kh_id_len )
{
struct ft_remote_r0kh * r0kh , * r0kh_wildcard ;
if ( ! wpa_auth - > conf . rkh_neg_timeout )
return ;
wpa_ft_rrb_lookup_r0kh ( wpa_auth , f_r0kh_id , f_r0kh_id_len ,
& r0kh , & r0kh_wildcard ) ;
if ( ! r0kh_wildcard ) {
/* r0kh removed after neg_timeout and might need re-adding */
return ;
}
wpa_hexdump ( MSG_DEBUG , " FT: Blacklist R0KH-ID " ,
f_r0kh_id , f_r0kh_id_len ) ;
if ( r0kh ) {
wpa_ft_rrb_r0kh_timeout ( wpa_auth , r0kh ,
wpa_auth - > conf . rkh_neg_timeout ) ;
os_memset ( r0kh - > addr , 0 , ETH_ALEN ) ;
} else
wpa_ft_rrb_add_r0kh ( wpa_auth , r0kh_wildcard , NULL , f_r0kh_id ,
f_r0kh_id_len ,
wpa_auth - > conf . rkh_neg_timeout ) ;
}
static void wpa_ft_expire_pull ( void * eloop_ctx , void * timeout_ctx )
{
struct wpa_state_machine * sm = eloop_ctx ;
wpa_printf ( MSG_DEBUG , " FT: Timeout pending pull request for " MACSTR ,
MAC2STR ( sm - > addr ) ) ;
if ( sm - > ft_pending_pull_left_retries < = 0 )
wpa_ft_block_r0kh ( sm - > wpa_auth , sm - > r0kh_id , sm - > r0kh_id_len ) ;
/* cancel multiple timeouts */
eloop_cancel_timeout ( wpa_ft_expire_pull , sm , NULL ) ;
ft_finish_pull ( sm ) ;
}
@ -1129,11 +1400,14 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
const u8 * ies , size_t ies_len ,
const u8 * pmk_r0_name )
{
struct ft_remote_r0kh * r0kh ;
struct ft_remote_r0kh * r0kh , * r0kh_wildcard ;
u8 * packet = NULL ;
const u8 * key , * f_r1kh_id = sm - > wpa_auth - > conf . r1_key_holder ;
size_t packet_len , key_len ;
struct ft_rrb_seq f_seq ;
int tsecs , tusecs , first ;
struct wpabuf * ft_pending_req_ies ;
int r0kh_timeout ;
struct tlv_list req_enc [ ] = {
{ . type = FT_RRB_PMK_R0_NAME , . len = WPA_PMK_NAME_LEN ,
. data = pmk_r0_name } ,
@ -1153,13 +1427,38 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
{ . type = FT_RRB_LAST_EMPTY , . len = 0 , . data = NULL } ,
} ;
if ( sm - > ft_pending_pull_left_retries < = 0 )
return - 1 ;
first = sm - > ft_pending_pull_left_retries = =
sm - > wpa_auth - > conf . rkh_pull_retries ;
sm - > ft_pending_pull_left_retries - - ;
wpa_ft_rrb_lookup_r0kh ( sm - > wpa_auth , sm - > r0kh_id , sm - > r0kh_id_len ,
& r0kh ) ;
& r0kh , & r0kh_wildcard ) ;
/* Keep r0kh sufficiently long in the list for seq num check */
r0kh_timeout = sm - > wpa_auth - > conf . rkh_pull_timeout / 1000 +
1 + ftRRBseqTimeout ;
if ( r0kh ) {
wpa_ft_rrb_r0kh_replenish ( sm - > wpa_auth , r0kh , r0kh_timeout ) ;
} else if ( r0kh_wildcard ) {
wpa_printf ( MSG_DEBUG , " FT: Using wildcard R0KH-ID " ) ;
/* r0kh->addr: updated by SEQ_RESP and wpa_ft_expire_pull */
r0kh = wpa_ft_rrb_add_r0kh ( sm - > wpa_auth , r0kh_wildcard ,
r0kh_wildcard - > addr ,
sm - > r0kh_id , sm - > r0kh_id_len ,
r0kh_timeout ) ;
}
if ( r0kh = = NULL ) {
wpa_hexdump ( MSG_DEBUG , " FT: Did not find R0KH-ID " ,
sm - > r0kh_id , sm - > r0kh_id_len ) ;
return - 1 ;
}
if ( is_zero_ether_addr ( r0kh - > addr ) ) {
wpa_hexdump ( MSG_DEBUG , " FT: R0KH-ID is blacklisted " ,
sm - > r0kh_id , sm - > r0kh_id_len ) ;
return - 1 ;
}
key = r0kh - > key ;
key_len = sizeof ( r0kh - > key ) ;
@ -1175,7 +1474,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
key_len , NULL , 0 , NULL , 0 , NULL ) ;
}
if ( random_get_bytes ( sm - > ft_pending_pull_nonce , FT_RRB_NONCE_LEN ) < 0 ) {
if ( first & &
random_get_bytes ( sm - > ft_pending_pull_nonce , FT_RRB_NONCE_LEN ) < 0 ) {
wpa_printf ( MSG_DEBUG , " FT: Failed to get random data for "
" nonce " ) ;
return - 1 ;
@ -1191,13 +1491,18 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
& packet , & packet_len ) < 0 )
return - 1 ;
ft_pending_req_ies = wpabuf_alloc_copy ( ies , ies_len ) ;
wpabuf_free ( sm - > ft_pending_req_ies ) ;
sm - > ft_pending_req_ies = wpabuf_alloc_copy ( ies , ies_len ) ;
sm - > ft_pending_req_ies = ft_pending_req_ies ;
if ( ! sm - > ft_pending_req_ies ) {
os_free ( packet ) ;
return - 1 ;
}
tsecs = sm - > wpa_auth - > conf . rkh_pull_timeout / 1000 ;
tusecs = ( sm - > wpa_auth - > conf . rkh_pull_timeout % 1000 ) * 1000 ;
eloop_register_timeout ( tsecs , tusecs , wpa_ft_expire_pull , sm , NULL ) ;
wpa_ft_rrb_oui_send ( sm - > wpa_auth , r0kh - > addr , FT_PACKET_R0KH_R1KH_PULL ,
packet , packet_len ) ;
@ -1816,8 +2121,8 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm,
} else if ( wpa_ft_fetch_pmk_r1 ( sm - > wpa_auth , sm - > addr , pmk_r1_name ,
pmk_r1 , & pairwise ) < 0 ) {
if ( wpa_ft_pull_pmk_r1 ( sm , ies , ies_len , parse . rsn_pmkid ) < 0 ) {
wpa_printf ( MSG_DEBUG , " FT: Did not have matching "
" PMK-R1 and unknown R0KH-ID" ) ;
wpa_printf ( MSG_DEBUG ,
" FT: Did not have matching PMK-R1 and either unknown or blocked R0KH-ID or NAK from R0KH " ) ;
return WLAN_STATUS_INVALID_PMKID ;
}
@ -1908,6 +2213,7 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
sm - > ft_pending_cb = cb ;
sm - > ft_pending_cb_ctx = ctx ;
sm - > ft_pending_auth_transaction = auth_transaction ;
sm - > ft_pending_pull_left_retries = sm - > wpa_auth - > conf . rkh_pull_retries ;
res = wpa_ft_process_auth_req ( sm , ies , ies_len , & resp_ies ,
& resp_ies_len ) ;
if ( res < 0 ) {
@ -2189,6 +2495,7 @@ static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
sm - > ft_pending_cb = wpa_ft_rrb_rx_request_cb ;
sm - > ft_pending_cb_ctx = sm ;
os_memcpy ( sm - > ft_pending_current_ap , current_ap , ETH_ALEN ) ;
sm - > ft_pending_pull_left_retries = sm - > wpa_auth - > conf . rkh_pull_retries ;
res = wpa_ft_process_auth_req ( sm , body , len , & resp_ies ,
& resp_ies_len ) ;
if ( res < 0 ) {
@ -2276,6 +2583,10 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len,
{ . type = FT_RRB_LAST_EMPTY , . len = 0 , . data = NULL } ,
} ;
if ( ! pmk_r0 )
return wpa_ft_rrb_build ( key , key_len , tlvs , NULL , tlv_auth ,
src_addr , type , packet , packet_len ) ;
if ( wpa_derive_pmk_r1 ( pmk_r0 - > pmk_r0 , pmk_r0 - > pmk_r0_name , r1kh_id ,
s1kh_id , pmk_r1 , pmk_r1_name ) < 0 )
return - 1 ;
@ -2301,7 +2612,7 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
const char * msgtype = " pull request " ;
u8 * plain = NULL , * packet = NULL ;
size_t plain_len = 0 , packet_len = 0 ;
struct ft_remote_r1kh * r1kh ;
struct ft_remote_r1kh * r1kh , * r1kh_wildcard ;
const u8 * key ;
size_t key_len ;
int seq_ret ;
@ -2327,17 +2638,31 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
RRB_GET_AUTH ( FT_RRB_R1KH_ID , r1kh_id , msgtype , FT_R1KH_ID_LEN ) ;
wpa_printf ( MSG_DEBUG , " FT: R1KH-ID= " MACSTR , MAC2STR ( f_r1kh_id ) ) ;
wpa_ft_rrb_lookup_r1kh ( wpa_auth , f_r1kh_id , & r1kh ) ;
if ( ! r1kh | | os_memcmp ( r1kh - > addr , src_addr , ETH_ALEN ) ! = 0 )
wpa_ft_rrb_lookup_r1kh ( wpa_auth , f_r1kh_id , & r1kh , & r1kh_wildcard ) ;
if ( r1kh ) {
key = r1kh - > key ;
key_len = sizeof ( r1kh - > key ) ;
} else if ( r1kh_wildcard ) {
wpa_printf ( MSG_DEBUG , " FT: Using wildcard R1KH-ID " ) ;
key = r1kh_wildcard - > key ;
key_len = sizeof ( r1kh_wildcard - > key ) ;
} else {
goto out ;
key = r1kh - > key ;
key_len = sizeof ( r1kh - > key ) ;
}
RRB_GET_AUTH ( FT_RRB_NONCE , nonce , " pull request " , FT_RRB_NONCE_LEN ) ;
wpa_hexdump ( MSG_DEBUG , " FT: nonce " , f_nonce , f_nonce_len ) ;
seq_ret = wpa_ft_rrb_seq_chk ( r1kh - > seq , src_addr , enc , enc_len , auth ,
auth_len , msgtype , no_defer ) ;
seq_ret = FT_RRB_SEQ_DROP ;
if ( r1kh )
seq_ret = wpa_ft_rrb_seq_chk ( r1kh - > seq , src_addr , enc , enc_len ,
auth , auth_len , msgtype , no_defer ) ;
if ( ! no_defer & & r1kh_wildcard & &
( ! r1kh | | os_memcmp ( r1kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) ) {
/* wildcard: r1kh-id unknown or changed addr -> do a seq req */
seq_ret = FT_RRB_SEQ_DEFER ;
}
if ( seq_ret = = FT_RRB_SEQ_DROP )
goto out ;
@ -2346,6 +2671,13 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
& plain , & plain_len ) < 0 )
goto out ;
if ( ! r1kh )
r1kh = wpa_ft_rrb_add_r1kh ( wpa_auth , r1kh_wildcard , src_addr ,
f_r1kh_id ,
wpa_auth - > conf . rkh_pos_timeout ) ;
if ( ! r1kh )
goto out ;
if ( seq_ret = = FT_RRB_SEQ_DEFER ) {
wpa_ft_rrb_seq_req ( wpa_auth , r1kh - > seq , src_addr , f_r0kh_id ,
f_r0kh_id_len , f_r1kh_id , key , key_len ,
@ -2356,6 +2688,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
wpa_ft_rrb_seq_accept ( wpa_auth , r1kh - > seq , src_addr , auth , auth_len ,
msgtype ) ;
wpa_ft_rrb_r1kh_replenish ( wpa_auth , r1kh ,
wpa_auth - > conf . rkh_pos_timeout ) ;
RRB_GET ( FT_RRB_PMK_R0_NAME , pmk_r0_name , msgtype , WPA_PMK_NAME_LEN ) ;
wpa_hexdump ( MSG_DEBUG , " FT: PMKR0Name " , f_pmk_r0_name ,
@ -2392,10 +2726,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
resp_auth [ 4 ] . len = 0 ;
resp_auth [ 4 ] . data = NULL ;
if ( wpa_ft_fetch_pmk_r0 ( wpa_auth , f_s1kh_id , f_pmk_r0_name , & r0 ) < 0 ) {
if ( wpa_ft_fetch_pmk_r0 ( wpa_auth , f_s1kh_id , f_pmk_r0_name , & r0 ) < 0 )
wpa_printf ( MSG_DEBUG , " FT: No matching PMK-R0-Name found " ) ;
goto out ;
}
ret = wpa_ft_rrb_build_r0 ( key , key_len , resp , r0 , f_r1kh_id , f_s1kh_id ,
resp_auth , wpa_auth - > addr ,
@ -2417,6 +2749,7 @@ out:
/* @returns 0 on success
* - 1 on error
* - 2 if FR_RRB_PAIRWISE is missing
*/
static int wpa_ft_rrb_rx_r1 ( struct wpa_authenticator * wpa_auth ,
const u8 * src_addr , u8 type ,
@ -2431,7 +2764,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
{
u8 * plain = NULL ;
size_t plain_len = 0 ;
struct ft_remote_r0kh * r0kh ;
struct ft_remote_r0kh * r0kh , * r0kh_wildcard ;
const u8 * key ;
size_t key_len ;
int seq_ret ;
@ -2453,14 +2786,31 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
goto out ;
}
wpa_ft_rrb_lookup_r0kh ( wpa_auth , f_r0kh_id , f_r0kh_id_len , & r0kh ) ;
if ( ! r0kh | | os_memcmp ( r0kh - > addr , src_addr , ETH_ALEN ) ! = 0 )
wpa_ft_rrb_lookup_r0kh ( wpa_auth , f_r0kh_id , f_r0kh_id_len , & r0kh ,
& r0kh_wildcard ) ;
if ( r0kh ) {
key = r0kh - > key ;
key_len = sizeof ( r0kh - > key ) ;
} else if ( r0kh_wildcard ) {
wpa_printf ( MSG_DEBUG , " FT: Using wildcard R0KH-ID " ) ;
key = r0kh_wildcard - > key ;
key_len = sizeof ( r0kh_wildcard - > key ) ;
} else {
goto out ;
key = r0kh - > key ;
key_len = sizeof ( r0kh - > key ) ;
}
seq_ret = FT_RRB_SEQ_DROP ;
if ( r0kh ) {
seq_ret = wpa_ft_rrb_seq_chk ( r0kh - > seq , src_addr , enc , enc_len ,
auth , auth_len , msgtype ,
cb ? 0 : 1 ) ;
}
if ( cb & & r0kh_wildcard & &
( ! r0kh | | os_memcmp ( r0kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) ) {
/* wildcard: r0kh-id unknown or changed addr -> do a seq req */
seq_ret = FT_RRB_SEQ_DEFER ;
}
seq_ret = wpa_ft_rrb_seq_chk ( r0kh - > seq , src_addr , enc , enc_len , auth ,
auth_len , msgtype , cb ? 0 : 1 ) ;
if ( seq_ret = = FT_RRB_SEQ_DROP )
goto out ;
@ -2468,6 +2818,13 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
src_addr , type , & plain , & plain_len ) < 0 )
goto out ;
if ( ! r0kh )
r0kh = wpa_ft_rrb_add_r0kh ( wpa_auth , r0kh_wildcard , src_addr ,
f_r0kh_id , f_r0kh_id_len ,
wpa_auth - > conf . rkh_pos_timeout ) ;
if ( ! r0kh )
goto out ;
if ( seq_ret = = FT_RRB_SEQ_DEFER ) {
wpa_ft_rrb_seq_req ( wpa_auth , r0kh - > seq , src_addr , f_r0kh_id ,
f_r0kh_id_len , f_r1kh_id , key , key_len ,
@ -2477,6 +2834,8 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
wpa_ft_rrb_seq_accept ( wpa_auth , r0kh - > seq , src_addr , auth , auth_len ,
msgtype ) ;
wpa_ft_rrb_r0kh_replenish ( wpa_auth , r0kh ,
wpa_auth - > conf . rkh_pos_timeout ) ;
RRB_GET ( FT_RRB_S1KH_ID , s1kh_id , msgtype , ETH_ALEN ) ;
wpa_printf ( MSG_DEBUG , " FT: S1KH-ID= " MACSTR , MAC2STR ( f_s1kh_id ) ) ;
@ -2484,9 +2843,11 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth,
if ( s1kh_id_out )
os_memcpy ( s1kh_id_out , f_s1kh_id , ETH_ALEN ) ;
ret = - 2 ;
RRB_GET ( FT_RRB_PAIRWISE , pairwise , msgtype , sizeof ( le16 ) ) ;
wpa_hexdump ( MSG_DEBUG , " FT: pairwise " , f_pairwise , f_pairwise_len ) ;
ret = - 1 ;
RRB_GET ( FT_RRB_PMK_R1_NAME , pmk_r1_name , msgtype , WPA_PMK_NAME_LEN ) ;
wpa_hexdump ( MSG_DEBUG , " FT: PMKR1Name " ,
f_pmk_r1_name , WPA_PMK_NAME_LEN ) ;
@ -2519,13 +2880,20 @@ static void ft_finish_pull(struct wpa_state_machine *sm)
size_t resp_ies_len ;
u16 status ;
if ( ! sm - > ft_pending_cb | | ! sm - > ft_pending_req_ies )
return ;
res = wpa_ft_process_auth_req ( sm , wpabuf_head ( sm - > ft_pending_req_ies ) ,
wpabuf_len ( sm - > ft_pending_req_ies ) ,
& resp_ies , & resp_ies_len ) ;
if ( res < 0 ) {
/* this loop is broken by ft_pending_pull_left_retries */
wpa_printf ( MSG_DEBUG ,
" FT: Callback postponed until response is available " ) ;
return ;
}
wpabuf_free ( sm - > ft_pending_req_ies ) ;
sm - > ft_pending_req_ies = NULL ;
if ( res < 0 )
res = WLAN_STATUS_UNSPECIFIED_FAILURE ;
status = res ;
wpa_printf ( MSG_DEBUG , " FT: Postponed auth callback result for " MACSTR
" - status %u " , MAC2STR ( sm - > addr ) , status ) ;
@ -2568,7 +2936,7 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
int no_defer )
{
const char * msgtype = " pull response " ;
int ret = - 1 ;
int nak, ret = - 1 ;
struct ft_get_sta_ctx ctx ;
u8 s1kh_id [ ETH_ALEN ] ;
const u8 * f_nonce ;
@ -2590,6 +2958,12 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
ret = wpa_ft_rrb_rx_r1 ( wpa_auth , src_addr , FT_PACKET_R0KH_R1KH_RESP ,
enc , enc_len , auth , auth_len , msgtype , s1kh_id ,
no_defer ? NULL : & wpa_ft_rrb_rx_resp ) ;
if ( ret = = - 2 ) {
ret = 0 ;
nak = 1 ;
} else {
nak = 0 ;
}
if ( ret < 0 )
return - 1 ;
@ -2598,6 +2972,9 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
wpa_printf ( MSG_DEBUG ,
" FT: Response to a pending pull request for " MACSTR ,
MAC2STR ( ctx . sm - > addr ) ) ;
eloop_cancel_timeout ( wpa_ft_expire_pull , ctx . sm , NULL ) ;
if ( nak )
ctx . sm - > ft_pending_pull_left_retries = 0 ;
ft_finish_pull ( ctx . sm ) ;
}
@ -2629,7 +3006,11 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
const u8 * enc , size_t enc_len ,
const u8 * auth , size_t auth_len ,
struct ft_remote_seq * * rkh_seq ,
u8 * * key , size_t * key_len )
u8 * * key , size_t * key_len ,
struct ft_remote_r0kh * * r0kh_out ,
struct ft_remote_r1kh * * r1kh_out ,
struct ft_remote_r0kh * * r0kh_wildcard_out ,
struct ft_remote_r1kh * * r1kh_wildcard_out )
{
struct ft_remote_r0kh * r0kh = NULL ;
struct ft_remote_r1kh * r1kh = NULL ;
@ -2638,6 +3019,8 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
int to_r0kh , to_r1kh ;
u8 * plain = NULL ;
size_t plain_len = 0 ;
struct ft_remote_r0kh * r0kh_wildcard ;
struct ft_remote_r1kh * r1kh_wildcard ;
RRB_GET_AUTH ( FT_RRB_R0KH_ID , r0kh_id , " seq " , - 1 ) ;
RRB_GET_AUTH ( FT_RRB_R1KH_ID , r1kh_id , " seq " , FT_R1KH_ID_LEN ) ;
@ -2657,29 +3040,38 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
if ( ! to_r0kh ) {
wpa_ft_rrb_lookup_r0kh ( wpa_auth , f_r0kh_id , f_r0kh_id_len ,
& r0kh ) ;
if ( ! r0kh | | os_memcmp ( r0kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) {
& r0kh , & r0kh_wildcard ) ;
if ( ! r0kh_wildcard & &
( ! r0kh | | os_memcmp ( r0kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) ) {
wpa_hexdump ( MSG_DEBUG , " FT: Did not find R0KH-ID " ,
f_r0kh_id , f_r0kh_id_len ) ;
goto out ;
}
* key = r0kh - > key ;
* key_len = sizeof ( r0kh - > key ) ;
* rkh_seq = r0kh - > seq ;
if ( r0kh ) {
* key = r0kh - > key ;
* key_len = sizeof ( r0kh - > key ) ;
} else {
* key = r0kh_wildcard - > key ;
* key_len = sizeof ( r0kh_wildcard - > key ) ;
}
}
if ( ! to_r1kh ) {
wpa_ft_rrb_lookup_r1kh ( wpa_auth , f_r1kh_id , & r1kh ) ;
if ( ! r1kh | | os_memcmp ( r1kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) {
wpa_ft_rrb_lookup_r1kh ( wpa_auth , f_r1kh_id , & r1kh ,
& r1kh_wildcard ) ;
if ( ! r1kh_wildcard & &
( ! r1kh | | os_memcmp ( r1kh - > addr , src_addr , ETH_ALEN ) ! = 0 ) ) {
wpa_hexdump ( MSG_DEBUG , " FT: Did not find R1KH-ID " ,
f_r1kh_id , FT_R1KH_ID_LEN ) ;
goto out ;
}
* key = r1kh - > key ;
* key_len = sizeof ( r1kh - > key ) ;
* rkh_seq = r1kh - > seq ;
if ( r1kh ) {
* key = r1kh - > key ;
* key_len = sizeof ( r1kh - > key ) ;
} else {
* key = r1kh_wildcard - > key ;
* key_len = sizeof ( r1kh_wildcard - > key ) ;
}
}
if ( wpa_ft_rrb_decrypt ( * key , * key_len , enc , enc_len , auth , auth_len ,
@ -2688,6 +3080,39 @@ static int wpa_ft_rrb_rx_seq(struct wpa_authenticator *wpa_auth,
os_free ( plain ) ;
if ( ! to_r0kh ) {
if ( ! r0kh )
r0kh = wpa_ft_rrb_add_r0kh ( wpa_auth , r0kh_wildcard ,
src_addr , f_r0kh_id ,
f_r0kh_id_len ,
ftRRBseqTimeout ) ;
if ( ! r0kh )
goto out ;
wpa_ft_rrb_r0kh_replenish ( wpa_auth , r0kh , ftRRBseqTimeout ) ;
* rkh_seq = r0kh - > seq ;
if ( r0kh_out )
* r0kh_out = r0kh ;
if ( r0kh_wildcard_out )
* r0kh_wildcard_out = r0kh_wildcard ;
}
if ( ! to_r1kh ) {
if ( ! r1kh )
r1kh = wpa_ft_rrb_add_r1kh ( wpa_auth , r1kh_wildcard ,
src_addr , f_r1kh_id ,
ftRRBseqTimeout ) ;
if ( ! r1kh )
goto out ;
wpa_ft_rrb_r1kh_replenish ( wpa_auth , r1kh , ftRRBseqTimeout ) ;
* rkh_seq = r1kh - > seq ;
if ( r1kh_out )
* r1kh_out = r1kh ;
if ( r1kh_wildcard_out )
* r1kh_wildcard_out = r1kh_wildcard ;
}
return 0 ;
out :
return - 1 ;
@ -2704,7 +3129,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
struct ft_rrb_seq f_seq ;
const u8 * f_nonce , * f_r0kh_id , * f_r1kh_id ;
size_t f_nonce_len , f_r0kh_id_len , f_r1kh_id_len ;
struct ft_remote_seq * rkh_seq ;
struct ft_remote_seq * rkh_seq = NULL ;
u8 * packet = NULL , * key = NULL ;
size_t packet_len = 0 , key_len = 0 ;
struct tlv_list seq_resp_auth [ 5 ] ;
@ -2713,7 +3138,7 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth,
if ( wpa_ft_rrb_rx_seq ( wpa_auth , src_addr , FT_PACKET_R0KH_R1KH_SEQ_REQ ,
enc , enc_len , auth , auth_len , & rkh_seq , & key ,
& key_len ) < 0 )
& key_len , NULL , NULL , NULL , NULL ) < 0 )
goto out ;
RRB_GET_AUTH ( FT_RRB_NONCE , nonce , " seq request " , FT_RRB_NONCE_LEN ) ;
@ -2767,6 +3192,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth,
{
u8 * key = NULL ;
size_t key_len = 0 ;
struct ft_remote_r0kh * r0kh = NULL , * r0kh_wildcard = NULL ;
struct ft_remote_r1kh * r1kh = NULL , * r1kh_wildcard = NULL ;
const u8 * f_nonce , * f_seq ;
size_t f_nonce_len , f_seq_len ;
struct ft_remote_seq * rkh_seq = NULL ;
@ -2780,7 +3207,8 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth,
if ( wpa_ft_rrb_rx_seq ( wpa_auth , src_addr , FT_PACKET_R0KH_R1KH_SEQ_RESP ,
enc , enc_len , auth , auth_len , & rkh_seq , & key ,
& key_len ) < 0 )
& key_len , & r0kh , & r1kh , & r0kh_wildcard ,
& r1kh_wildcard ) < 0 )
goto out ;
RRB_GET_AUTH ( FT_RRB_NONCE , nonce , " seq response " , FT_RRB_NONCE_LEN ) ;
@ -2804,6 +3232,20 @@ static int wpa_ft_rrb_rx_seq_resp(struct wpa_authenticator *wpa_auth,
goto out ;
}
if ( r0kh ) {
wpa_ft_rrb_r0kh_replenish ( wpa_auth , r0kh ,
wpa_auth - > conf . rkh_pos_timeout ) ;
if ( r0kh_wildcard )
os_memcpy ( r0kh - > addr , src_addr , ETH_ALEN ) ;
}
if ( r1kh ) {
wpa_ft_rrb_r1kh_replenish ( wpa_auth , r1kh ,
wpa_auth - > conf . rkh_pos_timeout ) ;
if ( r1kh_wildcard )
os_memcpy ( r1kh - > addr , src_addr , ETH_ALEN ) ;
}
seq_ret = wpa_ft_rrb_seq_chk ( rkh_seq , src_addr , enc , enc_len , auth ,
auth_len , " seq response " , 1 ) ;
if ( seq_ret = = FT_RRB_SEQ_OK ) {
@ -2967,6 +3409,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
{
const u8 * auth , * enc ;
size_t alen , elen ;
int no_defer = 0 ;
wpa_printf ( MSG_DEBUG , " FT: RRB-OUI received frame from remote AP "
MACSTR , MAC2STR ( src_addr ) ) ;
@ -2984,7 +3427,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
" FT: RRB-OUI received frame from remote AP " MACSTR
" to multicast address " MACSTR ,
MAC2STR ( src_addr ) , MAC2STR ( dst_addr ) ) ;
return ;
no_defer = 1 ;
}
if ( data_len < sizeof ( u16 ) ) {
@ -3005,23 +3448,23 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
switch ( oui_suffix ) {
case FT_PACKET_R0KH_R1KH_PULL :
wpa_ft_rrb_rx_pull ( wpa_auth , src_addr , enc , elen , auth , alen ,
0 ) ;
no_defer ) ;
break ;
case FT_PACKET_R0KH_R1KH_RESP :
wpa_ft_rrb_rx_resp ( wpa_auth , src_addr , enc , elen , auth , alen ,
0 ) ;
no_defer ) ;
break ;
case FT_PACKET_R0KH_R1KH_PUSH :
wpa_ft_rrb_rx_push ( wpa_auth , src_addr , enc , elen , auth , alen ,
0 ) ;
no_defer ) ;
break ;
case FT_PACKET_R0KH_R1KH_SEQ_REQ :
wpa_ft_rrb_rx_seq_req ( wpa_auth , src_addr , enc , elen , auth , alen ,
0 ) ;
no_defer ) ;
break ;
case FT_PACKET_R0KH_R1KH_SEQ_RESP :
wpa_ft_rrb_rx_seq_resp ( wpa_auth , src_addr , enc , elen , auth ,
alen , 0 ) ;
alen , no_defer ) ;
break ;
}
}
@ -3079,6 +3522,8 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
if ( ! wpa_auth - > conf . pmk_r1_push )
return ;
if ( ! wpa_auth - > conf . r1kh_list )
return ;
r0 = wpa_auth - > ft_pmk_cache - > pmk_r0 ;
while ( r0 ) {
@ -3094,7 +3539,10 @@ void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
wpa_printf ( MSG_DEBUG , " FT: Deriving and pushing PMK-R1 keys to R1KHs "
" for STA " MACSTR , MAC2STR ( addr ) ) ;
for ( r1kh = wpa_auth - > conf . r1kh_list ; r1kh ; r1kh = r1kh - > next ) {
for ( r1kh = * wpa_auth - > conf . r1kh_list ; r1kh ; r1kh = r1kh - > next ) {
if ( is_zero_ether_addr ( r1kh - > addr ) | |
is_zero_ether_addr ( r1kh - > id ) )
continue ;
if ( wpa_ft_rrb_init_r1kh_seq ( r1kh ) < 0 )
continue ;
wpa_ft_generate_pmk_r1 ( wpa_auth , r0 , r1kh , addr ) ;