]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP2: PKEXv2 core protocol changes
authorJouni Malinen <quic_jouni@quicinc.com>
Tue, 7 Dec 2021 15:04:48 +0000 (17:04 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 7 Dec 2021 21:26:29 +0000 (23:26 +0200)
Add support for PKEXv2 core protocol. This defines a new PKEX Exchange
Request message type with protocol negotiation and different rules for
key derivation with PKEXv2 or newer is used.

This does not change existing behavior for PKEX, i.e., the PKEXv1
variant will still be used by default.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/ap/dpp_hostapd.c
src/common/dpp.h
src/common/dpp_crypto.c
src/common/dpp_i.h
src/common/dpp_pkex.c
wpa_supplicant/dpp_supplicant.c

index cb6d2c4b832d041f51ece09111f6373aece42bea..13e1fc5bdd961a3662251ec32ed7cbac9db55802 100644 (file)
@@ -1713,7 +1713,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 static void
 hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
                                 const u8 *buf, size_t len,
-                                unsigned int freq)
+                                unsigned int freq, bool v2)
 {
        struct wpabuf *msg;
 
@@ -1741,7 +1741,7 @@ hostapd_dpp_rx_pkex_exchange_req(struct hostapd_data *hapd, const u8 *src,
                                                  hapd->own_addr, src,
                                                  hapd->dpp_pkex_identifier,
                                                  hapd->dpp_pkex_code,
-                                                 buf, len);
+                                                 buf, len, v2);
        if (!hapd->dpp_pkex) {
                wpa_printf(MSG_DEBUG,
                           "DPP: Failed to process the request - ignore it");
@@ -1953,8 +1953,18 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
        case DPP_PA_PEER_DISCOVERY_REQ:
                hostapd_dpp_rx_peer_disc_req(hapd, src, buf, len, freq);
                break;
+#ifdef CONFIG_DPP3
        case DPP_PA_PKEX_EXCHANGE_REQ:
-               hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq);
+               /* This is for PKEXv2, but for now, process only with
+                * CONFIG_DPP3 to avoid issues with a capability that has not
+                * been tested with other implementations. */
+               hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+                                                true);
+               break;
+#endif /* CONFIG_DPP3 */
+       case DPP_PA_PKEX_V1_EXCHANGE_REQ:
+               hostapd_dpp_rx_pkex_exchange_req(hapd, src, buf, len, freq,
+                                                false);
                break;
        case DPP_PA_PKEX_EXCHANGE_RESP:
                hostapd_dpp_rx_pkex_exchange_resp(hapd, src, buf, len, freq);
@@ -2161,15 +2171,16 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
        if (!hapd->dpp_pkex_code)
                return -1;
 
-       if (os_strstr(cmd, " init=1")) {
+       if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
                struct wpabuf *msg;
+               bool v2 = os_strstr(cmd, " init=2") != NULL;
 
                wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
                dpp_pkex_free(hapd->dpp_pkex);
                hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi,
                                               hapd->own_addr,
                                               hapd->dpp_pkex_identifier,
-                                              hapd->dpp_pkex_code);
+                                              hapd->dpp_pkex_code, v2);
                if (!hapd->dpp_pkex)
                        return -1;
 
@@ -2177,7 +2188,8 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd)
                /* TODO: Which channel to use? */
                wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
                        " freq=%u type=%d", MAC2STR(broadcast), 2437,
-                       DPP_PA_PKEX_EXCHANGE_REQ);
+                       v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+                       DPP_PA_PKEX_V1_EXCHANGE_REQ);
                hostapd_drv_send_action(hapd, 2437, 0, broadcast,
                                        wpabuf_head(msg), wpabuf_len(msg));
        }
index e8e8b140b2a731de69470030fe5d09d90a818296..8d62a0e2ac3b7cfb573dbaa0cf5b6f7aba7c9a60 100644 (file)
@@ -43,7 +43,7 @@ enum dpp_public_action_frame_type {
        DPP_PA_AUTHENTICATION_CONF = 2,
        DPP_PA_PEER_DISCOVERY_REQ = 5,
        DPP_PA_PEER_DISCOVERY_RESP = 6,
-       DPP_PA_PKEX_EXCHANGE_REQ = 7,
+       DPP_PA_PKEX_V1_EXCHANGE_REQ = 7,
        DPP_PA_PKEX_EXCHANGE_RESP = 8,
        DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
        DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
@@ -54,6 +54,7 @@ enum dpp_public_action_frame_type {
        DPP_PA_RECONFIG_AUTH_REQ = 15,
        DPP_PA_RECONFIG_AUTH_RESP = 16,
        DPP_PA_RECONFIG_AUTH_CONF = 17,
+       DPP_PA_PKEX_EXCHANGE_REQ = 18,
 };
 
 enum dpp_attribute_id {
@@ -175,6 +176,7 @@ struct dpp_pkex {
        unsigned int initiator:1;
        unsigned int exchange_done:1;
        unsigned int failed:1;
+       unsigned int v2:1;
        struct dpp_bootstrap_info *own_bi;
        u8 own_mac[ETH_ALEN];
        u8 peer_mac[ETH_ALEN];
@@ -192,6 +194,7 @@ struct dpp_pkex {
        unsigned int exch_req_wait_time;
        unsigned int exch_req_tries;
        unsigned int freq;
+       u8 peer_version;
 };
 
 enum dpp_akm {
@@ -601,15 +604,15 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 int dpp_get_connector_version(const char *connector);
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
                                const u8 *own_mac,
-                               const char *identifier,
-                               const char *code);
+                               const char *identifier, const char *code,
+                               bool v2);
 struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                                           struct dpp_bootstrap_info *bi,
                                           const u8 *own_mac,
                                           const u8 *peer_mac,
                                           const char *identifier,
                                           const char *code,
-                                          const u8 *buf, size_t len);
+                                          const u8 *buf, size_t len, bool v2);
 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
                                          const u8 *peer_mac,
                                          const u8 *buf, size_t len);
index da59730eb7b79f4892ae46ddbb0e217c67cece31..300416fb12ecced6199822c0fb3a06c3ae947a4e 100644 (file)
@@ -1447,12 +1447,15 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
        struct crypto_bignum *hash_bn = NULL;
        struct crypto_ec *ec = NULL;
 
-       /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
+       /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
 
-       wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init));
-       addr[num_elem] = mac_init;
-       len[num_elem] = ETH_ALEN;
-       num_elem++;
+       if (mac_init) {
+               wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR,
+                          MAC2STR(mac_init));
+               addr[num_elem] = mac_init;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
        if (identifier) {
                wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
                           identifier);
@@ -1467,7 +1470,7 @@ dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, const u8 *mac_init,
        if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
                goto fail;
        wpa_hexdump_key(MSG_DEBUG,
-                       "DPP: H(MAC-Initiator | [identifier |] code)",
+                       "DPP: H([MAC-Initiator |] [identifier |] code)",
                        hash, curve->hash_len);
        Pi_key = dpp_pkex_get_role_elem(curve, 1);
        if (!Pi_key)
@@ -1519,12 +1522,15 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
        struct crypto_bignum *hash_bn = NULL;
        struct crypto_ec *ec = NULL;
 
-       /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
+       /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
 
-       wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp));
-       addr[num_elem] = mac_resp;
-       len[num_elem] = ETH_ALEN;
-       num_elem++;
+       if (mac_resp) {
+               wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR,
+                          MAC2STR(mac_resp));
+               addr[num_elem] = mac_resp;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
        if (identifier) {
                wpa_printf(MSG_DEBUG, "DPP: code identifier: %s",
                           identifier);
@@ -1539,7 +1545,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
        if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0)
                goto fail;
        wpa_hexdump_key(MSG_DEBUG,
-                       "DPP: H(MAC-Responder | [identifier |] code)",
+                       "DPP: H([MAC-Responder |] [identifier |] code)",
                        hash, curve->hash_len);
        Pr_key = dpp_pkex_get_role_elem(curve, 0);
        if (!Pr_key)
@@ -1578,6 +1584,7 @@ fail:
 
 
 int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+                     u8 ver_init, u8 ver_resp,
                      const u8 *Mx, size_t Mx_len,
                      const u8 *Nx, size_t Nx_len,
                      const char *code,
@@ -1589,7 +1596,10 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
        u8 *info, *pos;
        size_t info_len;
 
-       /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
+       /*
+        * v1: info = MAC-Initiator | MAC-Responder
+        * v2: info = Protocol Version-Initiator | Protocol Version-Responder
+        * z = HKDF(<>, info | M.x | N.x | code, K.x)
         */
 
        /* HKDF-Extract(<>, IKM=K.x) */
@@ -1598,15 +1608,24 @@ int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
                return -1;
        wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)",
                        prk, hash_len);
-       info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code);
+       if (mac_init && mac_resp)
+               info_len = 2 * ETH_ALEN;
+       else
+               info_len = 2;
+       info_len += Mx_len + Nx_len + os_strlen(code);
        info = os_malloc(info_len);
        if (!info)
                return -1;
        pos = info;
-       os_memcpy(pos, mac_init, ETH_ALEN);
-       pos += ETH_ALEN;
-       os_memcpy(pos, mac_resp, ETH_ALEN);
-       pos += ETH_ALEN;
+       if (mac_init && mac_resp) {
+               os_memcpy(pos, mac_init, ETH_ALEN);
+               pos += ETH_ALEN;
+               os_memcpy(pos, mac_resp, ETH_ALEN);
+               pos += ETH_ALEN;
+       } else {
+               *pos++ = ver_init;
+               *pos++ = ver_resp;
+       }
        os_memcpy(pos, Mx, Mx_len);
        pos += Mx_len;
        os_memcpy(pos, Nx, Nx_len);
index 087878a508cbe09830889deadc65681c6a08b180..c00b1ee41240184668478121e783ad5c4921a606 100644 (file)
@@ -118,6 +118,7 @@ dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, const u8 *mac_resp,
                   const char *code, const char *identifier,
                   struct crypto_ec **ret_ec);
 int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp,
+                     u8 ver_init, u8 ver_resp,
                      const u8 *Mx, size_t Mx_len,
                      const u8 *Nx, size_t Nx_len,
                      const char *code,
index 06532b5457bd700a2c7d0bf776aafff9f4a6379d..38349fa3f540eb16c749143ebf04586109ee31b5 100644 (file)
@@ -26,7 +26,8 @@ size_t dpp_pkex_ephemeral_key_override_len = 0;
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
-static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
+static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex,
+                                                  bool v2)
 {
        struct crypto_ec *ec = NULL;
        const struct crypto_ec_point *X;
@@ -36,10 +37,11 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
        size_t attr_len;
        const struct dpp_curve_params *curve = pkex->own_bi->curve;
 
-       wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request");
+       wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request",
+                  v2 ? "" : "Version 1 ");
 
-       /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-       Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code,
+       /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
+       Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code,
                                pkex->identifier, &ec);
        if (!Qi)
                goto fail;
@@ -76,13 +78,27 @@ static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex)
 
        /* Initiator -> Responder: group, [identifier,] M */
        attr_len = 4 + 2;
+#ifdef CONFIG_DPP2
+       if (v2)
+               attr_len += 4 + 1;
+#endif /* CONFIG_DPP2 */
        if (pkex->identifier)
                attr_len += 4 + os_strlen(pkex->identifier);
        attr_len += 4 + 2 * curve->prime_len;
-       msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len);
+       msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+                           DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len);
        if (!msg)
                goto fail;
 
+#ifdef CONFIG_DPP2
+       if (v2) {
+               /* Protocol Version */
+               wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+               wpabuf_put_le16(msg, 1);
+               wpabuf_put_u8(msg, DPP_VERSION);
+       }
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
        if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) {
                wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group");
@@ -154,8 +170,8 @@ static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt)
 
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
                                const u8 *own_mac,
-                               const char *identifier,
-                               const char *code)
+                               const char *identifier, const char *code,
+                               bool v2)
 {
        struct dpp_pkex *pkex;
 
@@ -172,6 +188,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
                return NULL;
        pkex->msg_ctx = msg_ctx;
        pkex->initiator = 1;
+       pkex->v2 = v2;
        pkex->own_bi = bi;
        os_memcpy(pkex->own_mac, own_mac, ETH_ALEN);
        if (identifier) {
@@ -182,7 +199,7 @@ struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
        pkex->code = os_strdup(code);
        if (!pkex->code)
                goto fail;
-       pkex->exchange_req = dpp_pkex_build_exchange_req(pkex);
+       pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2);
        if (!pkex->exchange_req)
                goto fail;
        return pkex;
@@ -201,8 +218,13 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
        size_t attr_len;
        const struct dpp_curve_params *curve = pkex->own_bi->curve;
 
-       /* Initiator -> Responder: DPP Status, [identifier,] N */
+       /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,]
+        * N */
        attr_len = 4 + 1;
+#ifdef CONFIG_DPP2
+       if (pkex->v2)
+               attr_len += 4 + 1;
+#endif /* CONFIG_DPP2 */
        if (pkex->identifier)
                attr_len += 4 + os_strlen(pkex->identifier);
        attr_len += 4 + 2 * curve->prime_len;
@@ -229,6 +251,15 @@ dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex,
 skip_status:
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_DPP2
+       if (pkex->v2) {
+               /* Protocol Version */
+               wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+               wpabuf_put_le16(msg, 1);
+               wpabuf_put_u8(msg, DPP_VERSION);
+       }
+#endif /* CONFIG_DPP2 */
+
        /* Code Identifier attribute */
        if (pkex->identifier) {
                wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER);
@@ -310,7 +341,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                                           const u8 *peer_mac,
                                           const char *identifier,
                                           const char *code,
-                                          const u8 *buf, size_t len)
+                                          const u8 *buf, size_t len, bool v2)
 {
        const u8 *attr_group, *attr_id, *attr_key;
        u16 attr_group_len, attr_id_len, attr_key_len;
@@ -325,6 +356,7 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        u8 Kx[DPP_MAX_SHARED_SECRET_LEN];
        size_t Kx_len;
        int res;
+       u8 peer_version = 0;
 
        if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) {
                wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL
@@ -332,6 +364,24 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                return NULL;
        }
 
+#ifdef CONFIG_DPP2
+       if (v2) {
+               const u8 *version;
+               u16 version_len;
+
+               version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+                                      &version_len);
+               if (!version || version_len < 1 || version[0] == 0) {
+                       wpa_msg(msg_ctx, MSG_INFO,
+                               "Missing or invalid Protocol Version attribute");
+                       return NULL;
+               }
+               peer_version = version[0];
+               wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+                          peer_version);
+       }
+#endif /* CONFIG_DPP2 */
+
 #ifdef CONFIG_TESTING_OPTIONS
        if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) {
                wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR,
@@ -366,6 +416,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                pkex = os_zalloc(sizeof(*pkex));
                if (!pkex)
                        goto fail;
+               pkex->v2 = v2;
+               pkex->peer_version = peer_version;
                pkex->own_bi = bi;
                pkex->failed = 1;
                pkex->exchange_resp = dpp_pkex_build_exchange_resp(
@@ -385,8 +437,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
                return NULL;
        }
 
-       /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */
-       Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, &ec);
+       /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */
+       Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier,
+                               &ec);
        if (!Qi)
                goto fail;
 
@@ -411,6 +464,8 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        pkex = os_zalloc(sizeof(*pkex));
        if (!pkex)
                goto fail;
+       pkex->v2 = v2;
+       pkex->peer_version = peer_version;
        pkex->t = bi->pkex_t;
        pkex->msg_ctx = msg_ctx;
        pkex->own_bi = bi;
@@ -438,8 +493,9 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        if (!pkex->x)
                goto fail;
 
-       /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */
-       Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, NULL);
+       /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
+       Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier,
+                               NULL);
        if (!Qr)
                goto fail;
 
@@ -487,9 +543,10 @@ struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
                        Kx, Kx_len);
 
-       /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
-        */
-       res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac,
+       /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
+       res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac,
+                               pkex->v2 ? NULL : pkex->own_mac,
+                               pkex->peer_version, DPP_VERSION,
                                pkex->Mx, curve->prime_len,
                                pkex->Nx, curve->prime_len, pkex->code,
                                Kx, Kx_len, pkex->z, curve->hash_len);
@@ -645,6 +702,7 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN];
        const u8 *addr[4];
        size_t len[4];
+       size_t num_elem;
        u8 u[DPP_MAX_HASH_LEN];
        int res;
 
@@ -666,6 +724,24 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        }
 #endif /* CONFIG_TESTING_OPTIONS */
 
+#ifdef CONFIG_DPP2
+       if (pkex->v2) {
+               const u8 *version;
+               u16 version_len;
+
+               version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION,
+                                      &version_len);
+               if (!version || version_len < 1 || version[0] == 0) {
+               dpp_pkex_fail(pkex,
+                             "Missing or invalid Protocol Version attribute");
+                       return NULL;
+               }
+               pkex->peer_version = version[0];
+               wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u",
+                          pkex->peer_version);
+       }
+#endif /* CONFIG_DPP2 */
+
        os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN);
 
        attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS,
@@ -710,9 +786,9 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
                return NULL;
        }
 
-       /* Qr = H(MAC-Responder | [identifier |] code) * Pr */
-       Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code,
-                               pkex->identifier, &ec);
+       /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */
+       Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac,
+                               pkex->code, pkex->identifier, &ec);
        if (!Qr)
                goto fail;
 
@@ -751,21 +827,29 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
                        Jx, Jx_len);
 
-       /* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x) */
+       /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */
        A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
        Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
        X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
        if (!A_pub || !Y_pub || !X_pub)
                goto fail;
-       addr[0] = pkex->own_mac;
-       len[0] = ETH_ALEN;
-       addr[1] = wpabuf_head(A_pub);
-       len[1] = wpabuf_len(A_pub) / 2;
-       addr[2] = wpabuf_head(Y_pub);
-       len[2] = wpabuf_len(Y_pub) / 2;
-       addr[3] = wpabuf_head(X_pub);
-       len[3] = wpabuf_len(X_pub) / 2;
-       if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+       num_elem = 0;
+       if (!pkex->v2) {
+               addr[num_elem] = pkex->own_mac;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
+       addr[num_elem] = wpabuf_head(A_pub);
+       len[num_elem] = wpabuf_len(A_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(Y_pub);
+       len[num_elem] = wpabuf_len(Y_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(X_pub);
+       len[num_elem] = wpabuf_len(X_pub) / 2;
+       num_elem++;
+       if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
+           < 0)
                goto fail;
        wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len);
 
@@ -776,9 +860,10 @@ struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)",
                        Kx, Kx_len);
 
-       /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x)
-        */
-       res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac,
+       /* z = HKDF(<>, info | M.x | N.x | code, K.x) */
+       res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac,
+                               pkex->v2 ? NULL : pkex->peer_mac,
+                               DPP_VERSION, pkex->peer_version,
                                pkex->Mx, curve->prime_len,
                                attr_key /* N.x */, attr_key_len / 2,
                                pkex->code, Kx, Kx_len,
@@ -933,6 +1018,7 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
        u16 wrapped_data_len, b_key_len, peer_u_len = 0;
        const u8 *addr[4];
        size_t len[4];
+       size_t num_elem;
        u8 octet;
        u8 *unwrapped = NULL;
        size_t unwrapped_len = 0;
@@ -1015,21 +1101,29 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)",
                        Jx, Jx_len);
 
-       /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */
+       /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */
        A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
        Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
        X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
        if (!A_pub || !Y_pub || !X_pub)
                goto fail;
-       addr[0] = pkex->peer_mac;
-       len[0] = ETH_ALEN;
-       addr[1] = wpabuf_head(A_pub);
-       len[1] = wpabuf_len(A_pub) / 2;
-       addr[2] = wpabuf_head(Y_pub);
-       len[2] = wpabuf_len(Y_pub) / 2;
-       addr[3] = wpabuf_head(X_pub);
-       len[3] = wpabuf_len(X_pub) / 2;
-       if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0)
+       num_elem = 0;
+       if (!pkex->v2) {
+               addr[num_elem] = pkex->peer_mac;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
+       addr[num_elem] = wpabuf_head(A_pub);
+       len[num_elem] = wpabuf_len(A_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(Y_pub);
+       len[num_elem] = wpabuf_len(Y_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(X_pub);
+       len[num_elem] = wpabuf_len(X_pub) / 2;
+       num_elem++;
+       if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u)
+           < 0)
                goto fail;
 
        peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG,
@@ -1052,19 +1146,27 @@ struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
                        Lx, Lx_len);
 
-       /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */
+       /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */
        B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0);
        if (!B_pub)
                goto fail;
-       addr[0] = pkex->own_mac;
-       len[0] = ETH_ALEN;
-       addr[1] = wpabuf_head(B_pub);
-       len[1] = wpabuf_len(B_pub) / 2;
-       addr[2] = wpabuf_head(X_pub);
-       len[2] = wpabuf_len(X_pub) / 2;
-       addr[3] = wpabuf_head(Y_pub);
-       len[3] = wpabuf_len(Y_pub) / 2;
-       if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+       num_elem = 0;
+       if (!pkex->v2) {
+               addr[num_elem] = pkex->own_mac;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
+       addr[num_elem] = wpabuf_head(B_pub);
+       len[num_elem] = wpabuf_len(B_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(X_pub);
+       len[num_elem] = wpabuf_len(X_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(Y_pub);
+       len[num_elem] = wpabuf_len(Y_pub) / 2;
+       num_elem++;
+       if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
+           < 0)
                goto fail;
        wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len);
 
@@ -1094,6 +1196,7 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
        u16 wrapped_data_len, b_key_len, peer_v_len = 0;
        const u8 *addr[4];
        size_t len[4];
+       size_t num_elem;
        u8 octet;
        u8 *unwrapped = NULL;
        size_t unwrapped_len = 0;
@@ -1177,21 +1280,29 @@ int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
        wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)",
                        Lx, Lx_len);
 
-       /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */
+       /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */
        B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0);
        X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0);
        Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0);
        if (!B_pub || !X_pub || !Y_pub)
                goto fail;
-       addr[0] = pkex->peer_mac;
-       len[0] = ETH_ALEN;
-       addr[1] = wpabuf_head(B_pub);
-       len[1] = wpabuf_len(B_pub) / 2;
-       addr[2] = wpabuf_head(X_pub);
-       len[2] = wpabuf_len(X_pub) / 2;
-       addr[3] = wpabuf_head(Y_pub);
-       len[3] = wpabuf_len(Y_pub) / 2;
-       if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0)
+       num_elem = 0;
+       if (!pkex->v2) {
+               addr[num_elem] = pkex->peer_mac;
+               len[num_elem] = ETH_ALEN;
+               num_elem++;
+       }
+       addr[num_elem] = wpabuf_head(B_pub);
+       len[num_elem] = wpabuf_len(B_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(X_pub);
+       len[num_elem] = wpabuf_len(X_pub) / 2;
+       num_elem++;
+       addr[num_elem] = wpabuf_head(Y_pub);
+       len[num_elem] = wpabuf_len(Y_pub) / 2;
+       num_elem++;
+       if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v)
+           < 0)
                goto fail;
 
        peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG,
index 46f9692d8abec1a907cbec81c7ed21b8337e230c..4378546d04aa54daf285d667d3d976ea04f737c5 100644 (file)
@@ -2578,7 +2578,9 @@ static void wpas_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx)
        wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)",
                   pkex->exch_req_tries);
        wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
-               MAC2STR(broadcast), pkex->freq, DPP_PA_PKEX_EXCHANGE_REQ);
+               MAC2STR(broadcast), pkex->freq,
+               pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+               DPP_PA_PKEX_V1_EXCHANGE_REQ);
        offchannel_send_action(wpa_s, pkex->freq, broadcast,
                               wpa_s->own_addr, broadcast,
                               wpabuf_head(pkex->exchange_req),
@@ -2637,7 +2639,8 @@ wpas_dpp_tx_pkex_status(struct wpa_supplicant *wpa_s,
 
 static void
 wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
-                             const u8 *buf, size_t len, unsigned int freq)
+                             const u8 *buf, size_t len, unsigned int freq,
+                             bool v2)
 {
        struct wpabuf *msg;
        unsigned int wait_time;
@@ -2665,7 +2668,7 @@ wpas_dpp_rx_pkex_exchange_req(struct wpa_supplicant *wpa_s, const u8 *src,
                                                   wpa_s->own_addr, src,
                                                   wpa_s->dpp_pkex_identifier,
                                                   wpa_s->dpp_pkex_code,
-                                                  buf, len);
+                                                  buf, len, v2);
        if (!wpa_s->dpp_pkex) {
                wpa_printf(MSG_DEBUG,
                           "DPP: Failed to process the request - ignore it");
@@ -2888,8 +2891,17 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
        case DPP_PA_PEER_DISCOVERY_RESP:
                wpas_dpp_rx_peer_disc_resp(wpa_s, src, buf, len);
                break;
+#ifdef CONFIG_DPP3
        case DPP_PA_PKEX_EXCHANGE_REQ:
-               wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq);
+               /* This is for PKEXv2, but for now, process only with
+                * CONFIG_DPP3 to avoid issues with a capability that has not
+                * been tested with other implementations. */
+               wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq, true);
+               break;
+#endif /* CONFIG_DPP3 */
+       case DPP_PA_PKEX_V1_EXCHANGE_REQ:
+               wpas_dpp_rx_pkex_exchange_req(wpa_s, src, buf, len, freq,
+                                             false);
                break;
        case DPP_PA_PKEX_EXCHANGE_RESP:
                wpas_dpp_rx_pkex_exchange_resp(wpa_s, src, buf, len, freq);
@@ -3301,15 +3313,16 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
        if (!wpa_s->dpp_pkex_code)
                return -1;
 
-       if (os_strstr(cmd, " init=1")) {
+       if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) {
                struct dpp_pkex *pkex;
                struct wpabuf *msg;
+               bool v2 = os_strstr(cmd, " init=2") != NULL;
 
                wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX");
                dpp_pkex_free(wpa_s->dpp_pkex);
                wpa_s->dpp_pkex = dpp_pkex_init(wpa_s, own_bi, wpa_s->own_addr,
                                                wpa_s->dpp_pkex_identifier,
-                                               wpa_s->dpp_pkex_code);
+                                               wpa_s->dpp_pkex_code, v2);
                pkex = wpa_s->dpp_pkex;
                if (!pkex)
                        return -1;
@@ -3322,7 +3335,8 @@ int wpas_dpp_pkex_add(struct wpa_supplicant *wpa_s, const char *cmd)
                wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR
                        " freq=%u type=%d",
                        MAC2STR(broadcast), pkex->freq,
-                       DPP_PA_PKEX_EXCHANGE_REQ);
+                       v2 ? DPP_PA_PKEX_EXCHANGE_REQ :
+                       DPP_PA_PKEX_V1_EXCHANGE_REQ);
                offchannel_send_action(wpa_s, pkex->freq, broadcast,
                                       wpa_s->own_addr, broadcast,
                                       wpabuf_head(msg), wpabuf_len(msg),