From b57273d069f867f2be4191110980334d1ef2d8c6 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 7 Dec 2021 17:04:48 +0200 Subject: [PATCH] DPP2: PKEXv2 core protocol changes 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 --- src/ap/dpp_hostapd.c | 24 +++- src/common/dpp.h | 11 +- src/common/dpp_crypto.c | 55 +++++--- src/common/dpp_i.h | 1 + src/common/dpp_pkex.c | 237 +++++++++++++++++++++++--------- wpa_supplicant/dpp_supplicant.c | 28 +++- 6 files changed, 258 insertions(+), 98 deletions(-) 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),