1c1d255d3SCy Schubert /* 2c1d255d3SCy Schubert * DPP PKEX functionality 3c1d255d3SCy Schubert * Copyright (c) 2017, Qualcomm Atheros, Inc. 4c1d255d3SCy Schubert * Copyright (c) 2018-2020, The Linux Foundation 5c1d255d3SCy Schubert * 6c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license. 7c1d255d3SCy Schubert * See README for more details. 8c1d255d3SCy Schubert */ 9c1d255d3SCy Schubert 10c1d255d3SCy Schubert #include "utils/includes.h" 11c1d255d3SCy Schubert 12c1d255d3SCy Schubert #include "utils/common.h" 13c1d255d3SCy Schubert #include "common/wpa_ctrl.h" 14c1d255d3SCy Schubert #include "crypto/aes.h" 15c1d255d3SCy Schubert #include "crypto/aes_siv.h" 16c1d255d3SCy Schubert #include "crypto/crypto.h" 17c1d255d3SCy Schubert #include "dpp.h" 18c1d255d3SCy Schubert #include "dpp_i.h" 19c1d255d3SCy Schubert 20c1d255d3SCy Schubert 21c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 22c1d255d3SCy Schubert u8 dpp_pkex_own_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 23c1d255d3SCy Schubert u8 dpp_pkex_peer_mac_override[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 24c1d255d3SCy Schubert u8 dpp_pkex_ephemeral_key_override[600]; 25c1d255d3SCy Schubert size_t dpp_pkex_ephemeral_key_override_len = 0; 26c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 27c1d255d3SCy Schubert 28c1d255d3SCy Schubert 29*32a95656SCy Schubert static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex, 30*32a95656SCy Schubert bool v2) 31c1d255d3SCy Schubert { 324b72b91aSCy Schubert struct crypto_ec *ec = NULL; 334b72b91aSCy Schubert const struct crypto_ec_point *X; 344b72b91aSCy Schubert struct crypto_ec_point *Qi = NULL, *M = NULL; 354b72b91aSCy Schubert u8 *Mx, *My; 36c1d255d3SCy Schubert struct wpabuf *msg = NULL; 37c1d255d3SCy Schubert size_t attr_len; 38c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 39c1d255d3SCy Schubert 40*32a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request", 41*32a95656SCy Schubert v2 ? "" : "Version 1 "); 42c1d255d3SCy Schubert 43*32a95656SCy Schubert /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ 44*32a95656SCy Schubert Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code, 454b72b91aSCy Schubert pkex->identifier, &ec); 46c1d255d3SCy Schubert if (!Qi) 47c1d255d3SCy Schubert goto fail; 48c1d255d3SCy Schubert 49c1d255d3SCy Schubert /* Generate a random ephemeral keypair x/X */ 50c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 51c1d255d3SCy Schubert if (dpp_pkex_ephemeral_key_override_len) { 52c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve; 53c1d255d3SCy Schubert 54c1d255d3SCy Schubert wpa_printf(MSG_INFO, 55c1d255d3SCy Schubert "DPP: TESTING - override ephemeral key x/X"); 56c1d255d3SCy Schubert pkex->x = dpp_set_keypair(&tmp_curve, 57c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override, 58c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override_len); 59c1d255d3SCy Schubert } else { 60c1d255d3SCy Schubert pkex->x = dpp_gen_keypair(curve); 61c1d255d3SCy Schubert } 62c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */ 63c1d255d3SCy Schubert pkex->x = dpp_gen_keypair(curve); 64c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 65c1d255d3SCy Schubert if (!pkex->x) 66c1d255d3SCy Schubert goto fail; 67c1d255d3SCy Schubert 68c1d255d3SCy Schubert /* M = X + Qi */ 694b72b91aSCy Schubert X = crypto_ec_key_get_public_key(pkex->x); 704b72b91aSCy Schubert M = crypto_ec_point_init(ec); 714b72b91aSCy Schubert if (!X || !M) 72c1d255d3SCy Schubert goto fail; 734b72b91aSCy Schubert crypto_ec_point_debug_print(ec, X, "DPP: X"); 744b72b91aSCy Schubert 754b72b91aSCy Schubert if (crypto_ec_point_add(ec, X, Qi, M)) 76c1d255d3SCy Schubert goto fail; 774b72b91aSCy Schubert crypto_ec_point_debug_print(ec, M, "DPP: M"); 78c1d255d3SCy Schubert 79c1d255d3SCy Schubert /* Initiator -> Responder: group, [identifier,] M */ 80c1d255d3SCy Schubert attr_len = 4 + 2; 81*32a95656SCy Schubert #ifdef CONFIG_DPP2 82*32a95656SCy Schubert if (v2) 83*32a95656SCy Schubert attr_len += 4 + 1; 84*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 85c1d255d3SCy Schubert if (pkex->identifier) 86c1d255d3SCy Schubert attr_len += 4 + os_strlen(pkex->identifier); 87c1d255d3SCy Schubert attr_len += 4 + 2 * curve->prime_len; 88*32a95656SCy Schubert msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ : 89*32a95656SCy Schubert DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len); 90c1d255d3SCy Schubert if (!msg) 91c1d255d3SCy Schubert goto fail; 92c1d255d3SCy Schubert 93*32a95656SCy Schubert #ifdef CONFIG_DPP2 94*32a95656SCy Schubert if (v2) { 95*32a95656SCy Schubert /* Protocol Version */ 96*32a95656SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 97*32a95656SCy Schubert wpabuf_put_le16(msg, 1); 98*32a95656SCy Schubert wpabuf_put_u8(msg, DPP_VERSION); 99*32a95656SCy Schubert } 100*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 101*32a95656SCy Schubert 102c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 103c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) { 104c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group"); 105c1d255d3SCy Schubert goto skip_finite_cyclic_group; 106c1d255d3SCy Schubert } 107c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 108c1d255d3SCy Schubert 109c1d255d3SCy Schubert /* Finite Cyclic Group attribute */ 110c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 111c1d255d3SCy Schubert wpabuf_put_le16(msg, 2); 112c1d255d3SCy Schubert wpabuf_put_le16(msg, curve->ike_group); 113c1d255d3SCy Schubert 114c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 115c1d255d3SCy Schubert skip_finite_cyclic_group: 116c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 117c1d255d3SCy Schubert 118c1d255d3SCy Schubert /* Code Identifier attribute */ 119c1d255d3SCy Schubert if (pkex->identifier) { 120c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 121c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 122c1d255d3SCy Schubert wpabuf_put_str(msg, pkex->identifier); 123c1d255d3SCy Schubert } 124c1d255d3SCy Schubert 125c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 126c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 127c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 128c1d255d3SCy Schubert goto out; 129c1d255d3SCy Schubert } 130c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 131c1d255d3SCy Schubert 132c1d255d3SCy Schubert /* M in Encrypted Key attribute */ 133c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 134c1d255d3SCy Schubert wpabuf_put_le16(msg, 2 * curve->prime_len); 135c1d255d3SCy Schubert 136c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 137c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 138c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 139c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(msg, curve) < 0) 140c1d255d3SCy Schubert goto fail; 141c1d255d3SCy Schubert goto out; 142c1d255d3SCy Schubert } 143c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 144c1d255d3SCy Schubert 1454b72b91aSCy Schubert Mx = wpabuf_put(msg, curve->prime_len); 1464b72b91aSCy Schubert My = wpabuf_put(msg, curve->prime_len); 1474b72b91aSCy Schubert if (crypto_ec_point_to_bin(ec, M, Mx, My)) 148c1d255d3SCy Schubert goto fail; 149c1d255d3SCy Schubert 1504b72b91aSCy Schubert os_memcpy(pkex->Mx, Mx, curve->prime_len); 1514b72b91aSCy Schubert 152c1d255d3SCy Schubert out: 1534b72b91aSCy Schubert crypto_ec_point_deinit(M, 1); 1544b72b91aSCy Schubert crypto_ec_point_deinit(Qi, 1); 1554b72b91aSCy Schubert crypto_ec_deinit(ec); 156c1d255d3SCy Schubert return msg; 157c1d255d3SCy Schubert fail: 158c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request"); 159c1d255d3SCy Schubert wpabuf_free(msg); 160c1d255d3SCy Schubert msg = NULL; 161c1d255d3SCy Schubert goto out; 162c1d255d3SCy Schubert } 163c1d255d3SCy Schubert 164c1d255d3SCy Schubert 165c1d255d3SCy Schubert static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt) 166c1d255d3SCy Schubert { 167c1d255d3SCy Schubert wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); 168c1d255d3SCy Schubert } 169c1d255d3SCy Schubert 170c1d255d3SCy Schubert 171c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, 172c1d255d3SCy Schubert const u8 *own_mac, 173*32a95656SCy Schubert const char *identifier, const char *code, 174*32a95656SCy Schubert bool v2) 175c1d255d3SCy Schubert { 176c1d255d3SCy Schubert struct dpp_pkex *pkex; 177c1d255d3SCy Schubert 178c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 179c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 180c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 181c1d255d3SCy Schubert MAC2STR(dpp_pkex_own_mac_override)); 182c1d255d3SCy Schubert own_mac = dpp_pkex_own_mac_override; 183c1d255d3SCy Schubert } 184c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 185c1d255d3SCy Schubert 186c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 187c1d255d3SCy Schubert if (!pkex) 188c1d255d3SCy Schubert return NULL; 189c1d255d3SCy Schubert pkex->msg_ctx = msg_ctx; 190c1d255d3SCy Schubert pkex->initiator = 1; 191*32a95656SCy Schubert pkex->v2 = v2; 192c1d255d3SCy Schubert pkex->own_bi = bi; 193c1d255d3SCy Schubert os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 194c1d255d3SCy Schubert if (identifier) { 195c1d255d3SCy Schubert pkex->identifier = os_strdup(identifier); 196c1d255d3SCy Schubert if (!pkex->identifier) 197c1d255d3SCy Schubert goto fail; 198c1d255d3SCy Schubert } 199c1d255d3SCy Schubert pkex->code = os_strdup(code); 200c1d255d3SCy Schubert if (!pkex->code) 201c1d255d3SCy Schubert goto fail; 202*32a95656SCy Schubert pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2); 203c1d255d3SCy Schubert if (!pkex->exchange_req) 204c1d255d3SCy Schubert goto fail; 205c1d255d3SCy Schubert return pkex; 206c1d255d3SCy Schubert fail: 207c1d255d3SCy Schubert dpp_pkex_free(pkex); 208c1d255d3SCy Schubert return NULL; 209c1d255d3SCy Schubert } 210c1d255d3SCy Schubert 211c1d255d3SCy Schubert 212c1d255d3SCy Schubert static struct wpabuf * 213c1d255d3SCy Schubert dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex, 214c1d255d3SCy Schubert enum dpp_status_error status, 2154b72b91aSCy Schubert const u8 *Nx, const u8 *Ny) 216c1d255d3SCy Schubert { 217c1d255d3SCy Schubert struct wpabuf *msg = NULL; 218c1d255d3SCy Schubert size_t attr_len; 219c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 220c1d255d3SCy Schubert 221*32a95656SCy Schubert /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,] 222*32a95656SCy Schubert * N */ 223c1d255d3SCy Schubert attr_len = 4 + 1; 224*32a95656SCy Schubert #ifdef CONFIG_DPP2 225*32a95656SCy Schubert if (pkex->v2) 226*32a95656SCy Schubert attr_len += 4 + 1; 227*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 228c1d255d3SCy Schubert if (pkex->identifier) 229c1d255d3SCy Schubert attr_len += 4 + os_strlen(pkex->identifier); 230c1d255d3SCy Schubert attr_len += 4 + 2 * curve->prime_len; 231c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len); 232c1d255d3SCy Schubert if (!msg) 233c1d255d3SCy Schubert goto fail; 234c1d255d3SCy Schubert 235c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 236c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) { 237c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 238c1d255d3SCy Schubert goto skip_status; 239c1d255d3SCy Schubert } 240c1d255d3SCy Schubert 241c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) { 242c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 243c1d255d3SCy Schubert status = 255; 244c1d255d3SCy Schubert } 245c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 246c1d255d3SCy Schubert 247c1d255d3SCy Schubert /* DPP Status */ 248c1d255d3SCy Schubert dpp_build_attr_status(msg, status); 249c1d255d3SCy Schubert 250c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 251c1d255d3SCy Schubert skip_status: 252c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 253c1d255d3SCy Schubert 254*32a95656SCy Schubert #ifdef CONFIG_DPP2 255*32a95656SCy Schubert if (pkex->v2) { 256*32a95656SCy Schubert /* Protocol Version */ 257*32a95656SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 258*32a95656SCy Schubert wpabuf_put_le16(msg, 1); 259*32a95656SCy Schubert wpabuf_put_u8(msg, DPP_VERSION); 260*32a95656SCy Schubert } 261*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 262*32a95656SCy Schubert 263c1d255d3SCy Schubert /* Code Identifier attribute */ 264c1d255d3SCy Schubert if (pkex->identifier) { 265c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 266c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 267c1d255d3SCy Schubert wpabuf_put_str(msg, pkex->identifier); 268c1d255d3SCy Schubert } 269c1d255d3SCy Schubert 270c1d255d3SCy Schubert if (status != DPP_STATUS_OK) 271c1d255d3SCy Schubert goto skip_encrypted_key; 272c1d255d3SCy Schubert 273c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 274c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 275c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 276c1d255d3SCy Schubert goto skip_encrypted_key; 277c1d255d3SCy Schubert } 278c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 279c1d255d3SCy Schubert 280c1d255d3SCy Schubert /* N in Encrypted Key attribute */ 281c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 282c1d255d3SCy Schubert wpabuf_put_le16(msg, 2 * curve->prime_len); 283c1d255d3SCy Schubert 284c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 285c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 286c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 287c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(msg, curve) < 0) 288c1d255d3SCy Schubert goto fail; 289c1d255d3SCy Schubert goto skip_encrypted_key; 290c1d255d3SCy Schubert } 291c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 292c1d255d3SCy Schubert 2934b72b91aSCy Schubert wpabuf_put_data(msg, Nx, curve->prime_len); 2944b72b91aSCy Schubert wpabuf_put_data(msg, Ny, curve->prime_len); 2954b72b91aSCy Schubert os_memcpy(pkex->Nx, Nx, curve->prime_len); 296c1d255d3SCy Schubert 297c1d255d3SCy Schubert skip_encrypted_key: 298c1d255d3SCy Schubert if (status == DPP_STATUS_BAD_GROUP) { 299c1d255d3SCy Schubert /* Finite Cyclic Group attribute */ 300c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 301c1d255d3SCy Schubert wpabuf_put_le16(msg, 2); 302c1d255d3SCy Schubert wpabuf_put_le16(msg, curve->ike_group); 303c1d255d3SCy Schubert } 304c1d255d3SCy Schubert 305c1d255d3SCy Schubert return msg; 306c1d255d3SCy Schubert fail: 307c1d255d3SCy Schubert wpabuf_free(msg); 308c1d255d3SCy Schubert return NULL; 309c1d255d3SCy Schubert } 310c1d255d3SCy Schubert 311c1d255d3SCy Schubert 312c1d255d3SCy Schubert static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len, 313c1d255d3SCy Schubert const char *identifier) 314c1d255d3SCy Schubert { 315c1d255d3SCy Schubert if (!attr_id && identifier) { 316c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 317c1d255d3SCy Schubert "DPP: No PKEX code identifier received, but expected one"); 318c1d255d3SCy Schubert return 0; 319c1d255d3SCy Schubert } 320c1d255d3SCy Schubert 321c1d255d3SCy Schubert if (attr_id && !identifier) { 322c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 323c1d255d3SCy Schubert "DPP: PKEX code identifier received, but not expecting one"); 324c1d255d3SCy Schubert return 0; 325c1d255d3SCy Schubert } 326c1d255d3SCy Schubert 327c1d255d3SCy Schubert if (attr_id && identifier && 328c1d255d3SCy Schubert (os_strlen(identifier) != attr_id_len || 329c1d255d3SCy Schubert os_memcmp(identifier, attr_id, attr_id_len) != 0)) { 330c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); 331c1d255d3SCy Schubert return 0; 332c1d255d3SCy Schubert } 333c1d255d3SCy Schubert 334c1d255d3SCy Schubert return 1; 335c1d255d3SCy Schubert } 336c1d255d3SCy Schubert 337c1d255d3SCy Schubert 338c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, 339c1d255d3SCy Schubert struct dpp_bootstrap_info *bi, 340c1d255d3SCy Schubert const u8 *own_mac, 341c1d255d3SCy Schubert const u8 *peer_mac, 342c1d255d3SCy Schubert const char *identifier, 343c1d255d3SCy Schubert const char *code, 344*32a95656SCy Schubert const u8 *buf, size_t len, bool v2) 345c1d255d3SCy Schubert { 346c1d255d3SCy Schubert const u8 *attr_group, *attr_id, *attr_key; 347c1d255d3SCy Schubert u16 attr_group_len, attr_id_len, attr_key_len; 348c1d255d3SCy Schubert const struct dpp_curve_params *curve = bi->curve; 349c1d255d3SCy Schubert u16 ike_group; 350c1d255d3SCy Schubert struct dpp_pkex *pkex = NULL; 3514b72b91aSCy Schubert struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, 3524b72b91aSCy Schubert *N = NULL; 3534b72b91aSCy Schubert struct crypto_ec *ec = NULL; 3544b72b91aSCy Schubert const struct crypto_ec_point *Y; 3554b72b91aSCy Schubert u8 *x_coord = NULL, *y_coord = NULL; 356c1d255d3SCy Schubert u8 Kx[DPP_MAX_SHARED_SECRET_LEN]; 357c1d255d3SCy Schubert size_t Kx_len; 358c1d255d3SCy Schubert int res; 359*32a95656SCy Schubert u8 peer_version = 0; 360c1d255d3SCy Schubert 361c1d255d3SCy Schubert if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) { 362c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 363c1d255d3SCy Schubert "PKEX counter t limit reached - ignore message"); 364c1d255d3SCy Schubert return NULL; 365c1d255d3SCy Schubert } 366c1d255d3SCy Schubert 367*32a95656SCy Schubert #ifdef CONFIG_DPP2 368*32a95656SCy Schubert if (v2) { 369*32a95656SCy Schubert const u8 *version; 370*32a95656SCy Schubert u16 version_len; 371*32a95656SCy Schubert 372*32a95656SCy Schubert version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, 373*32a95656SCy Schubert &version_len); 374*32a95656SCy Schubert if (!version || version_len < 1 || version[0] == 0) { 375*32a95656SCy Schubert wpa_msg(msg_ctx, MSG_INFO, 376*32a95656SCy Schubert "Missing or invalid Protocol Version attribute"); 377*32a95656SCy Schubert return NULL; 378*32a95656SCy Schubert } 379*32a95656SCy Schubert peer_version = version[0]; 380*32a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 381*32a95656SCy Schubert peer_version); 382*32a95656SCy Schubert } 383*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 384*32a95656SCy Schubert 385c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 386c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 387c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 388c1d255d3SCy Schubert MAC2STR(dpp_pkex_peer_mac_override)); 389c1d255d3SCy Schubert peer_mac = dpp_pkex_peer_mac_override; 390c1d255d3SCy Schubert } 391c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 392c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 393c1d255d3SCy Schubert MAC2STR(dpp_pkex_own_mac_override)); 394c1d255d3SCy Schubert own_mac = dpp_pkex_own_mac_override; 395c1d255d3SCy Schubert } 396c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 397c1d255d3SCy Schubert 398c1d255d3SCy Schubert attr_id_len = 0; 399c1d255d3SCy Schubert attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, 400c1d255d3SCy Schubert &attr_id_len); 401c1d255d3SCy Schubert if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier)) 402c1d255d3SCy Schubert return NULL; 403c1d255d3SCy Schubert 404c1d255d3SCy Schubert attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, 405c1d255d3SCy Schubert &attr_group_len); 406c1d255d3SCy Schubert if (!attr_group || attr_group_len != 2) { 407c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 408c1d255d3SCy Schubert "Missing or invalid Finite Cyclic Group attribute"); 409c1d255d3SCy Schubert return NULL; 410c1d255d3SCy Schubert } 411c1d255d3SCy Schubert ike_group = WPA_GET_LE16(attr_group); 412c1d255d3SCy Schubert if (ike_group != curve->ike_group) { 413c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 414c1d255d3SCy Schubert "Mismatching PKEX curve: peer=%u own=%u", 415c1d255d3SCy Schubert ike_group, curve->ike_group); 416c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 417c1d255d3SCy Schubert if (!pkex) 418c1d255d3SCy Schubert goto fail; 419*32a95656SCy Schubert pkex->v2 = v2; 420*32a95656SCy Schubert pkex->peer_version = peer_version; 421c1d255d3SCy Schubert pkex->own_bi = bi; 422c1d255d3SCy Schubert pkex->failed = 1; 423c1d255d3SCy Schubert pkex->exchange_resp = dpp_pkex_build_exchange_resp( 424c1d255d3SCy Schubert pkex, DPP_STATUS_BAD_GROUP, NULL, NULL); 425c1d255d3SCy Schubert if (!pkex->exchange_resp) 426c1d255d3SCy Schubert goto fail; 427c1d255d3SCy Schubert return pkex; 428c1d255d3SCy Schubert } 429c1d255d3SCy Schubert 430c1d255d3SCy Schubert /* M in Encrypted Key attribute */ 431c1d255d3SCy Schubert attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY, 432c1d255d3SCy Schubert &attr_key_len); 433c1d255d3SCy Schubert if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 || 434c1d255d3SCy Schubert attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) { 435c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 436c1d255d3SCy Schubert "Missing Encrypted Key attribute"); 437c1d255d3SCy Schubert return NULL; 438c1d255d3SCy Schubert } 439c1d255d3SCy Schubert 440*32a95656SCy Schubert /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ 441*32a95656SCy Schubert Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, identifier, 442*32a95656SCy Schubert &ec); 443c1d255d3SCy Schubert if (!Qi) 444c1d255d3SCy Schubert goto fail; 445c1d255d3SCy Schubert 446c1d255d3SCy Schubert /* X' = M - Qi */ 4474b72b91aSCy Schubert X = crypto_ec_point_init(ec); 4484b72b91aSCy Schubert M = crypto_ec_point_from_bin(ec, attr_key); 4494b72b91aSCy Schubert if (!X || !M || 4504b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, M) || 4514b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, M) || 4524b72b91aSCy Schubert crypto_ec_point_invert(ec, Qi) || 4534b72b91aSCy Schubert crypto_ec_point_add(ec, M, Qi, X) || 4544b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, X) || 4554b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, X)) { 456c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 457c1d255d3SCy Schubert "Invalid Encrypted Key value"); 458c1d255d3SCy Schubert bi->pkex_t++; 459c1d255d3SCy Schubert goto fail; 460c1d255d3SCy Schubert } 4614b72b91aSCy Schubert crypto_ec_point_debug_print(ec, M, "DPP: M"); 4624b72b91aSCy Schubert crypto_ec_point_debug_print(ec, X, "DPP: X'"); 463c1d255d3SCy Schubert 464c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 465c1d255d3SCy Schubert if (!pkex) 466c1d255d3SCy Schubert goto fail; 467*32a95656SCy Schubert pkex->v2 = v2; 468*32a95656SCy Schubert pkex->peer_version = peer_version; 469c1d255d3SCy Schubert pkex->t = bi->pkex_t; 470c1d255d3SCy Schubert pkex->msg_ctx = msg_ctx; 471c1d255d3SCy Schubert pkex->own_bi = bi; 472c1d255d3SCy Schubert os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 473c1d255d3SCy Schubert os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 474c1d255d3SCy Schubert if (identifier) { 475c1d255d3SCy Schubert pkex->identifier = os_strdup(identifier); 476c1d255d3SCy Schubert if (!pkex->identifier) 477c1d255d3SCy Schubert goto fail; 478c1d255d3SCy Schubert } 479c1d255d3SCy Schubert pkex->code = os_strdup(code); 480c1d255d3SCy Schubert if (!pkex->code) 481c1d255d3SCy Schubert goto fail; 482c1d255d3SCy Schubert 483c1d255d3SCy Schubert os_memcpy(pkex->Mx, attr_key, attr_key_len / 2); 484c1d255d3SCy Schubert 4854b72b91aSCy Schubert x_coord = os_malloc(curve->prime_len); 4864b72b91aSCy Schubert y_coord = os_malloc(curve->prime_len); 4874b72b91aSCy Schubert if (!x_coord || !y_coord || 4884b72b91aSCy Schubert crypto_ec_point_to_bin(ec, X, x_coord, y_coord)) 489c1d255d3SCy Schubert goto fail; 4904b72b91aSCy Schubert 4914b72b91aSCy Schubert pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord, 4924b72b91aSCy Schubert y_coord, crypto_ec_prime_len(ec)); 4934b72b91aSCy Schubert if (!pkex->x) 494c1d255d3SCy Schubert goto fail; 495c1d255d3SCy Schubert 496*32a95656SCy Schubert /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ 497*32a95656SCy Schubert Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, identifier, 498*32a95656SCy Schubert NULL); 499c1d255d3SCy Schubert if (!Qr) 500c1d255d3SCy Schubert goto fail; 501c1d255d3SCy Schubert 502c1d255d3SCy Schubert /* Generate a random ephemeral keypair y/Y */ 503c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 504c1d255d3SCy Schubert if (dpp_pkex_ephemeral_key_override_len) { 505c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve; 506c1d255d3SCy Schubert 507c1d255d3SCy Schubert wpa_printf(MSG_INFO, 508c1d255d3SCy Schubert "DPP: TESTING - override ephemeral key y/Y"); 509c1d255d3SCy Schubert pkex->y = dpp_set_keypair(&tmp_curve, 510c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override, 511c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override_len); 512c1d255d3SCy Schubert } else { 513c1d255d3SCy Schubert pkex->y = dpp_gen_keypair(curve); 514c1d255d3SCy Schubert } 515c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */ 516c1d255d3SCy Schubert pkex->y = dpp_gen_keypair(curve); 517c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 518c1d255d3SCy Schubert if (!pkex->y) 519c1d255d3SCy Schubert goto fail; 520c1d255d3SCy Schubert 521c1d255d3SCy Schubert /* N = Y + Qr */ 5224b72b91aSCy Schubert Y = crypto_ec_key_get_public_key(pkex->y); 5234b72b91aSCy Schubert if (!Y) 524c1d255d3SCy Schubert goto fail; 5254b72b91aSCy Schubert crypto_ec_point_debug_print(ec, Y, "DPP: Y"); 5264b72b91aSCy Schubert 5274b72b91aSCy Schubert N = crypto_ec_point_init(ec); 5284b72b91aSCy Schubert if (!N || 5294b72b91aSCy Schubert crypto_ec_point_add(ec, Y, Qr, N) || 5304b72b91aSCy Schubert crypto_ec_point_to_bin(ec, N, x_coord, y_coord)) 531c1d255d3SCy Schubert goto fail; 5324b72b91aSCy Schubert crypto_ec_point_debug_print(ec, N, "DPP: N"); 533c1d255d3SCy Schubert 534c1d255d3SCy Schubert pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK, 5354b72b91aSCy Schubert x_coord, y_coord); 536c1d255d3SCy Schubert if (!pkex->exchange_resp) 537c1d255d3SCy Schubert goto fail; 538c1d255d3SCy Schubert 539c1d255d3SCy Schubert /* K = y * X' */ 540c1d255d3SCy Schubert if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0) 541c1d255d3SCy Schubert goto fail; 542c1d255d3SCy Schubert 543c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 544c1d255d3SCy Schubert Kx, Kx_len); 545c1d255d3SCy Schubert 546*32a95656SCy Schubert /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ 547*32a95656SCy Schubert res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac, 548*32a95656SCy Schubert pkex->v2 ? NULL : pkex->own_mac, 549*32a95656SCy Schubert pkex->peer_version, DPP_VERSION, 550c1d255d3SCy Schubert pkex->Mx, curve->prime_len, 551c1d255d3SCy Schubert pkex->Nx, curve->prime_len, pkex->code, 552c1d255d3SCy Schubert Kx, Kx_len, pkex->z, curve->hash_len); 553c1d255d3SCy Schubert os_memset(Kx, 0, Kx_len); 554c1d255d3SCy Schubert if (res < 0) 555c1d255d3SCy Schubert goto fail; 556c1d255d3SCy Schubert 557c1d255d3SCy Schubert pkex->exchange_done = 1; 558c1d255d3SCy Schubert 559c1d255d3SCy Schubert out: 5604b72b91aSCy Schubert os_free(x_coord); 5614b72b91aSCy Schubert os_free(y_coord); 5624b72b91aSCy Schubert crypto_ec_point_deinit(Qi, 1); 5634b72b91aSCy Schubert crypto_ec_point_deinit(Qr, 1); 5644b72b91aSCy Schubert crypto_ec_point_deinit(M, 1); 5654b72b91aSCy Schubert crypto_ec_point_deinit(N, 1); 5664b72b91aSCy Schubert crypto_ec_point_deinit(X, 1); 5674b72b91aSCy Schubert crypto_ec_deinit(ec); 568c1d255d3SCy Schubert return pkex; 569c1d255d3SCy Schubert fail: 570c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed"); 571c1d255d3SCy Schubert dpp_pkex_free(pkex); 572c1d255d3SCy Schubert pkex = NULL; 573c1d255d3SCy Schubert goto out; 574c1d255d3SCy Schubert } 575c1d255d3SCy Schubert 576c1d255d3SCy Schubert 577c1d255d3SCy Schubert static struct wpabuf * 578c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex, 579c1d255d3SCy Schubert const struct wpabuf *A_pub, const u8 *u) 580c1d255d3SCy Schubert { 581c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 582c1d255d3SCy Schubert struct wpabuf *msg = NULL; 583c1d255d3SCy Schubert size_t clear_len, attr_len; 584c1d255d3SCy Schubert struct wpabuf *clear = NULL; 585c1d255d3SCy Schubert u8 *wrapped; 586c1d255d3SCy Schubert u8 octet; 587c1d255d3SCy Schubert const u8 *addr[2]; 588c1d255d3SCy Schubert size_t len[2]; 589c1d255d3SCy Schubert 590c1d255d3SCy Schubert /* {A, u, [bootstrapping info]}z */ 591c1d255d3SCy Schubert clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 592c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 593c1d255d3SCy Schubert attr_len = 4 + clear_len + AES_BLOCK_SIZE; 594c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 595c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) 596c1d255d3SCy Schubert attr_len += 5; 597c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 598c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len); 599c1d255d3SCy Schubert if (!clear || !msg) 600c1d255d3SCy Schubert goto fail; 601c1d255d3SCy Schubert 602c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 603c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) { 604c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 605c1d255d3SCy Schubert goto skip_bootstrap_key; 606c1d255d3SCy Schubert } 607c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) { 608c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 609c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 610c1d255d3SCy Schubert wpabuf_put_le16(clear, 2 * curve->prime_len); 611c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(clear, curve) < 0) 612c1d255d3SCy Schubert goto fail; 613c1d255d3SCy Schubert goto skip_bootstrap_key; 614c1d255d3SCy Schubert } 615c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 616c1d255d3SCy Schubert 617c1d255d3SCy Schubert /* A in Bootstrap Key attribute */ 618c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 619c1d255d3SCy Schubert wpabuf_put_le16(clear, wpabuf_len(A_pub)); 620c1d255d3SCy Schubert wpabuf_put_buf(clear, A_pub); 621c1d255d3SCy Schubert 622c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 623c1d255d3SCy Schubert skip_bootstrap_key: 624c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) { 625c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag"); 626c1d255d3SCy Schubert goto skip_i_auth_tag; 627c1d255d3SCy Schubert } 628c1d255d3SCy Schubert if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) { 629c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch"); 630c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 631c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 632c1d255d3SCy Schubert wpabuf_put_data(clear, u, curve->hash_len - 1); 633c1d255d3SCy Schubert wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01); 634c1d255d3SCy Schubert goto skip_i_auth_tag; 635c1d255d3SCy Schubert } 636c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 637c1d255d3SCy Schubert 638c1d255d3SCy Schubert /* u in I-Auth tag attribute */ 639c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 640c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 641c1d255d3SCy Schubert wpabuf_put_data(clear, u, curve->hash_len); 642c1d255d3SCy Schubert 643c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 644c1d255d3SCy Schubert skip_i_auth_tag: 645c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) { 646c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 647c1d255d3SCy Schubert goto skip_wrapped_data; 648c1d255d3SCy Schubert } 649c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 650c1d255d3SCy Schubert 651c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 652c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 653c1d255d3SCy Schubert octet = 0; 654c1d255d3SCy Schubert addr[1] = &octet; 655c1d255d3SCy Schubert len[1] = sizeof(octet); 656c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 657c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 658c1d255d3SCy Schubert 659c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 660c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 661c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 662c1d255d3SCy Schubert 663c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 664c1d255d3SCy Schubert if (aes_siv_encrypt(pkex->z, curve->hash_len, 665c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 666c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 667c1d255d3SCy Schubert goto fail; 668c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 669c1d255d3SCy Schubert wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 670c1d255d3SCy Schubert 671c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 672c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) { 673c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 674c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK); 675c1d255d3SCy Schubert } 676c1d255d3SCy Schubert skip_wrapped_data: 677c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 678c1d255d3SCy Schubert 679c1d255d3SCy Schubert out: 680c1d255d3SCy Schubert wpabuf_free(clear); 681c1d255d3SCy Schubert return msg; 682c1d255d3SCy Schubert 683c1d255d3SCy Schubert fail: 684c1d255d3SCy Schubert wpabuf_free(msg); 685c1d255d3SCy Schubert msg = NULL; 686c1d255d3SCy Schubert goto out; 687c1d255d3SCy Schubert } 688c1d255d3SCy Schubert 689c1d255d3SCy Schubert 690c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, 691c1d255d3SCy Schubert const u8 *peer_mac, 692c1d255d3SCy Schubert const u8 *buf, size_t buflen) 693c1d255d3SCy Schubert { 694c1d255d3SCy Schubert const u8 *attr_status, *attr_id, *attr_key, *attr_group; 695c1d255d3SCy Schubert u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len; 6964b72b91aSCy Schubert struct crypto_ec *ec = NULL; 697c1d255d3SCy Schubert struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 698c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 6994b72b91aSCy Schubert struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL; 7004b72b91aSCy Schubert u8 *x_coord = NULL, *y_coord = NULL; 701c1d255d3SCy Schubert size_t Jx_len, Kx_len; 702c1d255d3SCy Schubert u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; 703c1d255d3SCy Schubert const u8 *addr[4]; 704c1d255d3SCy Schubert size_t len[4]; 705*32a95656SCy Schubert size_t num_elem; 706c1d255d3SCy Schubert u8 u[DPP_MAX_HASH_LEN]; 707c1d255d3SCy Schubert int res; 708c1d255d3SCy Schubert 709c1d255d3SCy Schubert if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 710c1d255d3SCy Schubert return NULL; 711c1d255d3SCy Schubert 712c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 713c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) { 714c1d255d3SCy Schubert wpa_printf(MSG_INFO, 715c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX Exchange Response"); 716c1d255d3SCy Schubert pkex->failed = 1; 717c1d255d3SCy Schubert return NULL; 718c1d255d3SCy Schubert } 719c1d255d3SCy Schubert 720c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 721c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 722c1d255d3SCy Schubert MAC2STR(dpp_pkex_peer_mac_override)); 723c1d255d3SCy Schubert peer_mac = dpp_pkex_peer_mac_override; 724c1d255d3SCy Schubert } 725c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 726c1d255d3SCy Schubert 727*32a95656SCy Schubert #ifdef CONFIG_DPP2 728*32a95656SCy Schubert if (pkex->v2) { 729*32a95656SCy Schubert const u8 *version; 730*32a95656SCy Schubert u16 version_len; 731*32a95656SCy Schubert 732*32a95656SCy Schubert version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION, 733*32a95656SCy Schubert &version_len); 734*32a95656SCy Schubert if (!version || version_len < 1 || version[0] == 0) { 735*32a95656SCy Schubert dpp_pkex_fail(pkex, 736*32a95656SCy Schubert "Missing or invalid Protocol Version attribute"); 737*32a95656SCy Schubert return NULL; 738*32a95656SCy Schubert } 739*32a95656SCy Schubert pkex->peer_version = version[0]; 740*32a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 741*32a95656SCy Schubert pkex->peer_version); 742*32a95656SCy Schubert } 743*32a95656SCy Schubert #endif /* CONFIG_DPP2 */ 744*32a95656SCy Schubert 745c1d255d3SCy Schubert os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 746c1d255d3SCy Schubert 747c1d255d3SCy Schubert attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, 748c1d255d3SCy Schubert &attr_status_len); 749c1d255d3SCy Schubert if (!attr_status || attr_status_len != 1) { 750c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No DPP Status attribute"); 751c1d255d3SCy Schubert return NULL; 752c1d255d3SCy Schubert } 753c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]); 754c1d255d3SCy Schubert 755c1d255d3SCy Schubert if (attr_status[0] == DPP_STATUS_BAD_GROUP) { 756c1d255d3SCy Schubert attr_group = dpp_get_attr(buf, buflen, 757c1d255d3SCy Schubert DPP_ATTR_FINITE_CYCLIC_GROUP, 758c1d255d3SCy Schubert &attr_group_len); 759c1d255d3SCy Schubert if (attr_group && attr_group_len == 2) { 760c1d255d3SCy Schubert wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 761c1d255d3SCy Schubert "Peer indicated mismatching PKEX group - proposed %u", 762c1d255d3SCy Schubert WPA_GET_LE16(attr_group)); 763c1d255d3SCy Schubert return NULL; 764c1d255d3SCy Schubert } 765c1d255d3SCy Schubert } 766c1d255d3SCy Schubert 767c1d255d3SCy Schubert if (attr_status[0] != DPP_STATUS_OK) { 768c1d255d3SCy Schubert dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)"); 769c1d255d3SCy Schubert return NULL; 770c1d255d3SCy Schubert } 771c1d255d3SCy Schubert 772c1d255d3SCy Schubert attr_id_len = 0; 773c1d255d3SCy Schubert attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER, 774c1d255d3SCy Schubert &attr_id_len); 775c1d255d3SCy Schubert if (!dpp_pkex_identifier_match(attr_id, attr_id_len, 776c1d255d3SCy Schubert pkex->identifier)) { 777c1d255d3SCy Schubert dpp_pkex_fail(pkex, "PKEX code identifier mismatch"); 778c1d255d3SCy Schubert return NULL; 779c1d255d3SCy Schubert } 780c1d255d3SCy Schubert 781c1d255d3SCy Schubert /* N in Encrypted Key attribute */ 782c1d255d3SCy Schubert attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY, 783c1d255d3SCy Schubert &attr_key_len); 784c1d255d3SCy Schubert if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) { 785c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Missing Encrypted Key attribute"); 786c1d255d3SCy Schubert return NULL; 787c1d255d3SCy Schubert } 788c1d255d3SCy Schubert 789*32a95656SCy Schubert /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ 790*32a95656SCy Schubert Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac, 791*32a95656SCy Schubert pkex->code, pkex->identifier, &ec); 792c1d255d3SCy Schubert if (!Qr) 793c1d255d3SCy Schubert goto fail; 794c1d255d3SCy Schubert 795c1d255d3SCy Schubert /* Y' = N - Qr */ 7964b72b91aSCy Schubert Y = crypto_ec_point_init(ec); 7974b72b91aSCy Schubert N = crypto_ec_point_from_bin(ec, attr_key); 7984b72b91aSCy Schubert if (!Y || !N || 7994b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, N) || 8004b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, N) || 8014b72b91aSCy Schubert crypto_ec_point_invert(ec, Qr) || 8024b72b91aSCy Schubert crypto_ec_point_add(ec, N, Qr, Y) || 8034b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, Y) || 8044b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, Y)) { 805c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid Encrypted Key value"); 806c1d255d3SCy Schubert pkex->t++; 807c1d255d3SCy Schubert goto fail; 808c1d255d3SCy Schubert } 8094b72b91aSCy Schubert crypto_ec_point_debug_print(ec, N, "DPP: N"); 8104b72b91aSCy Schubert crypto_ec_point_debug_print(ec, Y, "DPP: Y'"); 811c1d255d3SCy Schubert 812c1d255d3SCy Schubert pkex->exchange_done = 1; 813c1d255d3SCy Schubert 814c1d255d3SCy Schubert /* ECDH: J = a * Y' */ 8154b72b91aSCy Schubert x_coord = os_malloc(curve->prime_len); 8164b72b91aSCy Schubert y_coord = os_malloc(curve->prime_len); 8174b72b91aSCy Schubert if (!x_coord || !y_coord || 8184b72b91aSCy Schubert crypto_ec_point_to_bin(ec, Y, x_coord, y_coord)) 819c1d255d3SCy Schubert goto fail; 8204b72b91aSCy Schubert pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord, 8214b72b91aSCy Schubert curve->prime_len); 8224b72b91aSCy Schubert if (!pkex->y) 823c1d255d3SCy Schubert goto fail; 824c1d255d3SCy Schubert if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0) 825c1d255d3SCy Schubert goto fail; 826c1d255d3SCy Schubert 827c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 828c1d255d3SCy Schubert Jx, Jx_len); 829c1d255d3SCy Schubert 830*32a95656SCy Schubert /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */ 8314b72b91aSCy Schubert A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); 8324b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 8334b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 834c1d255d3SCy Schubert if (!A_pub || !Y_pub || !X_pub) 835c1d255d3SCy Schubert goto fail; 836*32a95656SCy Schubert num_elem = 0; 837*32a95656SCy Schubert if (!pkex->v2) { 838*32a95656SCy Schubert addr[num_elem] = pkex->own_mac; 839*32a95656SCy Schubert len[num_elem] = ETH_ALEN; 840*32a95656SCy Schubert num_elem++; 841*32a95656SCy Schubert } 842*32a95656SCy Schubert addr[num_elem] = wpabuf_head(A_pub); 843*32a95656SCy Schubert len[num_elem] = wpabuf_len(A_pub) / 2; 844*32a95656SCy Schubert num_elem++; 845*32a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 846*32a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 847*32a95656SCy Schubert num_elem++; 848*32a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 849*32a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 850*32a95656SCy Schubert num_elem++; 851*32a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) 852*32a95656SCy Schubert < 0) 853c1d255d3SCy Schubert goto fail; 854c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len); 855c1d255d3SCy Schubert 856c1d255d3SCy Schubert /* K = x * Y' */ 857c1d255d3SCy Schubert if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0) 858c1d255d3SCy Schubert goto fail; 859c1d255d3SCy Schubert 860c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 861c1d255d3SCy Schubert Kx, Kx_len); 862c1d255d3SCy Schubert 863*32a95656SCy Schubert /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ 864*32a95656SCy Schubert res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac, 865*32a95656SCy Schubert pkex->v2 ? NULL : pkex->peer_mac, 866*32a95656SCy Schubert DPP_VERSION, pkex->peer_version, 867c1d255d3SCy Schubert pkex->Mx, curve->prime_len, 868c1d255d3SCy Schubert attr_key /* N.x */, attr_key_len / 2, 869c1d255d3SCy Schubert pkex->code, Kx, Kx_len, 870c1d255d3SCy Schubert pkex->z, curve->hash_len); 871c1d255d3SCy Schubert os_memset(Kx, 0, Kx_len); 872c1d255d3SCy Schubert if (res < 0) 873c1d255d3SCy Schubert goto fail; 874c1d255d3SCy Schubert 875c1d255d3SCy Schubert msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u); 876c1d255d3SCy Schubert if (!msg) 877c1d255d3SCy Schubert goto fail; 878c1d255d3SCy Schubert 879c1d255d3SCy Schubert out: 880c1d255d3SCy Schubert wpabuf_free(A_pub); 881c1d255d3SCy Schubert wpabuf_free(X_pub); 882c1d255d3SCy Schubert wpabuf_free(Y_pub); 8834b72b91aSCy Schubert os_free(x_coord); 8844b72b91aSCy Schubert os_free(y_coord); 8854b72b91aSCy Schubert crypto_ec_point_deinit(Qr, 1); 8864b72b91aSCy Schubert crypto_ec_point_deinit(Y, 1); 8874b72b91aSCy Schubert crypto_ec_point_deinit(N, 1); 8884b72b91aSCy Schubert crypto_ec_deinit(ec); 889c1d255d3SCy Schubert return msg; 890c1d255d3SCy Schubert fail: 891c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed"); 892c1d255d3SCy Schubert goto out; 893c1d255d3SCy Schubert } 894c1d255d3SCy Schubert 895c1d255d3SCy Schubert 896c1d255d3SCy Schubert static struct wpabuf * 897c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex, 898c1d255d3SCy Schubert const struct wpabuf *B_pub, const u8 *v) 899c1d255d3SCy Schubert { 900c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 901c1d255d3SCy Schubert struct wpabuf *msg = NULL; 902c1d255d3SCy Schubert const u8 *addr[2]; 903c1d255d3SCy Schubert size_t len[2]; 904c1d255d3SCy Schubert u8 octet; 905c1d255d3SCy Schubert u8 *wrapped; 906c1d255d3SCy Schubert struct wpabuf *clear = NULL; 907c1d255d3SCy Schubert size_t clear_len, attr_len; 908c1d255d3SCy Schubert 909c1d255d3SCy Schubert /* {B, v [bootstrapping info]}z */ 910c1d255d3SCy Schubert clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 911c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 912c1d255d3SCy Schubert attr_len = 4 + clear_len + AES_BLOCK_SIZE; 913c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 914c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) 915c1d255d3SCy Schubert attr_len += 5; 916c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 917c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len); 918c1d255d3SCy Schubert if (!clear || !msg) 919c1d255d3SCy Schubert goto fail; 920c1d255d3SCy Schubert 921c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 922c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) { 923c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 924c1d255d3SCy Schubert goto skip_bootstrap_key; 925c1d255d3SCy Schubert } 926c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) { 927c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 928c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 929c1d255d3SCy Schubert wpabuf_put_le16(clear, 2 * curve->prime_len); 930c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(clear, curve) < 0) 931c1d255d3SCy Schubert goto fail; 932c1d255d3SCy Schubert goto skip_bootstrap_key; 933c1d255d3SCy Schubert } 934c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 935c1d255d3SCy Schubert 936c1d255d3SCy Schubert /* B in Bootstrap Key attribute */ 937c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 938c1d255d3SCy Schubert wpabuf_put_le16(clear, wpabuf_len(B_pub)); 939c1d255d3SCy Schubert wpabuf_put_buf(clear, B_pub); 940c1d255d3SCy Schubert 941c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 942c1d255d3SCy Schubert skip_bootstrap_key: 943c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) { 944c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag"); 945c1d255d3SCy Schubert goto skip_r_auth_tag; 946c1d255d3SCy Schubert } 947c1d255d3SCy Schubert if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) { 948c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch"); 949c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 950c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 951c1d255d3SCy Schubert wpabuf_put_data(clear, v, curve->hash_len - 1); 952c1d255d3SCy Schubert wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01); 953c1d255d3SCy Schubert goto skip_r_auth_tag; 954c1d255d3SCy Schubert } 955c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 956c1d255d3SCy Schubert 957c1d255d3SCy Schubert /* v in R-Auth tag attribute */ 958c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 959c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 960c1d255d3SCy Schubert wpabuf_put_data(clear, v, curve->hash_len); 961c1d255d3SCy Schubert 962c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 963c1d255d3SCy Schubert skip_r_auth_tag: 964c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) { 965c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 966c1d255d3SCy Schubert goto skip_wrapped_data; 967c1d255d3SCy Schubert } 968c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 969c1d255d3SCy Schubert 970c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 971c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 972c1d255d3SCy Schubert octet = 1; 973c1d255d3SCy Schubert addr[1] = &octet; 974c1d255d3SCy Schubert len[1] = sizeof(octet); 975c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 976c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 977c1d255d3SCy Schubert 978c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 979c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 980c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 981c1d255d3SCy Schubert 982c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 983c1d255d3SCy Schubert if (aes_siv_encrypt(pkex->z, curve->hash_len, 984c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 985c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 986c1d255d3SCy Schubert goto fail; 987c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 988c1d255d3SCy Schubert wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 989c1d255d3SCy Schubert 990c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 991c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) { 992c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 993c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK); 994c1d255d3SCy Schubert } 995c1d255d3SCy Schubert skip_wrapped_data: 996c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 997c1d255d3SCy Schubert 998c1d255d3SCy Schubert out: 999c1d255d3SCy Schubert wpabuf_free(clear); 1000c1d255d3SCy Schubert return msg; 1001c1d255d3SCy Schubert 1002c1d255d3SCy Schubert fail: 1003c1d255d3SCy Schubert wpabuf_free(msg); 1004c1d255d3SCy Schubert msg = NULL; 1005c1d255d3SCy Schubert goto out; 1006c1d255d3SCy Schubert } 1007c1d255d3SCy Schubert 1008c1d255d3SCy Schubert 1009c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, 1010c1d255d3SCy Schubert const u8 *hdr, 1011c1d255d3SCy Schubert const u8 *buf, size_t buflen) 1012c1d255d3SCy Schubert { 1013c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 1014c1d255d3SCy Schubert size_t Jx_len, Lx_len; 1015c1d255d3SCy Schubert u8 Jx[DPP_MAX_SHARED_SECRET_LEN]; 1016c1d255d3SCy Schubert u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 1017c1d255d3SCy Schubert const u8 *wrapped_data, *b_key, *peer_u; 1018c1d255d3SCy Schubert u16 wrapped_data_len, b_key_len, peer_u_len = 0; 1019c1d255d3SCy Schubert const u8 *addr[4]; 1020c1d255d3SCy Schubert size_t len[4]; 1021*32a95656SCy Schubert size_t num_elem; 1022c1d255d3SCy Schubert u8 octet; 1023c1d255d3SCy Schubert u8 *unwrapped = NULL; 1024c1d255d3SCy Schubert size_t unwrapped_len = 0; 1025c1d255d3SCy Schubert struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 1026c1d255d3SCy Schubert struct wpabuf *B_pub = NULL; 1027c1d255d3SCy Schubert u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; 1028c1d255d3SCy Schubert 1029c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1030c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) { 1031c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1032c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX CR Request"); 1033c1d255d3SCy Schubert pkex->failed = 1; 1034c1d255d3SCy Schubert return NULL; 1035c1d255d3SCy Schubert } 1036c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1037c1d255d3SCy Schubert 1038c1d255d3SCy Schubert if (!pkex->exchange_done || pkex->failed || 1039c1d255d3SCy Schubert pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator) 1040c1d255d3SCy Schubert goto fail; 1041c1d255d3SCy Schubert 1042c1d255d3SCy Schubert wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 1043c1d255d3SCy Schubert &wrapped_data_len); 1044c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 1045c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1046c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 1047c1d255d3SCy Schubert goto fail; 1048c1d255d3SCy Schubert } 1049c1d255d3SCy Schubert 1050c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1051c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 1052c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 1053c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 1054c1d255d3SCy Schubert if (!unwrapped) 1055c1d255d3SCy Schubert goto fail; 1056c1d255d3SCy Schubert 1057c1d255d3SCy Schubert addr[0] = hdr; 1058c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 1059c1d255d3SCy Schubert octet = 0; 1060c1d255d3SCy Schubert addr[1] = &octet; 1061c1d255d3SCy Schubert len[1] = sizeof(octet); 1062c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1063c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1064c1d255d3SCy Schubert 1065c1d255d3SCy Schubert if (aes_siv_decrypt(pkex->z, curve->hash_len, 1066c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 1067c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 1068c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1069c1d255d3SCy Schubert "AES-SIV decryption failed - possible PKEX code mismatch"); 1070c1d255d3SCy Schubert pkex->failed = 1; 1071c1d255d3SCy Schubert pkex->t++; 1072c1d255d3SCy Schubert goto fail; 1073c1d255d3SCy Schubert } 1074c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 1075c1d255d3SCy Schubert unwrapped, unwrapped_len); 1076c1d255d3SCy Schubert 1077c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 1078c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 1079c1d255d3SCy Schubert goto fail; 1080c1d255d3SCy Schubert } 1081c1d255d3SCy Schubert 1082c1d255d3SCy Schubert b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 1083c1d255d3SCy Schubert &b_key_len); 1084c1d255d3SCy Schubert if (!b_key || b_key_len != 2 * curve->prime_len) { 1085c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 1086c1d255d3SCy Schubert goto fail; 1087c1d255d3SCy Schubert } 1088c1d255d3SCy Schubert pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 1089c1d255d3SCy Schubert b_key_len); 1090c1d255d3SCy Schubert if (!pkex->peer_bootstrap_key) { 1091c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 1092c1d255d3SCy Schubert goto fail; 1093c1d255d3SCy Schubert } 1094c1d255d3SCy Schubert dpp_debug_print_key("DPP: Peer bootstrap public key", 1095c1d255d3SCy Schubert pkex->peer_bootstrap_key); 1096c1d255d3SCy Schubert 1097c1d255d3SCy Schubert /* ECDH: J' = y * A' */ 1098c1d255d3SCy Schubert if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0) 1099c1d255d3SCy Schubert goto fail; 1100c1d255d3SCy Schubert 1101c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 1102c1d255d3SCy Schubert Jx, Jx_len); 1103c1d255d3SCy Schubert 1104*32a95656SCy Schubert /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */ 11054b72b91aSCy Schubert A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); 11064b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 11074b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 1108c1d255d3SCy Schubert if (!A_pub || !Y_pub || !X_pub) 1109c1d255d3SCy Schubert goto fail; 1110*32a95656SCy Schubert num_elem = 0; 1111*32a95656SCy Schubert if (!pkex->v2) { 1112*32a95656SCy Schubert addr[num_elem] = pkex->peer_mac; 1113*32a95656SCy Schubert len[num_elem] = ETH_ALEN; 1114*32a95656SCy Schubert num_elem++; 1115*32a95656SCy Schubert } 1116*32a95656SCy Schubert addr[num_elem] = wpabuf_head(A_pub); 1117*32a95656SCy Schubert len[num_elem] = wpabuf_len(A_pub) / 2; 1118*32a95656SCy Schubert num_elem++; 1119*32a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 1120*32a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 1121*32a95656SCy Schubert num_elem++; 1122*32a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 1123*32a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 1124*32a95656SCy Schubert num_elem++; 1125*32a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) 1126*32a95656SCy Schubert < 0) 1127c1d255d3SCy Schubert goto fail; 1128c1d255d3SCy Schubert 1129c1d255d3SCy Schubert peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 1130c1d255d3SCy Schubert &peer_u_len); 1131c1d255d3SCy Schubert if (!peer_u || peer_u_len != curve->hash_len || 1132c1d255d3SCy Schubert os_memcmp(peer_u, u, curve->hash_len) != 0) { 1133c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found"); 1134c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'", 1135c1d255d3SCy Schubert u, curve->hash_len); 1136c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len); 1137c1d255d3SCy Schubert pkex->t++; 1138c1d255d3SCy Schubert goto fail; 1139c1d255d3SCy Schubert } 1140c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received"); 1141c1d255d3SCy Schubert 1142c1d255d3SCy Schubert /* ECDH: L = b * X' */ 1143c1d255d3SCy Schubert if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0) 1144c1d255d3SCy Schubert goto fail; 1145c1d255d3SCy Schubert 1146c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 1147c1d255d3SCy Schubert Lx, Lx_len); 1148c1d255d3SCy Schubert 1149*32a95656SCy Schubert /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */ 11504b72b91aSCy Schubert B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); 1151c1d255d3SCy Schubert if (!B_pub) 1152c1d255d3SCy Schubert goto fail; 1153*32a95656SCy Schubert num_elem = 0; 1154*32a95656SCy Schubert if (!pkex->v2) { 1155*32a95656SCy Schubert addr[num_elem] = pkex->own_mac; 1156*32a95656SCy Schubert len[num_elem] = ETH_ALEN; 1157*32a95656SCy Schubert num_elem++; 1158*32a95656SCy Schubert } 1159*32a95656SCy Schubert addr[num_elem] = wpabuf_head(B_pub); 1160*32a95656SCy Schubert len[num_elem] = wpabuf_len(B_pub) / 2; 1161*32a95656SCy Schubert num_elem++; 1162*32a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 1163*32a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 1164*32a95656SCy Schubert num_elem++; 1165*32a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 1166*32a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 1167*32a95656SCy Schubert num_elem++; 1168*32a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) 1169*32a95656SCy Schubert < 0) 1170c1d255d3SCy Schubert goto fail; 1171c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len); 1172c1d255d3SCy Schubert 1173c1d255d3SCy Schubert msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v); 1174c1d255d3SCy Schubert if (!msg) 1175c1d255d3SCy Schubert goto fail; 1176c1d255d3SCy Schubert 1177c1d255d3SCy Schubert out: 1178c1d255d3SCy Schubert os_free(unwrapped); 1179c1d255d3SCy Schubert wpabuf_free(A_pub); 1180c1d255d3SCy Schubert wpabuf_free(B_pub); 1181c1d255d3SCy Schubert wpabuf_free(X_pub); 1182c1d255d3SCy Schubert wpabuf_free(Y_pub); 1183c1d255d3SCy Schubert return msg; 1184c1d255d3SCy Schubert fail: 1185c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1186c1d255d3SCy Schubert "DPP: PKEX Commit-Reveal Request processing failed"); 1187c1d255d3SCy Schubert goto out; 1188c1d255d3SCy Schubert } 1189c1d255d3SCy Schubert 1190c1d255d3SCy Schubert 1191c1d255d3SCy Schubert int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, 1192c1d255d3SCy Schubert const u8 *buf, size_t buflen) 1193c1d255d3SCy Schubert { 1194c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 1195c1d255d3SCy Schubert const u8 *wrapped_data, *b_key, *peer_v; 1196c1d255d3SCy Schubert u16 wrapped_data_len, b_key_len, peer_v_len = 0; 1197c1d255d3SCy Schubert const u8 *addr[4]; 1198c1d255d3SCy Schubert size_t len[4]; 1199*32a95656SCy Schubert size_t num_elem; 1200c1d255d3SCy Schubert u8 octet; 1201c1d255d3SCy Schubert u8 *unwrapped = NULL; 1202c1d255d3SCy Schubert size_t unwrapped_len = 0; 1203c1d255d3SCy Schubert int ret = -1; 1204c1d255d3SCy Schubert u8 v[DPP_MAX_HASH_LEN]; 1205c1d255d3SCy Schubert size_t Lx_len; 1206c1d255d3SCy Schubert u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 1207c1d255d3SCy Schubert struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 1208c1d255d3SCy Schubert 1209c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1210c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) { 1211c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1212c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX CR Response"); 1213c1d255d3SCy Schubert pkex->failed = 1; 1214c1d255d3SCy Schubert goto fail; 1215c1d255d3SCy Schubert } 1216c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1217c1d255d3SCy Schubert 1218c1d255d3SCy Schubert if (!pkex->exchange_done || pkex->failed || 1219c1d255d3SCy Schubert pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 1220c1d255d3SCy Schubert goto fail; 1221c1d255d3SCy Schubert 1222c1d255d3SCy Schubert wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 1223c1d255d3SCy Schubert &wrapped_data_len); 1224c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 1225c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1226c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 1227c1d255d3SCy Schubert goto fail; 1228c1d255d3SCy Schubert } 1229c1d255d3SCy Schubert 1230c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1231c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 1232c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 1233c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 1234c1d255d3SCy Schubert if (!unwrapped) 1235c1d255d3SCy Schubert goto fail; 1236c1d255d3SCy Schubert 1237c1d255d3SCy Schubert addr[0] = hdr; 1238c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 1239c1d255d3SCy Schubert octet = 1; 1240c1d255d3SCy Schubert addr[1] = &octet; 1241c1d255d3SCy Schubert len[1] = sizeof(octet); 1242c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1243c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1244c1d255d3SCy Schubert 1245c1d255d3SCy Schubert if (aes_siv_decrypt(pkex->z, curve->hash_len, 1246c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 1247c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 1248c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1249c1d255d3SCy Schubert "AES-SIV decryption failed - possible PKEX code mismatch"); 1250c1d255d3SCy Schubert pkex->t++; 1251c1d255d3SCy Schubert goto fail; 1252c1d255d3SCy Schubert } 1253c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 1254c1d255d3SCy Schubert unwrapped, unwrapped_len); 1255c1d255d3SCy Schubert 1256c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 1257c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 1258c1d255d3SCy Schubert goto fail; 1259c1d255d3SCy Schubert } 1260c1d255d3SCy Schubert 1261c1d255d3SCy Schubert b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 1262c1d255d3SCy Schubert &b_key_len); 1263c1d255d3SCy Schubert if (!b_key || b_key_len != 2 * curve->prime_len) { 1264c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 1265c1d255d3SCy Schubert goto fail; 1266c1d255d3SCy Schubert } 1267c1d255d3SCy Schubert pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 1268c1d255d3SCy Schubert b_key_len); 1269c1d255d3SCy Schubert if (!pkex->peer_bootstrap_key) { 1270c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 1271c1d255d3SCy Schubert goto fail; 1272c1d255d3SCy Schubert } 1273c1d255d3SCy Schubert dpp_debug_print_key("DPP: Peer bootstrap public key", 1274c1d255d3SCy Schubert pkex->peer_bootstrap_key); 1275c1d255d3SCy Schubert 1276c1d255d3SCy Schubert /* ECDH: L' = x * B' */ 1277c1d255d3SCy Schubert if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0) 1278c1d255d3SCy Schubert goto fail; 1279c1d255d3SCy Schubert 1280c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 1281c1d255d3SCy Schubert Lx, Lx_len); 1282c1d255d3SCy Schubert 1283*32a95656SCy Schubert /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */ 12844b72b91aSCy Schubert B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); 12854b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 12864b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 1287c1d255d3SCy Schubert if (!B_pub || !X_pub || !Y_pub) 1288c1d255d3SCy Schubert goto fail; 1289*32a95656SCy Schubert num_elem = 0; 1290*32a95656SCy Schubert if (!pkex->v2) { 1291*32a95656SCy Schubert addr[num_elem] = pkex->peer_mac; 1292*32a95656SCy Schubert len[num_elem] = ETH_ALEN; 1293*32a95656SCy Schubert num_elem++; 1294*32a95656SCy Schubert } 1295*32a95656SCy Schubert addr[num_elem] = wpabuf_head(B_pub); 1296*32a95656SCy Schubert len[num_elem] = wpabuf_len(B_pub) / 2; 1297*32a95656SCy Schubert num_elem++; 1298*32a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 1299*32a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 1300*32a95656SCy Schubert num_elem++; 1301*32a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 1302*32a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 1303*32a95656SCy Schubert num_elem++; 1304*32a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) 1305*32a95656SCy Schubert < 0) 1306c1d255d3SCy Schubert goto fail; 1307c1d255d3SCy Schubert 1308c1d255d3SCy Schubert peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG, 1309c1d255d3SCy Schubert &peer_v_len); 1310c1d255d3SCy Schubert if (!peer_v || peer_v_len != curve->hash_len || 1311c1d255d3SCy Schubert os_memcmp(peer_v, v, curve->hash_len) != 0) { 1312c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found"); 1313c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'", 1314c1d255d3SCy Schubert v, curve->hash_len); 1315c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len); 1316c1d255d3SCy Schubert pkex->t++; 1317c1d255d3SCy Schubert goto fail; 1318c1d255d3SCy Schubert } 1319c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received"); 1320c1d255d3SCy Schubert 1321c1d255d3SCy Schubert ret = 0; 1322c1d255d3SCy Schubert out: 1323c1d255d3SCy Schubert wpabuf_free(B_pub); 1324c1d255d3SCy Schubert wpabuf_free(X_pub); 1325c1d255d3SCy Schubert wpabuf_free(Y_pub); 1326c1d255d3SCy Schubert os_free(unwrapped); 1327c1d255d3SCy Schubert return ret; 1328c1d255d3SCy Schubert fail: 1329c1d255d3SCy Schubert goto out; 1330c1d255d3SCy Schubert } 1331c1d255d3SCy Schubert 1332c1d255d3SCy Schubert 1333c1d255d3SCy Schubert struct dpp_bootstrap_info * 1334c1d255d3SCy Schubert dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, 1335c1d255d3SCy Schubert unsigned int freq) 1336c1d255d3SCy Schubert { 1337c1d255d3SCy Schubert struct dpp_bootstrap_info *bi; 1338c1d255d3SCy Schubert 1339c1d255d3SCy Schubert bi = os_zalloc(sizeof(*bi)); 1340c1d255d3SCy Schubert if (!bi) 1341c1d255d3SCy Schubert return NULL; 1342c1d255d3SCy Schubert bi->id = dpp_next_id(dpp); 1343c1d255d3SCy Schubert bi->type = DPP_BOOTSTRAP_PKEX; 1344c1d255d3SCy Schubert os_memcpy(bi->mac_addr, peer, ETH_ALEN); 1345c1d255d3SCy Schubert bi->num_freq = 1; 1346c1d255d3SCy Schubert bi->freq[0] = freq; 1347c1d255d3SCy Schubert bi->curve = pkex->own_bi->curve; 1348c1d255d3SCy Schubert bi->pubkey = pkex->peer_bootstrap_key; 1349c1d255d3SCy Schubert pkex->peer_bootstrap_key = NULL; 1350c1d255d3SCy Schubert if (dpp_bootstrap_key_hash(bi) < 0) { 1351c1d255d3SCy Schubert dpp_bootstrap_info_free(bi); 1352c1d255d3SCy Schubert return NULL; 1353c1d255d3SCy Schubert } 1354c1d255d3SCy Schubert dpp_pkex_free(pkex); 1355c1d255d3SCy Schubert dl_list_add(&dpp->bootstrap, &bi->list); 1356c1d255d3SCy Schubert return bi; 1357c1d255d3SCy Schubert } 1358c1d255d3SCy Schubert 1359c1d255d3SCy Schubert 1360c1d255d3SCy Schubert void dpp_pkex_free(struct dpp_pkex *pkex) 1361c1d255d3SCy Schubert { 1362c1d255d3SCy Schubert if (!pkex) 1363c1d255d3SCy Schubert return; 1364c1d255d3SCy Schubert 1365c1d255d3SCy Schubert os_free(pkex->identifier); 1366c1d255d3SCy Schubert os_free(pkex->code); 13674b72b91aSCy Schubert crypto_ec_key_deinit(pkex->x); 13684b72b91aSCy Schubert crypto_ec_key_deinit(pkex->y); 13694b72b91aSCy Schubert crypto_ec_key_deinit(pkex->peer_bootstrap_key); 1370c1d255d3SCy Schubert wpabuf_free(pkex->exchange_req); 1371c1d255d3SCy Schubert wpabuf_free(pkex->exchange_resp); 1372c1d255d3SCy Schubert os_free(pkex); 1373c1d255d3SCy Schubert } 1374