diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index cb6d2c4b8..13e1fc5bd 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -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)); } diff --git a/src/common/dpp.h b/src/common/dpp.h index e8e8b140b..8d62a0e2a 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -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); diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c index da59730eb..300416fb1 100644 --- a/src/common/dpp_crypto.c +++ b/src/common/dpp_crypto.c @@ -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); diff --git a/src/common/dpp_i.h b/src/common/dpp_i.h index 087878a50..c00b1ee41 100644 --- a/src/common/dpp_i.h +++ b/src/common/dpp_i.h @@ -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, diff --git a/src/common/dpp_pkex.c b/src/common/dpp_pkex.c index 06532b545..38349fa3f 100644 --- a/src/common/dpp_pkex.c +++ b/src/common/dpp_pkex.c @@ -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, diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 46f9692d8..4378546d0 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -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),