[PATCH 1/6] FT: Allow roaming between APs if IDs match MAC
Benjamin Berg
benjamin at sipsolutions.net
Wed Sep 21 05:17:01 PDT 2016
On Mi, 2016-09-21 at 10:32 +0200, Michael Braun wrote:
> do I undertand correctly that this change also requires
> nas_identifier to be the BSSID?
That is correct. The code assumes that the nas_identifier matches the
BSSID to be able to send requests without having prior knowledge about
other APs in the network.
Benjamin
> Am 19.09.2016 17:47, schrieb Benjamin Berg:
> >
> > From: Benjamin Berg <benjamin.berg at open-mesh.com>
> >
> > This patch adds a new option to set a static key for the
> > communication
> > between the APs during 802.11r roaming. For this to work hostapd
> > has to assume that both the nas_identifier and R1KH identifier
> > match
> > the MAC/BSSID of the hostapd instance.
> >
> > The advantage is that all APs can share a common configuration and
> > roaming
> > works throughout the network without each AP having a list of all
> > other
> > APs and a key for them. It is assumed that all APs can communicate
> > on a
> > common layer two network.
> >
> > Signed-off-by: Benjamin Berg <benjamin.berg at open-mesh.com>
> > ---
> > hostapd/config_file.c | 9 +++
> > src/ap/ap_config.h | 2 +
> > src/ap/wpa_auth.h | 2 +
> > src/ap/wpa_auth_ft.c | 173
> > +++++++++++++++++++++++++++++++++++++------------
> > src/ap/wpa_auth_glue.c | 2 +
> > 5 files changed, 146 insertions(+), 42 deletions(-)
> >
> > diff --git a/hostapd/config_file.c b/hostapd/config_file.c
> > index 5079f69..a43fa2f 100644
> > --- a/hostapd/config_file.c
> > +++ b/hostapd/config_file.c
> > @@ -2555,6 +2555,15 @@ static int hostapd_config_fill(struct
> > hostapd_config *conf,
> > line, pos);
> > return 1;
> > }
> > + } else if (os_strcmp(buf, "ft_remote_key") == 0) {
> > +
> > + bss->ft_remote_trust_khid = 1;
> > +
> > + if (hexstr2bin(pos, bss->ft_remote_key,
> > sizeof(bss->ft_remote_key)))
> > {
> > + wpa_printf(MSG_ERROR, "Invalid FT
> > communication key: '%s'", pos);
> > + return 1;
> > + }
> > +
> > } else if (os_strcmp(buf, "pmk_r1_push") == 0) {
> > bss->pmk_r1_push = atoi(pos);
> > } else if (os_strcmp(buf, "ft_over_ds") == 0) {
> > diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
> > index 8c8f7e2..5896f90 100644
> > --- a/src/ap/ap_config.h
> > +++ b/src/ap/ap_config.h
> > @@ -337,6 +337,8 @@ struct hostapd_bss_config {
> > u32 reassociation_deadline;
> > struct ft_remote_r0kh *r0kh_list;
> > struct ft_remote_r1kh *r1kh_list;
> > + int ft_remote_trust_khid;
> > + u8 ft_remote_key[16];
> > int pmk_r1_push;
> > int ft_over_ds;
> > #endif /* CONFIG_IEEE80211R */
> > diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
> > index 0de8d97..cd70912 100644
> > --- a/src/ap/wpa_auth.h
> > +++ b/src/ap/wpa_auth.h
> > @@ -168,6 +168,8 @@ struct wpa_auth_config {
> > u32 reassociation_deadline;
> > struct ft_remote_r0kh *r0kh_list;
> > struct ft_remote_r1kh *r1kh_list;
> > + int ft_remote_trust_khid;
> > + u8 ft_remote_key[16];
> > int pmk_r1_push;
> > int ft_over_ds;
> > #endif /* CONFIG_IEEE80211R */
> > diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
> > index 42242a5..a6e277d 100644
> > --- a/src/ap/wpa_auth_ft.c
> > +++ b/src/ap/wpa_auth_ft.c
> > @@ -300,30 +300,125 @@ static int wpa_ft_fetch_pmk_r1(struct
> > wpa_authenticator *wpa_auth,
> > return -1;
> > }
> >
> > -
> > -static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
> > - const u8 *ies, size_t ies_len,
> > - const u8 *pmk_r0_name)
> > +static int wpa_ft_r0kh_find_by_id(struct wpa_authenticator
> > *wpa_auth,
> > + const u8 *r0kh_id,
> > + int r0kh_id_len,
> > + u8 *addr,
> > + u8 *key)
> > {
> > struct ft_remote_r0kh *r0kh;
> > - struct ft_r0kh_r1kh_pull_frame frame, f;
> >
> > - r0kh = sm->wpa_auth->conf.r0kh_list;
> > + /* First try to lookup in list. */
> > + r0kh = wpa_auth->conf.r0kh_list;
> > while (r0kh) {
> > - if (r0kh->id_len == sm->r0kh_id_len &&
> > - os_memcmp_const(r0kh->id, sm->r0kh_id, sm-
> > >r0kh_id_len) ==
> > + if (r0kh->id_len == r0kh_id_len &&
> > + os_memcmp_const(r0kh->id, r0kh_id,
> > r0kh_id_len) ==
> > 0)
> > break;
> > r0kh = r0kh->next;
> > }
> > if (r0kh == NULL) {
> > - wpa_hexdump(MSG_DEBUG, "FT: Did not find R0KH-ID",
> > + /* If we trust the KHID to be a MAC, then use this
> > instead.
> > + **/
> > + if (wpa_auth->conf.ft_remote_trust_khid &&
> > r0kh_id_len == (3*6-1)) {
> > + if (hwaddr_aton((char*) r0kh_id, addr)) {
> > + return -1;
> > + }
> > + os_memcpy(key, wpa_auth-
> > >conf.ft_remote_key,
> > + sizeof(wpa_auth-
> > >conf.ft_remote_key));
> > + } else {
> > + return -1;
> > + }
> > + } else {
> > + os_memcpy(key, r0kh->key,
> > + sizeof(r0kh->key));
> > + os_memcpy(addr, r0kh->addr,
> > + ETH_ALEN);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int wpa_ft_r0kh_find_by_addr(struct wpa_authenticator
> > *wpa_auth,
> > + const u8 *r0kh_addr,
> > + u8 *key)
> > +{
> > + struct ft_remote_r0kh *r0kh;
> > +
> > + /* First try to lookup in list. */
> > + r0kh = wpa_auth->conf.r0kh_list;
> > + while (r0kh) {
> > + if (os_memcmp_const(r0kh->addr, r0kh_addr,
> > ETH_ALEN) == 0)
> > + break;
> > + r0kh = r0kh->next;
> > + }
> > + if (r0kh == NULL) {
> > + /* If we trust the KHID to be a MAC, then use this
> > instead.
> > + **/
> > + if (wpa_auth->conf.ft_remote_trust_khid) {
> > + os_memcpy(key, wpa_auth-
> > >conf.ft_remote_key,
> > + sizeof(wpa_auth-
> > >conf.ft_remote_key));
> > + } else {
> > + return -1;
> > + }
> > + } else {
> > + os_memcpy(key, r0kh->key,
> > + sizeof(r0kh->key));
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int wpa_ft_r1kh_find_by_addr(struct wpa_authenticator
> > *wpa_auth,
> > + const u8 *src_addr,
> > + u8 *id,
> > + u8 *key)
> > +{
> > + struct ft_remote_r1kh *r1kh;
> > +
> > + /* First try to lookup in list. */
> > + r1kh = wpa_auth->conf.r1kh_list;
> > + while (r1kh) {
> > + if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) ==
> > 0)
> > + break;
> > + r1kh = r1kh->next;
> > + }
> > + if (r1kh == NULL) {
> > + /* If we trust the KHID to be a MAC, then use this
> > instead.
> > + **/
> > + if (wpa_auth->conf.ft_remote_trust_khid) {
> > + os_memcpy(id, src_addr, ETH_ALEN);
> > + os_memcpy(key, wpa_auth-
> > >conf.ft_remote_key,
> > + sizeof(wpa_auth-
> > >conf.ft_remote_key));
> > + } else {
> > + return -1;
> > + }
> > + } else {
> > + os_memcpy(id, r1kh->id, ETH_ALEN);
> > + os_memcpy(key, r1kh->key,
> > + sizeof(r1kh->key));
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm,
> > + const u8 *ies, size_t ies_len,
> > + const u8 *pmk_r0_name)
> > +{
> > + macaddr r0kh_addr;
> > + u8 r0kh_key[16];
> > + struct ft_r0kh_r1kh_pull_frame frame, f;
> > +
> > + if (wpa_ft_r0kh_find_by_id(sm->wpa_auth, sm->r0kh_id,
> > sm->r0kh_id_len,
> > + r0kh_addr, r0kh_key)) {
> > + wpa_hexdump(MSG_DEBUG, "FT: Cannot pull PMK-R1 for
> > R0KH",
> > sm->r0kh_id, sm->r0kh_id_len);
> > return -1;
> > }
> >
> > wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to
> > remote R0KH "
> > - "address " MACSTR, MAC2STR(r0kh->addr));
> > + "address " MACSTR, MAC2STR(r0kh_addr));
> >
> > os_memset(&frame, 0, sizeof(frame));
> > frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
> > @@ -345,7 +440,7 @@ static int wpa_ft_pull_pmk_r1(struct
> > wpa_state_machine *sm,
> > os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN);
> > os_memset(f.pad, 0, sizeof(f.pad));
> >
> > - if (aes_wrap(r0kh->key, sizeof(r0kh->key),
> > + if (aes_wrap(r0kh_key, sizeof(r0kh_key),
> > (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
> > f.nonce, frame.nonce) < 0)
> > return -1;
> > @@ -355,7 +450,7 @@ static int wpa_ft_pull_pmk_r1(struct
> > wpa_state_machine *sm,
> > if (sm->ft_pending_req_ies == NULL)
> > return -1;
> >
> > - wpa_ft_rrb_send(sm->wpa_auth, r0kh->addr, (u8 *) &frame,
> > sizeof(frame));
> > + wpa_ft_rrb_send(sm->wpa_auth, r0kh_addr, (u8 *) &frame,
> > sizeof(frame));
> >
> > return 0;
> > }
> > @@ -1313,7 +1408,8 @@ static int wpa_ft_rrb_rx_pull(struct
> > wpa_authenticator *wpa_auth,
> > struct ft_r0kh_r1kh_pull_frame f;
> > const u8 *crypt;
> > u8 *plain;
> > - struct ft_remote_r1kh *r1kh;
> > + u8 r1kh_id[FT_R1KH_ID_LEN];
> > + u8 r1kh_key[16];
> > struct ft_r0kh_r1kh_resp_frame resp, r;
> > u8 pmk_r0[PMK_LEN];
> > int pairwise;
> > @@ -1323,13 +1419,8 @@ static int wpa_ft_rrb_rx_pull(struct
> > wpa_authenticator *wpa_auth,
> > if (data_len < sizeof(f))
> > return -1;
> >
> > - r1kh = wpa_auth->conf.r1kh_list;
> > - while (r1kh) {
> > - if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) ==
> > 0)
> > - break;
> > - r1kh = r1kh->next;
> > - }
> > - if (r1kh == NULL) {
> > +
> > + if (wpa_ft_r1kh_find_by_addr(wpa_auth, src_addr, r1kh_id,
> > r1kh_key)
> > != 0) {
> > wpa_printf(MSG_DEBUG, "FT: No matching R1KH
> > address found for "
> > "PMK-R1 pull source address " MACSTR,
> > MAC2STR(src_addr));
> > @@ -1341,7 +1432,7 @@ static int wpa_ft_rrb_rx_pull(struct
> > wpa_authenticator *wpa_auth,
> > plain = ((u8 *) &f) + offsetof(struct
> > ft_r0kh_r1kh_pull_frame,
> > nonce);
> > /* aes_unwrap() does not support inplace decryption, so
> > use a
> > temporary
> > * buffer for the data. */
> > - if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
> > + if (aes_unwrap(r1kh_key, sizeof(r1kh_key),
> > (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
> > crypt, plain) < 0) {
> > wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-
> > R1 pull "
> > @@ -1349,6 +1440,16 @@ static int wpa_ft_rrb_rx_pull(struct
> > wpa_authenticator *wpa_auth,
> > return -1;
> > }
> >
> > + /* Ensure that R1KH-ID matches the expected value. */
> > + if (os_memcmp(r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN) != 0) {
> > + wpa_printf(MSG_ERROR, "FT: PMK-R1 pull included
> > R1KH_ID "
> > + "(" MACSTR ") that did not match the
> > packet "
> > + "senders ID (" MACSTR ", MAC " MACSTR
> > ")",
> > + MAC2STR(f.r1kh_id), MAC2STR(r1kh_id),
> > + MAC2STR(src_addr));
> > + return -1;
> > + }
> > +
> > wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
> > f.nonce, sizeof(f.nonce));
> > wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
> > @@ -1382,7 +1483,7 @@ static int wpa_ft_rrb_rx_pull(struct
> > wpa_authenticator *wpa_auth,
> > r.pairwise = host_to_le16(pairwise);
> > os_memset(r.pad, 0, sizeof(r.pad));
> >
> > - if (aes_wrap(r1kh->key, sizeof(r1kh->key),
> > + if (aes_wrap(r1kh_key, sizeof(r1kh_key),
> > (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
> > r.nonce, resp.nonce) < 0) {
> > os_memset(pmk_r0, 0, PMK_LEN);
> > @@ -1449,7 +1550,7 @@ static int wpa_ft_rrb_rx_resp(struct
> > wpa_authenticator *wpa_auth,
> > struct ft_r0kh_r1kh_resp_frame f;
> > const u8 *crypt;
> > u8 *plain;
> > - struct ft_remote_r0kh *r0kh;
> > + u8 r0kh_key[16];
> > int pairwise, res;
> >
> > wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull
> > response");
> > @@ -1457,14 +1558,8 @@ static int wpa_ft_rrb_rx_resp(struct
> > wpa_authenticator *wpa_auth,
> > if (data_len < sizeof(f))
> > return -1;
> >
> > - r0kh = wpa_auth->conf.r0kh_list;
> > - while (r0kh) {
> > - if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) ==
> > 0)
> > - break;
> > - r0kh = r0kh->next;
> > - }
> > - if (r0kh == NULL) {
> > - wpa_printf(MSG_DEBUG, "FT: No matching R0KH
> > address found for "
> > + if (wpa_ft_r0kh_find_by_addr(wpa_auth, src_addr,
> > r0kh_key)) {
> > + wpa_printf(MSG_DEBUG, "FT: No R0KH address found
> > for "
> > "PMK-R0 pull response source address "
> > MACSTR,
> > MAC2STR(src_addr));
> > return -1;
> > @@ -1475,7 +1570,7 @@ static int wpa_ft_rrb_rx_resp(struct
> > wpa_authenticator *wpa_auth,
> > plain = ((u8 *) &f) + offsetof(struct
> > ft_r0kh_r1kh_resp_frame,
> > nonce);
> > /* aes_unwrap() does not support inplace decryption, so
> > use a
> > temporary
> > * buffer for the data. */
> > - if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
> > + if (aes_unwrap(r0kh_key, sizeof(r0kh_key),
> > (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
> > crypt, plain) < 0) {
> > wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-
> > R1 pull "
> > @@ -1518,7 +1613,7 @@ static int wpa_ft_rrb_rx_push(struct
> > wpa_authenticator *wpa_auth,
> > struct ft_r0kh_r1kh_push_frame f;
> > const u8 *crypt;
> > u8 *plain;
> > - struct ft_remote_r0kh *r0kh;
> > + u8 r0kh_key[16];
> > struct os_time now;
> > os_time_t tsend;
> > int pairwise;
> > @@ -1528,14 +1623,8 @@ static int wpa_ft_rrb_rx_push(struct
> > wpa_authenticator *wpa_auth,
> > if (data_len < sizeof(f))
> > return -1;
> >
> > - r0kh = wpa_auth->conf.r0kh_list;
> > - while (r0kh) {
> > - if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) ==
> > 0)
> > - break;
> > - r0kh = r0kh->next;
> > - }
> > - if (r0kh == NULL) {
> > - wpa_printf(MSG_DEBUG, "FT: No matching R0KH
> > address found for "
> > + if (wpa_ft_r0kh_find_by_addr(wpa_auth, src_addr,
> > r0kh_key)) {
> > + wpa_printf(MSG_DEBUG, "FT: No R0KH address found
> > for "
> > "PMK-R0 push source address " MACSTR,
> > MAC2STR(src_addr));
> > return -1;
> > @@ -1547,7 +1636,7 @@ static int wpa_ft_rrb_rx_push(struct
> > wpa_authenticator *wpa_auth,
> > timestamp);
> > /* aes_unwrap() does not support inplace decryption, so
> > use a
> > temporary
> > * buffer for the data. */
> > - if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
> > + if (aes_unwrap(r0kh_key, sizeof(r0kh_key),
> > (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
> > crypt, plain) < 0) {
> > wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-
> > R1 push from "
> > diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
> > index 2142414..90e39a4 100644
> > --- a/src/ap/wpa_auth_glue.c
> > +++ b/src/ap/wpa_auth_glue.c
> > @@ -71,6 +71,8 @@ static void hostapd_wpa_auth_conf(struct
> > hostapd_bss_config *conf,
> > wconf->reassociation_deadline = conf-
> > >reassociation_deadline;
> > wconf->r0kh_list = conf->r0kh_list;
> > wconf->r1kh_list = conf->r1kh_list;
> > + wconf->ft_remote_trust_khid = conf->ft_remote_trust_khid;
> > + os_memcpy(wconf->ft_remote_key, conf->ft_remote_key,
> > sizeof(wconf->ft_remote_key));
> > wconf->pmk_r1_push = conf->pmk_r1_push;
> > wconf->ft_over_ds = conf->ft_over_ds;
> > #endif /* CONFIG_IEEE80211R */
>
> _______________________________________________
> Hostap mailing list
> Hostap at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/hostap
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/hostap/attachments/20160921/17a39065/attachment.sig>
More information about the Hostap
mailing list