]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PR: Derive and add DIRA in USD PR element
authorPeddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
Sat, 26 Apr 2025 18:27:32 +0000 (23:57 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 17 Oct 2025 10:22:51 +0000 (13:22 +0300)
Derive the Device Identity Resolution Attribute (DIRA) and add it to the
Proximity Ranging element. The DIRA attribute is used to resolve the
identity of a device even when MAC randomization causes the peer
device's MAC address to change. The DIRA attribute includes fields such
as the cipher version, a nonce, and a tag.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
src/common/proximity_ranging.c
src/common/proximity_ranging.h

index 8eb951eb28d9604c1328d01ecd036ef0a4d602b4..341c0de7c7892aabe38d1e0e77fed768c927a8aa 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "crypto/sha256.h"
 #include "proximity_ranging.h"
 
 
@@ -223,6 +224,61 @@ static void pr_get_ntb_capabilities(struct pr_data *pr,
 }
 
 
+static int pr_derive_dira(struct pr_data *pr, struct pr_dira *dira)
+{
+       u8 nonce[DEVICE_IDENTITY_NONCE_LEN];
+       u8 tag[DEVICE_MAX_HASH_LEN];
+       u8 data[DIR_STR_LEN + ETH_ALEN + DEVICE_IDENTITY_NONCE_LEN];
+
+       if (pr->cfg->dik_cipher != DIRA_CIPHER_VERSION_128) {
+               wpa_printf(MSG_INFO, "PR: Unsupported DIRA Cipher version %d",
+                          pr->cfg->dik_cipher);
+               return -1;
+       }
+
+       if (pr->cfg->dik_len != DEVICE_IDENTITY_KEY_LEN) {
+               wpa_printf(MSG_INFO, "PR: Invalid DIK length %zu",
+                          pr->cfg->dik_len);
+               return -1;
+       }
+
+       os_memset(data, 0, sizeof(data));
+
+       if (os_get_random(nonce, DEVICE_IDENTITY_NONCE_LEN) < 0) {
+               wpa_printf(MSG_INFO, "PR: Failed to generate DIRA nonce");
+               return -1;
+       }
+
+       /* Tag = Truncate-64(HMAC-SHA-256(DevIK, "DIR" || PR Device Address ||
+        *                                Nonce))
+        */
+       os_memcpy(data, "DIR", DIR_STR_LEN);
+       os_memcpy(&data[DIR_STR_LEN], pr->cfg->dev_addr, ETH_ALEN);
+       os_memcpy(&data[DIR_STR_LEN + ETH_ALEN], nonce,
+                 DEVICE_IDENTITY_NONCE_LEN);
+
+       if (hmac_sha256(pr->cfg->dik_data, pr->cfg->dik_len, data, sizeof(data),
+                       tag) < 0) {
+               wpa_printf(MSG_ERROR, "PR: Could not derive DIRA tag");
+               return -1;
+       }
+
+       os_memset(dira, 0, sizeof(struct pr_dira));
+       dira->cipher_version = pr->cfg->dik_cipher;
+       dira->nonce_len = DEVICE_IDENTITY_NONCE_LEN;
+       os_memcpy(dira->nonce, nonce, DEVICE_IDENTITY_NONCE_LEN);
+       dira->tag_len = DEVICE_IDENTITY_TAG_LEN;
+       os_memcpy(dira->tag, tag, DEVICE_IDENTITY_TAG_LEN);
+
+       wpa_hexdump_key(MSG_DEBUG, "PR: DIK", pr->cfg->dik_data,
+                       pr->cfg->dik_len);
+       wpa_hexdump(MSG_DEBUG, "PR: DIRA-NONCE", dira->nonce, dira->nonce_len);
+       wpa_hexdump(MSG_DEBUG, "PR: DIRA-TAG", dira->tag, dira->tag_len);
+
+       return 0;
+}
+
+
 static void pr_buf_add_channel_list(struct wpabuf *buf, const char *country,
                                    const struct pr_channels *chan)
 {
@@ -341,11 +397,35 @@ static void pr_buf_add_ntb_capa_info(struct wpabuf *buf,
 }
 
 
+static void pr_buf_add_dira(struct wpabuf *buf, const struct pr_dira *dira)
+{
+       u8 *len;
+       size_t _len;
+
+       /* Proximity Ranging Device Identity Resolution attribute */
+       wpabuf_put_u8(buf, PR_ATTR_DEVICE_IDENTITY_RESOLUTION);
+
+       /* Length to be filled */
+       len = wpabuf_put(buf, 2);
+
+       wpabuf_put_u8(buf, dira->cipher_version);
+       wpabuf_put_data(buf, dira->nonce, dira->nonce_len);
+       wpabuf_put_data(buf, dira->tag, dira->tag_len);
+
+       /* Update attribute length */
+       _len = (u8 *) wpabuf_put(buf, 0) - len - 2;
+       WPA_PUT_LE16(len, _len);
+
+       wpa_printf(MSG_DEBUG, "PR: * DIRA");
+}
+
+
 struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr)
 {
        u32 ie_type;
        struct wpabuf *buf, *buf2;
        struct pr_capabilities pr_caps;
+       struct pr_dira dira;
 
        buf = wpabuf_alloc(1000);
        if (!buf)
@@ -368,6 +448,9 @@ struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr)
                pr_buf_add_ntb_capa_info(buf, &ntb_caps);
        }
 
+       if (!pr_derive_dira(pr, &dira))
+               pr_buf_add_dira(buf, &dira);
+
        ie_type = (OUI_WFA << 8) | PR_OUI_TYPE;
        buf2 = pr_encaps_elem(buf, ie_type);
        wpabuf_free(buf);
index 45ae998fc723eb6d4bd3077a28a3fb6ffdc2701a..b05dc54c7e0626edcbed75fe6d863b6418fbfb88 100644 (file)
 #include "wps/wps_defs.h"
 
 #define DEVICE_IDENTITY_KEY_LEN 16
+#define DEVICE_IDENTITY_TAG_LEN 8
+#define DEVICE_IDENTITY_NONCE_LEN 8
+#define DIR_STR_LEN 3
+#define DEVICE_MAX_HASH_LEN 32
+
+/* DIRA Cipher versions */
+#define DIRA_CIPHER_VERSION_128 0
 
 /**
  * PR_MAX_OP_CLASSES - Maximum number of operating classes
@@ -317,6 +324,20 @@ struct pr_data {
        struct dl_list devices;
 };
 
+/* PR Device Identity Resolution Attribute parameters */
+struct pr_dira {
+       /* Cipher version type */
+       int cipher_version;
+       /* Nonce used in DIRA attribute */
+       u8 nonce[DEVICE_IDENTITY_NONCE_LEN];
+       /* Length of nonce */
+       size_t nonce_len;
+       /* Tag computed for nonce using NIK */
+       u8 tag[DEVICE_IDENTITY_TAG_LEN];
+       /* Length of tag in octets */
+       size_t tag_len;
+};
+
 struct pr_data * pr_init(const struct pr_config *cfg);
 void pr_deinit(struct pr_data *pr);
 struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr);