diff mbox series

[v3,22/25] P2P: Add support to validate DIRA and configure PMK

Message ID 1722850403-8852-23-git-send-email-quic_shivbara@quicinc.com
State Deferred
Headers show
Series Add support for P2P2 | expand

Commit Message

Shivani Baranwal Aug. 5, 2024, 9:33 a.m. UTC
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 mbox series

Patch

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;