When DIRA is matched, configure PMK for pairing verification of previously paired peer. --- src/ap/wpa_auth.c | 18 +++++++++++++ src/ap/wpa_auth.h | 3 +++ src/p2p/p2p.c | 39 +++++++++++++++++++++++++++ src/p2p/p2p.h | 19 ++++++++++++++ src/rsn_supp/wpa.c | 17 ++++++++++++ src/rsn_supp/wpa.h | 2 ++ wpa_supplicant/p2p_supplicant.c | 58 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 156 insertions(+) diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 93f157d..20c809a 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -6557,6 +6557,24 @@ wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, pmkid); } +int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr, u8 **pmk, u16 *pmk_len, + u8 **pmkid) +{ + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = wpa_auth_pmksa_get(wpa_auth, sta_addr, NULL); + if (!pmksa) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get PMKSA for " MACSTR, + MAC2STR(sta_addr)); + return -1; + } + + *pmk = pmksa->pmk; + *pmk_len = pmksa->pmk_len; + *pmkid = pmksa->pmkid; + return 0; +} void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa, struct wpa_state_machine *sm, diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index b22c419..0d621a0 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -528,6 +528,9 @@ wpa_auth_get_pmksa_cache(struct wpa_authenticator *wpa_auth); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); +int wpa_auth_pmksa_get_pmk(struct wpa_authenticator *wpa_auth, + const u8 *sta_addr, u8 **pmk, u16 *pmk_len, + u8 **pmkid); struct rsn_pmksa_cache_entry * wpa_auth_pmksa_get_fils_cache_id(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, const u8 *pmkid); diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 216abf4..2c81ec5 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -5177,6 +5177,24 @@ int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, } +int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr, + u8 **dik_data, u16 *dik_len, u8 *cipher) +{ + struct p2p_device *dev = p2p_get_device(p2p, dev_addr); + if (!dev) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get device identity key for dev " + MACSTR, MAC2STR(dev_addr)); + return -1; + } + + *dik_data = dev->info.dik_data; + *dik_len = dev->info.dik_len; + *cipher = dev->info.dik_cipher_version; + + return 0; +} + + void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr) { os_memcpy(p2p->peer_filter, addr, ETH_ALEN); @@ -5931,6 +5949,14 @@ void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value) p2p->allow_6ghz = value; } +void p2p_validate_dira(struct p2p_data *p2p, struct p2p_device *dev, + const u8 *dira, u16 dira_len) +{ + if (p2p->cfg->validate_dira) + p2p->cfg->validate_dira(p2p->cfg->cb_ctx, p2p->cfg->dev_addr, + dev->info.p2p_device_addr, dira, + dira_len); +} struct wpabuf * p2p_usd_elems(struct p2p_data *p2p) { @@ -6035,6 +6061,9 @@ void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len, if (!ether_addr_equal(peer_addr, p2p_dev_addr)) os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN); + if (msg.dira && msg.dira_len) + p2p_validate_dira(p2p, dev, msg.dira, msg.dira_len); + p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR " dev_capab=0x%x group_capab=0x%x listen_freq=%d", MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab, @@ -6913,4 +6942,14 @@ int p2p_pasn_auth_rx(struct p2p_data *p2p, const struct ieee80211_mgmt *mgmt, } return ret; } + + +void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, + u8 *pmk, u16 pmk_len, u8 *pmkid) +{ + pasn_initiator_pmksa_cache_add(p2p->initiator_pmksa, src, dst, pmk, + pmk_len, pmkid); + pasn_responder_pmksa_cache_add(p2p->responder_pmksa, src, dst, pmk, + pmk_len, pmkid); +} #endif diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 9962b69..6024370 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -1337,6 +1337,21 @@ struct p2p_config { int freq); /** + * validate_dira - Function handler to validate dira against list of + * device identity keys available + * @ctx: Callback context from cb_ctx + * @own_addr: p2p device own address + * @peer_addr: p2p device address of the peer + * @dira: DIRA attribute present in the USD frames + * @dira_len: length of DIRA + * + * This function can be used to vaildate DIRA and configure PMK of + * paired/persistent peer from conf file. + */ + void (*validate_dira)(void *ctx, const u8 *own_addr, const u8 *peer_addr, + const u8 *dira, u16 dira_len); + + /** * pasn_send_mgmt - Function handler to transmit a Management frame * @ctx: Callback context from cb_ctx * @data : Frame to transmit @@ -2293,6 +2308,8 @@ int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr, u8 *iface_addr); int p2p_get_dev_addr(struct p2p_data *p2p, const u8 *iface_addr, u8 *dev_addr); +int p2p_get_dev_identity_key(struct p2p_data *p2p, const u8 *dev_addr, + u8 **dik_data, u16 *dik_len, u8 *cipher); void p2p_set_peer_filter(struct p2p_data *p2p, const u8 *addr); @@ -2697,4 +2714,6 @@ int p2p_pasn_parse_encrypted_data(struct p2p_data *p2p, const u8 *data, size_t len); int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data, size_t data_len, u8 acked, bool verify); +void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, + u8 *pmk, u16 pmk_len, u8 *pmkid); #endif /* P2P_H */ diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 52a4c74..3aa660d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -5547,6 +5547,23 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, akmp); } +int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, u8 **pmk, + u16 *pmk_len, u8 **pmkid) +{ + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = wpa_sm_pmksa_cache_get(sm, aa, NULL, NULL, 0); + if (!pmksa) { + wpa_printf(MSG_DEBUG, "P2P: Failed to get PMKSA for " MACSTR, + MAC2STR(aa)); + return -1; + } + + *pmk = pmksa->pmk; + *pmk_len = pmksa->pmk_len; + *pmkid = pmksa->pmkid; + return 0; +} void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, struct rsn_pmksa_cache_entry *entry) diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index d85dd9a..2d9ed50 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -254,6 +254,8 @@ struct rsn_pmksa_cache_entry * wpa_sm_pmksa_cache_get(struct wpa_sm *sm, const u8 *pmkid, const void *network_ctx, int akmp); +int wpa_sm_pmksa_get_pmk(struct wpa_sm *sm, const u8 *aa, u8 **pmk, + u16 *pmk_len, u8 **pmkid); void wpa_sm_pmksa_cache_remove(struct wpa_sm *sm, struct rsn_pmksa_cache_entry *entry); bool wpa_sm_has_ft_keys(struct wpa_sm *sm, const u8 *md); diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 0aeb9c6..903aa42 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -5152,6 +5152,63 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr, int status, #endif /* CONFIG_PASN */ } +void wpas_validate_dira(void *ctx, const u8 *own_addr, const u8 *peer_addr, + const u8 *dira, u16 dira_len) +{ + int ret; + u8 pmk[PMK_LEN_MAX]; + u8 pmkid[PMKID_LEN]; + u8 tag[DEVICE_MAX_HASH_LEN]; + u8 dik[DEVICE_IDENTITY_KEY_LEN]; + struct wpa_dev_ik *ik = NULL; + struct wpa_supplicant *wpa_s = ctx; + u8 data[DIR_STR_LEN + DEVICE_IDENTITY_NONCE_LEN + ETH_ALEN]; + + if (dira[0] != DIRA_CIPHER_VERSION_128) { + wpa_printf(MSG_ERROR, + "DIRA cipher version unsupported, (%d)", dira[0]); + return; + } + + os_memset(tag, 0, sizeof(tag)); + os_memset(data, 0, sizeof(data)); + os_memcpy(data, "DIR", DIR_STR_LEN); + os_memcpy(&data[DIR_STR_LEN], peer_addr, ETH_ALEN); + os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], &dira[1], + DEVICE_IDENTITY_NONCE_LEN); + + for (ik = wpa_s->conf->identity; ik; ik = ik->next) { + if (ik->dik_len != DEVICE_IDENTITY_KEY_LEN || + ik->dik_cipher != DIRA_CIPHER_VERSION_128) + continue; + + hexstr2bin(ik->dik_data, dik, DEVICE_IDENTITY_KEY_LEN); + ret = hmac_sha256(dik, DEVICE_IDENTITY_KEY_LEN, data, + sizeof(data), tag); + if (ret < 0) { + wpa_printf(MSG_ERROR, "DIRA Tag derivation failed"); + return; + } + + if (os_memcmp(tag, &dira[1 + DEVICE_IDENTITY_NONCE_LEN], + DEVICE_IDENTITY_TAG_LEN) == 0) { + wpa_printf(MSG_DEBUG, "DIRA Tag Matched"); + break; + } + } + + if (!ik) + return; + + hexstr2bin(ik->pmk, pmk, ik->pmk_len); + hexstr2bin(ik->pmkid, pmkid, PMKID_LEN); + +#ifdef CONFIG_PASN + p2p_pasn_pmksa_set_pmk(wpa_s->global->p2p, own_addr, peer_addr, pmk, + ik->pmk_len, pmkid); +#endif /* CONFIG_PASN */ +} + #ifdef CONFIG_PASN static void wpas_p2p_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit) { @@ -5449,6 +5506,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.register_bootstrap_comeback = wpas_p2p_register_bootstrap_comeback; p2p.bootstrap_req_rx = wpas_bootstrap_req_rx; p2p.bootstrap_completed = wpas_bootstrap_completed; + p2p.validate_dira = wpas_validate_dira; #ifdef CONFIG_PASN p2p.pasn_send_mgmt = wpas_p2p_pasn_send_mlme; p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies; -- 2.7.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap