]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P2: Validate DIRA and configure PMK
authorShivani Baranwal <quic_shivbara@quicinc.com>
Sun, 4 Aug 2024 22:41:30 +0000 (04:11 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 1 Nov 2024 17:06:55 +0000 (19:06 +0200)
When DIRA is matched, configure PMK for pairing verification of a
previously paired peer.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
src/p2p/p2p.c
src/p2p/p2p.h
wpa_supplicant/p2p_supplicant.c

index 6312f58343fbd46406b92109d29a162b107eceb4..bb970f8028e620beda7463f1daabda7290f630b9 100644 (file)
@@ -6006,6 +6006,16 @@ static int p2p_derive_nonce_tag(struct p2p_data *p2p)
 }
 
 
+static 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,
+                                       dev->info.p2p_device_addr,
+                                       dira, dira_len);
+}
+
+
 struct wpabuf * p2p_usd_elems(struct p2p_data *p2p)
 {
        struct wpabuf *buf;
@@ -6117,6 +6127,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,
@@ -7032,4 +7045,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,
+                           const u8 *pmk, size_t pmk_len, const 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 /* CONFIG_PASN */
index cd214d4841109ca975946458f502cd0b10994752..c7a803bc3d88b47fdd299c09ac5d8c12d72504e2 100644 (file)
@@ -1325,6 +1325,22 @@ struct p2p_config {
        void (*bootstrap_completed)(void *ctx, const u8 *addr,
                                    enum p2p_status_code status, int freq);
 
+       /**
+        * validate_dira - Indicate reception of DIRA to be validated against a
+        *      list of available device identity keys
+        * @ctx: Callback context from cb_ctx
+        * @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 validate DIRA and configure PMK of a
+        * paired/persistent peer from configuration. The handler function is
+        * expected to call p2p_pasn_pmksa_set_pmk() to set the PMK/PMKID in
+        * case a matching entry is found.
+        */
+       void (*validate_dira)(void *ctx, const u8 *peer_addr,
+                             const u8 *dira, size_t dira_len);
+
        /**
         * pasn_send_mgmt - Function handler to transmit a Management frame
         * @ctx: Callback context from cb_ctx
@@ -2705,5 +2721,7 @@ int p2p_parse_data_element(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, bool acked, bool verify);
 int p2p_config_sae_password(struct p2p_data *p2p, const char *pw);
+void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst,
+                           const u8 *pmk, size_t pmk_len, const u8 *pmkid);
 
 #endif /* P2P_H */
index 1cbe6f1aa08569aab364d10f33a2ed57a47e4cb2..e967efd892906eae24238e39668b7c7318fa0c23 100644 (file)
@@ -5223,6 +5223,70 @@ static void wpas_bootstrap_completed(void *ctx, const u8 *addr,
 }
 
 
+static void wpas_validate_dira(void *ctx, const u8 *peer_addr,
+                              const u8 *dira, size_t dira_len)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+       int ret;
+       u8 tag[DEVICE_MAX_HASH_LEN];
+       struct wpa_dev_ik *ik;
+       const u8 *addr[3];
+       size_t len[3];
+       const char *label = "DIR";
+
+       if (dira_len < 1 || dira[0] != DIRA_CIPHER_VERSION_128) {
+               wpa_printf(MSG_ERROR,
+                          "P2P2: Unsupported DIRA cipher version %d", dira[0]);
+               return;
+       }
+
+       if (dira_len < 1 + DEVICE_IDENTITY_NONCE_LEN + DEVICE_IDENTITY_TAG_LEN)
+       {
+               wpa_printf(MSG_INFO, "P2P2: Truncated DIRA (length %zu)",
+                          dira_len);
+               return;
+       }
+
+       addr[0] = (const u8 *) label;
+       len[0] = DIR_STR_LEN;
+       addr[1] = peer_addr;
+       len[1] = ETH_ALEN;
+       addr[2] = &dira[1];
+       len[2] = DEVICE_IDENTITY_NONCE_LEN;
+
+       for (ik = wpa_s->conf->identity; ik; ik = ik->next) {
+               if (wpabuf_len(ik->dik) != DEVICE_IDENTITY_KEY_LEN ||
+                   ik->dik_cipher != DIRA_CIPHER_VERSION_128)
+                       continue;
+
+               ret = hmac_sha256_vector(wpabuf_head(ik->dik),
+                                        DEVICE_IDENTITY_KEY_LEN,
+                                        3, addr, len, tag);
+               if (ret < 0) {
+                       wpa_printf(MSG_ERROR,
+                                  "P2P2: Failed to derive DIRA Tag");
+                       return;
+               }
+
+               if (os_memcmp(tag, &dira[1 + DEVICE_IDENTITY_NONCE_LEN],
+                             DEVICE_IDENTITY_TAG_LEN) == 0) {
+                       wpa_printf(MSG_DEBUG, "P2P2: DIRA Tag matched");
+                       break;
+               }
+       }
+
+       if (!ik)
+               return;
+
+#ifdef CONFIG_PASN
+       p2p_pasn_pmksa_set_pmk(wpa_s->global->p2p, wpa_s->global->p2p_dev_addr,
+                              peer_addr,
+                              wpabuf_head(ik->pmk), wpabuf_len(ik->pmk),
+                              wpabuf_head(ik->pmkid));
+#endif /* CONFIG_PASN */
+}
+
+
 #ifdef CONFIG_PASN
 
 static int wpas_p2p_initiate_pasn_verify(struct wpa_supplicant *wpa_s,
@@ -5432,6 +5496,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_mgmt;
        p2p.prepare_data_element = wpas_p2p_prepare_data_element;