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 2932a95656SCy Schubert static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex, 3032a95656SCy Schubert bool v2) 31c1d255d3SCy Schubert { 324b72b91aSCy Schubert struct crypto_ec *ec = NULL; 33*a90b9d01SCy Schubert struct crypto_ec_point *Qi = NULL, *M = NULL, *X = NULL; 344b72b91aSCy Schubert u8 *Mx, *My; 35c1d255d3SCy Schubert struct wpabuf *msg = NULL; 36c1d255d3SCy Schubert size_t attr_len; 37c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 38c1d255d3SCy Schubert 3932a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build PKEX %sExchange Request", 4032a95656SCy Schubert v2 ? "" : "Version 1 "); 41c1d255d3SCy Schubert 4232a95656SCy Schubert /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ 4332a95656SCy Schubert Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : pkex->own_mac, pkex->code, 44*a90b9d01SCy Schubert pkex->code_len, pkex->identifier, &ec); 45c1d255d3SCy Schubert if (!Qi) 46c1d255d3SCy Schubert goto fail; 47c1d255d3SCy Schubert 48c1d255d3SCy Schubert /* Generate a random ephemeral keypair x/X */ 49c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 50c1d255d3SCy Schubert if (dpp_pkex_ephemeral_key_override_len) { 51c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve; 52c1d255d3SCy Schubert 53c1d255d3SCy Schubert wpa_printf(MSG_INFO, 54c1d255d3SCy Schubert "DPP: TESTING - override ephemeral key x/X"); 55c1d255d3SCy Schubert pkex->x = dpp_set_keypair(&tmp_curve, 56c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override, 57c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override_len); 58c1d255d3SCy Schubert } else { 59c1d255d3SCy Schubert pkex->x = dpp_gen_keypair(curve); 60c1d255d3SCy Schubert } 61c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */ 62c1d255d3SCy Schubert pkex->x = dpp_gen_keypair(curve); 63c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 64c1d255d3SCy Schubert if (!pkex->x) 65c1d255d3SCy Schubert goto fail; 66c1d255d3SCy Schubert 67c1d255d3SCy Schubert /* M = X + Qi */ 684b72b91aSCy Schubert X = crypto_ec_key_get_public_key(pkex->x); 694b72b91aSCy Schubert M = crypto_ec_point_init(ec); 704b72b91aSCy Schubert if (!X || !M) 71c1d255d3SCy Schubert goto fail; 724b72b91aSCy Schubert crypto_ec_point_debug_print(ec, X, "DPP: X"); 734b72b91aSCy Schubert 744b72b91aSCy Schubert if (crypto_ec_point_add(ec, X, Qi, M)) 75c1d255d3SCy Schubert goto fail; 764b72b91aSCy Schubert crypto_ec_point_debug_print(ec, M, "DPP: M"); 77c1d255d3SCy Schubert 78c1d255d3SCy Schubert /* Initiator -> Responder: group, [identifier,] M */ 79c1d255d3SCy Schubert attr_len = 4 + 2; 8032a95656SCy Schubert #ifdef CONFIG_DPP2 8132a95656SCy Schubert if (v2) 8232a95656SCy Schubert attr_len += 4 + 1; 8332a95656SCy Schubert #endif /* CONFIG_DPP2 */ 84c1d255d3SCy Schubert if (pkex->identifier) 85c1d255d3SCy Schubert attr_len += 4 + os_strlen(pkex->identifier); 86c1d255d3SCy Schubert attr_len += 4 + 2 * curve->prime_len; 8732a95656SCy Schubert msg = dpp_alloc_msg(v2 ? DPP_PA_PKEX_EXCHANGE_REQ : 8832a95656SCy Schubert DPP_PA_PKEX_V1_EXCHANGE_REQ, attr_len); 89c1d255d3SCy Schubert if (!msg) 90c1d255d3SCy Schubert goto fail; 91c1d255d3SCy Schubert 9232a95656SCy Schubert #ifdef CONFIG_DPP2 9332a95656SCy Schubert if (v2) { 9432a95656SCy Schubert /* Protocol Version */ 9532a95656SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 9632a95656SCy Schubert wpabuf_put_le16(msg, 1); 9732a95656SCy Schubert wpabuf_put_u8(msg, DPP_VERSION); 9832a95656SCy Schubert } 9932a95656SCy Schubert #endif /* CONFIG_DPP2 */ 10032a95656SCy Schubert 101c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 102c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ) { 103c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Finite Cyclic Group"); 104c1d255d3SCy Schubert goto skip_finite_cyclic_group; 105c1d255d3SCy Schubert } 106c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 107c1d255d3SCy Schubert 108c1d255d3SCy Schubert /* Finite Cyclic Group attribute */ 109c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 110c1d255d3SCy Schubert wpabuf_put_le16(msg, 2); 111c1d255d3SCy Schubert wpabuf_put_le16(msg, curve->ike_group); 112c1d255d3SCy Schubert 113c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 114c1d255d3SCy Schubert skip_finite_cyclic_group: 115c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 116c1d255d3SCy Schubert 117c1d255d3SCy Schubert /* Code Identifier attribute */ 118c1d255d3SCy Schubert if (pkex->identifier) { 119c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 120c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 121c1d255d3SCy Schubert wpabuf_put_str(msg, pkex->identifier); 122c1d255d3SCy Schubert } 123c1d255d3SCy Schubert 124c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 125c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 126c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 127c1d255d3SCy Schubert goto out; 128c1d255d3SCy Schubert } 129c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 130c1d255d3SCy Schubert 131c1d255d3SCy Schubert /* M in Encrypted Key attribute */ 132c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 133c1d255d3SCy Schubert wpabuf_put_le16(msg, 2 * curve->prime_len); 134c1d255d3SCy Schubert 135c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 136c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ) { 137c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 138c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(msg, curve) < 0) 139c1d255d3SCy Schubert goto fail; 140c1d255d3SCy Schubert goto out; 141c1d255d3SCy Schubert } 142c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 143c1d255d3SCy Schubert 1444b72b91aSCy Schubert Mx = wpabuf_put(msg, curve->prime_len); 1454b72b91aSCy Schubert My = wpabuf_put(msg, curve->prime_len); 1464b72b91aSCy Schubert if (crypto_ec_point_to_bin(ec, M, Mx, My)) 147c1d255d3SCy Schubert goto fail; 148*a90b9d01SCy Schubert wpabuf_free(pkex->enc_key); 149*a90b9d01SCy Schubert pkex->enc_key = wpabuf_alloc_copy(Mx, 2 * curve->prime_len); 150c1d255d3SCy Schubert 1514b72b91aSCy Schubert os_memcpy(pkex->Mx, Mx, curve->prime_len); 1524b72b91aSCy Schubert 153c1d255d3SCy Schubert out: 154*a90b9d01SCy Schubert crypto_ec_point_deinit(X, 1); 1554b72b91aSCy Schubert crypto_ec_point_deinit(M, 1); 1564b72b91aSCy Schubert crypto_ec_point_deinit(Qi, 1); 1574b72b91aSCy Schubert crypto_ec_deinit(ec); 158c1d255d3SCy Schubert return msg; 159c1d255d3SCy Schubert fail: 160c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request"); 161c1d255d3SCy Schubert wpabuf_free(msg); 162c1d255d3SCy Schubert msg = NULL; 163c1d255d3SCy Schubert goto out; 164c1d255d3SCy Schubert } 165c1d255d3SCy Schubert 166c1d255d3SCy Schubert 167c1d255d3SCy Schubert static void dpp_pkex_fail(struct dpp_pkex *pkex, const char *txt) 168c1d255d3SCy Schubert { 169c1d255d3SCy Schubert wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL "%s", txt); 170c1d255d3SCy Schubert } 171c1d255d3SCy Schubert 172c1d255d3SCy Schubert 173c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, 174c1d255d3SCy Schubert const u8 *own_mac, 17532a95656SCy Schubert const char *identifier, const char *code, 176*a90b9d01SCy Schubert size_t code_len, bool v2) 177c1d255d3SCy Schubert { 178c1d255d3SCy Schubert struct dpp_pkex *pkex; 179c1d255d3SCy Schubert 180c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 181c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 182c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 183c1d255d3SCy Schubert MAC2STR(dpp_pkex_own_mac_override)); 184c1d255d3SCy Schubert own_mac = dpp_pkex_own_mac_override; 185c1d255d3SCy Schubert } 186c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 187c1d255d3SCy Schubert 188c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 189c1d255d3SCy Schubert if (!pkex) 190c1d255d3SCy Schubert return NULL; 191c1d255d3SCy Schubert pkex->msg_ctx = msg_ctx; 192c1d255d3SCy Schubert pkex->initiator = 1; 19332a95656SCy Schubert pkex->v2 = v2; 194c1d255d3SCy Schubert pkex->own_bi = bi; 195c1d255d3SCy Schubert os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 196c1d255d3SCy Schubert if (identifier) { 197c1d255d3SCy Schubert pkex->identifier = os_strdup(identifier); 198c1d255d3SCy Schubert if (!pkex->identifier) 199c1d255d3SCy Schubert goto fail; 200c1d255d3SCy Schubert } 201*a90b9d01SCy Schubert pkex->code = os_memdup(code, code_len); 202c1d255d3SCy Schubert if (!pkex->code) 203c1d255d3SCy Schubert goto fail; 204*a90b9d01SCy Schubert pkex->code_len = code_len; 20532a95656SCy Schubert pkex->exchange_req = dpp_pkex_build_exchange_req(pkex, v2); 206c1d255d3SCy Schubert if (!pkex->exchange_req) 207c1d255d3SCy Schubert goto fail; 208c1d255d3SCy Schubert return pkex; 209c1d255d3SCy Schubert fail: 210c1d255d3SCy Schubert dpp_pkex_free(pkex); 211c1d255d3SCy Schubert return NULL; 212c1d255d3SCy Schubert } 213c1d255d3SCy Schubert 214c1d255d3SCy Schubert 215c1d255d3SCy Schubert static struct wpabuf * 216c1d255d3SCy Schubert dpp_pkex_build_exchange_resp(struct dpp_pkex *pkex, 217c1d255d3SCy Schubert enum dpp_status_error status, 2184b72b91aSCy Schubert const u8 *Nx, const u8 *Ny) 219c1d255d3SCy Schubert { 220c1d255d3SCy Schubert struct wpabuf *msg = NULL; 221c1d255d3SCy Schubert size_t attr_len; 222c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 223c1d255d3SCy Schubert 22432a95656SCy Schubert /* Initiator -> Responder: DPP Status, [Protocol Version,] [identifier,] 22532a95656SCy Schubert * N */ 226c1d255d3SCy Schubert attr_len = 4 + 1; 22732a95656SCy Schubert #ifdef CONFIG_DPP2 22832a95656SCy Schubert if (pkex->v2) 22932a95656SCy Schubert attr_len += 4 + 1; 23032a95656SCy Schubert #endif /* CONFIG_DPP2 */ 231c1d255d3SCy Schubert if (pkex->identifier) 232c1d255d3SCy Schubert attr_len += 4 + os_strlen(pkex->identifier); 233c1d255d3SCy Schubert attr_len += 4 + 2 * curve->prime_len; 234c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len); 235c1d255d3SCy Schubert if (!msg) 236c1d255d3SCy Schubert goto fail; 237c1d255d3SCy Schubert 238c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 239c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP) { 240c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Status"); 241c1d255d3SCy Schubert goto skip_status; 242c1d255d3SCy Schubert } 243c1d255d3SCy Schubert 244c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP) { 245c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Status"); 246c1d255d3SCy Schubert status = 255; 247c1d255d3SCy Schubert } 248c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 249c1d255d3SCy Schubert 250c1d255d3SCy Schubert /* DPP Status */ 251c1d255d3SCy Schubert dpp_build_attr_status(msg, status); 252c1d255d3SCy Schubert 253c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 254c1d255d3SCy Schubert skip_status: 255c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 256c1d255d3SCy Schubert 25732a95656SCy Schubert #ifdef CONFIG_DPP2 25832a95656SCy Schubert if (pkex->v2) { 25932a95656SCy Schubert /* Protocol Version */ 26032a95656SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 26132a95656SCy Schubert wpabuf_put_le16(msg, 1); 26232a95656SCy Schubert wpabuf_put_u8(msg, DPP_VERSION); 26332a95656SCy Schubert } 26432a95656SCy Schubert #endif /* CONFIG_DPP2 */ 26532a95656SCy Schubert 266c1d255d3SCy Schubert /* Code Identifier attribute */ 267c1d255d3SCy Schubert if (pkex->identifier) { 268c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 269c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 270c1d255d3SCy Schubert wpabuf_put_str(msg, pkex->identifier); 271c1d255d3SCy Schubert } 272c1d255d3SCy Schubert 273c1d255d3SCy Schubert if (status != DPP_STATUS_OK) 274c1d255d3SCy Schubert goto skip_encrypted_key; 275c1d255d3SCy Schubert 276c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 277c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 278c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Encrypted Key"); 279c1d255d3SCy Schubert goto skip_encrypted_key; 280c1d255d3SCy Schubert } 281c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 282c1d255d3SCy Schubert 283c1d255d3SCy Schubert /* N in Encrypted Key attribute */ 284c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 285c1d255d3SCy Schubert wpabuf_put_le16(msg, 2 * curve->prime_len); 286c1d255d3SCy Schubert 287c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 288c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP) { 289c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Encrypted Key"); 290c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(msg, curve) < 0) 291c1d255d3SCy Schubert goto fail; 292c1d255d3SCy Schubert goto skip_encrypted_key; 293c1d255d3SCy Schubert } 294c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 295c1d255d3SCy Schubert 2964b72b91aSCy Schubert wpabuf_put_data(msg, Nx, curve->prime_len); 2974b72b91aSCy Schubert wpabuf_put_data(msg, Ny, curve->prime_len); 2984b72b91aSCy Schubert os_memcpy(pkex->Nx, Nx, curve->prime_len); 299c1d255d3SCy Schubert 300c1d255d3SCy Schubert skip_encrypted_key: 301c1d255d3SCy Schubert if (status == DPP_STATUS_BAD_GROUP) { 302c1d255d3SCy Schubert /* Finite Cyclic Group attribute */ 303c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 304c1d255d3SCy Schubert wpabuf_put_le16(msg, 2); 305c1d255d3SCy Schubert wpabuf_put_le16(msg, curve->ike_group); 306c1d255d3SCy Schubert } 307c1d255d3SCy Schubert 308c1d255d3SCy Schubert return msg; 309c1d255d3SCy Schubert fail: 310c1d255d3SCy Schubert wpabuf_free(msg); 311c1d255d3SCy Schubert return NULL; 312c1d255d3SCy Schubert } 313c1d255d3SCy Schubert 314c1d255d3SCy Schubert 315c1d255d3SCy Schubert static int dpp_pkex_identifier_match(const u8 *attr_id, u16 attr_id_len, 316c1d255d3SCy Schubert const char *identifier) 317c1d255d3SCy Schubert { 318c1d255d3SCy Schubert if (!attr_id && identifier) { 319c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 320c1d255d3SCy Schubert "DPP: No PKEX code identifier received, but expected one"); 321c1d255d3SCy Schubert return 0; 322c1d255d3SCy Schubert } 323c1d255d3SCy Schubert 324c1d255d3SCy Schubert if (attr_id && !identifier) { 325c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 326c1d255d3SCy Schubert "DPP: PKEX code identifier received, but not expecting one"); 327c1d255d3SCy Schubert return 0; 328c1d255d3SCy Schubert } 329c1d255d3SCy Schubert 330c1d255d3SCy Schubert if (attr_id && identifier && 331c1d255d3SCy Schubert (os_strlen(identifier) != attr_id_len || 332c1d255d3SCy Schubert os_memcmp(identifier, attr_id, attr_id_len) != 0)) { 333c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); 334c1d255d3SCy Schubert return 0; 335c1d255d3SCy Schubert } 336c1d255d3SCy Schubert 337c1d255d3SCy Schubert return 1; 338c1d255d3SCy Schubert } 339c1d255d3SCy Schubert 340c1d255d3SCy Schubert 341c1d255d3SCy Schubert struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx, 342c1d255d3SCy Schubert struct dpp_bootstrap_info *bi, 343c1d255d3SCy Schubert const u8 *own_mac, 344c1d255d3SCy Schubert const u8 *peer_mac, 345c1d255d3SCy Schubert const char *identifier, 346*a90b9d01SCy Schubert const char *code, size_t code_len, 34732a95656SCy Schubert const u8 *buf, size_t len, bool v2) 348c1d255d3SCy Schubert { 349c1d255d3SCy Schubert const u8 *attr_group, *attr_id, *attr_key; 350c1d255d3SCy Schubert u16 attr_group_len, attr_id_len, attr_key_len; 351c1d255d3SCy Schubert const struct dpp_curve_params *curve = bi->curve; 352c1d255d3SCy Schubert u16 ike_group; 353c1d255d3SCy Schubert struct dpp_pkex *pkex = NULL; 3544b72b91aSCy Schubert struct crypto_ec_point *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, 355*a90b9d01SCy Schubert *N = NULL, *Y = NULL; 3564b72b91aSCy Schubert struct crypto_ec *ec = NULL; 3574b72b91aSCy Schubert u8 *x_coord = NULL, *y_coord = NULL; 358c1d255d3SCy Schubert u8 Kx[DPP_MAX_SHARED_SECRET_LEN]; 359c1d255d3SCy Schubert size_t Kx_len; 360c1d255d3SCy Schubert int res; 36132a95656SCy Schubert u8 peer_version = 0; 362c1d255d3SCy Schubert 363c1d255d3SCy Schubert if (bi->pkex_t >= PKEX_COUNTER_T_LIMIT) { 364c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 365c1d255d3SCy Schubert "PKEX counter t limit reached - ignore message"); 366c1d255d3SCy Schubert return NULL; 367c1d255d3SCy Schubert } 368c1d255d3SCy Schubert 36932a95656SCy Schubert #ifdef CONFIG_DPP2 37032a95656SCy Schubert if (v2) { 37132a95656SCy Schubert const u8 *version; 37232a95656SCy Schubert u16 version_len; 37332a95656SCy Schubert 37432a95656SCy Schubert version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION, 37532a95656SCy Schubert &version_len); 37632a95656SCy Schubert if (!version || version_len < 1 || version[0] == 0) { 37732a95656SCy Schubert wpa_msg(msg_ctx, MSG_INFO, 37832a95656SCy Schubert "Missing or invalid Protocol Version attribute"); 37932a95656SCy Schubert return NULL; 38032a95656SCy Schubert } 38132a95656SCy Schubert peer_version = version[0]; 38232a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 38332a95656SCy Schubert peer_version); 38432a95656SCy Schubert } 38532a95656SCy Schubert #endif /* CONFIG_DPP2 */ 38632a95656SCy Schubert 387c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 388c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 389c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 390c1d255d3SCy Schubert MAC2STR(dpp_pkex_peer_mac_override)); 391c1d255d3SCy Schubert peer_mac = dpp_pkex_peer_mac_override; 392c1d255d3SCy Schubert } 393c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_own_mac_override)) { 394c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - own_mac override " MACSTR, 395c1d255d3SCy Schubert MAC2STR(dpp_pkex_own_mac_override)); 396c1d255d3SCy Schubert own_mac = dpp_pkex_own_mac_override; 397c1d255d3SCy Schubert } 398c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 399c1d255d3SCy Schubert 400c1d255d3SCy Schubert attr_id_len = 0; 401c1d255d3SCy Schubert attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, 402c1d255d3SCy Schubert &attr_id_len); 403c1d255d3SCy Schubert if (!dpp_pkex_identifier_match(attr_id, attr_id_len, identifier)) 404c1d255d3SCy Schubert return NULL; 405c1d255d3SCy Schubert 406c1d255d3SCy Schubert attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, 407c1d255d3SCy Schubert &attr_group_len); 408c1d255d3SCy Schubert if (!attr_group || attr_group_len != 2) { 409c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 410c1d255d3SCy Schubert "Missing or invalid Finite Cyclic Group attribute"); 411c1d255d3SCy Schubert return NULL; 412c1d255d3SCy Schubert } 413c1d255d3SCy Schubert ike_group = WPA_GET_LE16(attr_group); 414c1d255d3SCy Schubert if (ike_group != curve->ike_group) { 415c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 416c1d255d3SCy Schubert "Mismatching PKEX curve: peer=%u own=%u", 417c1d255d3SCy Schubert ike_group, curve->ike_group); 418c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 419c1d255d3SCy Schubert if (!pkex) 420c1d255d3SCy Schubert goto fail; 42132a95656SCy Schubert pkex->v2 = v2; 42232a95656SCy Schubert pkex->peer_version = peer_version; 423c1d255d3SCy Schubert pkex->own_bi = bi; 424c1d255d3SCy Schubert pkex->failed = 1; 425c1d255d3SCy Schubert pkex->exchange_resp = dpp_pkex_build_exchange_resp( 426c1d255d3SCy Schubert pkex, DPP_STATUS_BAD_GROUP, NULL, NULL); 427c1d255d3SCy Schubert if (!pkex->exchange_resp) 428c1d255d3SCy Schubert goto fail; 429c1d255d3SCy Schubert return pkex; 430c1d255d3SCy Schubert } 431c1d255d3SCy Schubert 432c1d255d3SCy Schubert /* M in Encrypted Key attribute */ 433c1d255d3SCy Schubert attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY, 434c1d255d3SCy Schubert &attr_key_len); 435c1d255d3SCy Schubert if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 || 436c1d255d3SCy Schubert attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) { 437c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 438c1d255d3SCy Schubert "Missing Encrypted Key attribute"); 439c1d255d3SCy Schubert return NULL; 440c1d255d3SCy Schubert } 441c1d255d3SCy Schubert 44232a95656SCy Schubert /* Qi = H([MAC-Initiator |] [identifier |] code) * Pi */ 443*a90b9d01SCy Schubert Qi = dpp_pkex_derive_Qi(curve, v2 ? NULL : peer_mac, code, code_len, 444*a90b9d01SCy Schubert identifier, &ec); 445c1d255d3SCy Schubert if (!Qi) 446c1d255d3SCy Schubert goto fail; 447c1d255d3SCy Schubert 448c1d255d3SCy Schubert /* X' = M - Qi */ 4494b72b91aSCy Schubert X = crypto_ec_point_init(ec); 4504b72b91aSCy Schubert M = crypto_ec_point_from_bin(ec, attr_key); 4514b72b91aSCy Schubert if (!X || !M || 4524b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, M) || 4534b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, M) || 4544b72b91aSCy Schubert crypto_ec_point_invert(ec, Qi) || 4554b72b91aSCy Schubert crypto_ec_point_add(ec, M, Qi, X) || 4564b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, X) || 4574b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, X)) { 458c1d255d3SCy Schubert wpa_msg(msg_ctx, MSG_INFO, DPP_EVENT_FAIL 459c1d255d3SCy Schubert "Invalid Encrypted Key value"); 460c1d255d3SCy Schubert bi->pkex_t++; 461c1d255d3SCy Schubert goto fail; 462c1d255d3SCy Schubert } 4634b72b91aSCy Schubert crypto_ec_point_debug_print(ec, M, "DPP: M"); 4644b72b91aSCy Schubert crypto_ec_point_debug_print(ec, X, "DPP: X'"); 465c1d255d3SCy Schubert 466c1d255d3SCy Schubert pkex = os_zalloc(sizeof(*pkex)); 467c1d255d3SCy Schubert if (!pkex) 468c1d255d3SCy Schubert goto fail; 46932a95656SCy Schubert pkex->v2 = v2; 47032a95656SCy Schubert pkex->peer_version = peer_version; 471c1d255d3SCy Schubert pkex->t = bi->pkex_t; 472c1d255d3SCy Schubert pkex->msg_ctx = msg_ctx; 473c1d255d3SCy Schubert pkex->own_bi = bi; 474*a90b9d01SCy Schubert if (own_mac) 475c1d255d3SCy Schubert os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 476*a90b9d01SCy Schubert if (peer_mac) 477c1d255d3SCy Schubert os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 478c1d255d3SCy Schubert if (identifier) { 479c1d255d3SCy Schubert pkex->identifier = os_strdup(identifier); 480c1d255d3SCy Schubert if (!pkex->identifier) 481c1d255d3SCy Schubert goto fail; 482c1d255d3SCy Schubert } 483*a90b9d01SCy Schubert pkex->code = os_memdup(code, code_len); 484c1d255d3SCy Schubert if (!pkex->code) 485c1d255d3SCy Schubert goto fail; 486*a90b9d01SCy Schubert pkex->code_len = code_len; 487c1d255d3SCy Schubert 488c1d255d3SCy Schubert os_memcpy(pkex->Mx, attr_key, attr_key_len / 2); 489c1d255d3SCy Schubert 4904b72b91aSCy Schubert x_coord = os_malloc(curve->prime_len); 4914b72b91aSCy Schubert y_coord = os_malloc(curve->prime_len); 4924b72b91aSCy Schubert if (!x_coord || !y_coord || 4934b72b91aSCy Schubert crypto_ec_point_to_bin(ec, X, x_coord, y_coord)) 494c1d255d3SCy Schubert goto fail; 4954b72b91aSCy Schubert 4964b72b91aSCy Schubert pkex->x = crypto_ec_key_set_pub(curve->ike_group, x_coord, 4974b72b91aSCy Schubert y_coord, crypto_ec_prime_len(ec)); 4984b72b91aSCy Schubert if (!pkex->x) 499c1d255d3SCy Schubert goto fail; 500c1d255d3SCy Schubert 50132a95656SCy Schubert /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ 502*a90b9d01SCy Schubert Qr = dpp_pkex_derive_Qr(curve, v2 ? NULL : own_mac, code, code_len, 503*a90b9d01SCy Schubert identifier, NULL); 504c1d255d3SCy Schubert if (!Qr) 505c1d255d3SCy Schubert goto fail; 506c1d255d3SCy Schubert 507c1d255d3SCy Schubert /* Generate a random ephemeral keypair y/Y */ 508c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 509c1d255d3SCy Schubert if (dpp_pkex_ephemeral_key_override_len) { 510c1d255d3SCy Schubert const struct dpp_curve_params *tmp_curve; 511c1d255d3SCy Schubert 512c1d255d3SCy Schubert wpa_printf(MSG_INFO, 513c1d255d3SCy Schubert "DPP: TESTING - override ephemeral key y/Y"); 514c1d255d3SCy Schubert pkex->y = dpp_set_keypair(&tmp_curve, 515c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override, 516c1d255d3SCy Schubert dpp_pkex_ephemeral_key_override_len); 517c1d255d3SCy Schubert } else { 518c1d255d3SCy Schubert pkex->y = dpp_gen_keypair(curve); 519c1d255d3SCy Schubert } 520c1d255d3SCy Schubert #else /* CONFIG_TESTING_OPTIONS */ 521c1d255d3SCy Schubert pkex->y = dpp_gen_keypair(curve); 522c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 523c1d255d3SCy Schubert if (!pkex->y) 524c1d255d3SCy Schubert goto fail; 525c1d255d3SCy Schubert 526c1d255d3SCy Schubert /* N = Y + Qr */ 5274b72b91aSCy Schubert Y = crypto_ec_key_get_public_key(pkex->y); 5284b72b91aSCy Schubert if (!Y) 529c1d255d3SCy Schubert goto fail; 5304b72b91aSCy Schubert crypto_ec_point_debug_print(ec, Y, "DPP: Y"); 5314b72b91aSCy Schubert 5324b72b91aSCy Schubert N = crypto_ec_point_init(ec); 5334b72b91aSCy Schubert if (!N || 5344b72b91aSCy Schubert crypto_ec_point_add(ec, Y, Qr, N) || 5354b72b91aSCy Schubert crypto_ec_point_to_bin(ec, N, x_coord, y_coord)) 536c1d255d3SCy Schubert goto fail; 5374b72b91aSCy Schubert crypto_ec_point_debug_print(ec, N, "DPP: N"); 538c1d255d3SCy Schubert 539c1d255d3SCy Schubert pkex->exchange_resp = dpp_pkex_build_exchange_resp(pkex, DPP_STATUS_OK, 5404b72b91aSCy Schubert x_coord, y_coord); 541c1d255d3SCy Schubert if (!pkex->exchange_resp) 542c1d255d3SCy Schubert goto fail; 543c1d255d3SCy Schubert 544c1d255d3SCy Schubert /* K = y * X' */ 545c1d255d3SCy Schubert if (dpp_ecdh(pkex->y, pkex->x, Kx, &Kx_len) < 0) 546c1d255d3SCy Schubert goto fail; 547c1d255d3SCy Schubert 548c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 549c1d255d3SCy Schubert Kx, Kx_len); 550c1d255d3SCy Schubert 55132a95656SCy Schubert /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ 55232a95656SCy Schubert res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->peer_mac, 55332a95656SCy Schubert pkex->v2 ? NULL : pkex->own_mac, 55432a95656SCy Schubert pkex->peer_version, DPP_VERSION, 555c1d255d3SCy Schubert pkex->Mx, curve->prime_len, 556c1d255d3SCy Schubert pkex->Nx, curve->prime_len, pkex->code, 557*a90b9d01SCy Schubert pkex->code_len, Kx, Kx_len, pkex->z, 558*a90b9d01SCy Schubert curve->hash_len); 559c1d255d3SCy Schubert os_memset(Kx, 0, Kx_len); 560c1d255d3SCy Schubert if (res < 0) 561c1d255d3SCy Schubert goto fail; 562c1d255d3SCy Schubert 563c1d255d3SCy Schubert pkex->exchange_done = 1; 564c1d255d3SCy Schubert 565c1d255d3SCy Schubert out: 5664b72b91aSCy Schubert os_free(x_coord); 5674b72b91aSCy Schubert os_free(y_coord); 5684b72b91aSCy Schubert crypto_ec_point_deinit(Qi, 1); 5694b72b91aSCy Schubert crypto_ec_point_deinit(Qr, 1); 5704b72b91aSCy Schubert crypto_ec_point_deinit(M, 1); 5714b72b91aSCy Schubert crypto_ec_point_deinit(N, 1); 5724b72b91aSCy Schubert crypto_ec_point_deinit(X, 1); 573*a90b9d01SCy Schubert crypto_ec_point_deinit(Y, 1); 5744b72b91aSCy Schubert crypto_ec_deinit(ec); 575c1d255d3SCy Schubert return pkex; 576c1d255d3SCy Schubert fail: 577c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing failed"); 578c1d255d3SCy Schubert dpp_pkex_free(pkex); 579c1d255d3SCy Schubert pkex = NULL; 580c1d255d3SCy Schubert goto out; 581c1d255d3SCy Schubert } 582c1d255d3SCy Schubert 583c1d255d3SCy Schubert 584c1d255d3SCy Schubert static struct wpabuf * 585c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_req(struct dpp_pkex *pkex, 586c1d255d3SCy Schubert const struct wpabuf *A_pub, const u8 *u) 587c1d255d3SCy Schubert { 588c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 589c1d255d3SCy Schubert struct wpabuf *msg = NULL; 590c1d255d3SCy Schubert size_t clear_len, attr_len; 591c1d255d3SCy Schubert struct wpabuf *clear = NULL; 592c1d255d3SCy Schubert u8 *wrapped; 593c1d255d3SCy Schubert u8 octet; 594c1d255d3SCy Schubert const u8 *addr[2]; 595c1d255d3SCy Schubert size_t len[2]; 596c1d255d3SCy Schubert 597c1d255d3SCy Schubert /* {A, u, [bootstrapping info]}z */ 598c1d255d3SCy Schubert clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 599c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 600c1d255d3SCy Schubert attr_len = 4 + clear_len + AES_BLOCK_SIZE; 601c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 602c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) 603c1d255d3SCy Schubert attr_len += 5; 604c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 605c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, attr_len); 606c1d255d3SCy Schubert if (!clear || !msg) 607c1d255d3SCy Schubert goto fail; 608c1d255d3SCy Schubert 609c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 610c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ) { 611c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 612c1d255d3SCy Schubert goto skip_bootstrap_key; 613c1d255d3SCy Schubert } 614c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ) { 615c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 616c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 617c1d255d3SCy Schubert wpabuf_put_le16(clear, 2 * curve->prime_len); 618c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(clear, curve) < 0) 619c1d255d3SCy Schubert goto fail; 620c1d255d3SCy Schubert goto skip_bootstrap_key; 621c1d255d3SCy Schubert } 622c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 623c1d255d3SCy Schubert 624c1d255d3SCy Schubert /* A in Bootstrap Key attribute */ 625c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 626c1d255d3SCy Schubert wpabuf_put_le16(clear, wpabuf_len(A_pub)); 627c1d255d3SCy Schubert wpabuf_put_buf(clear, A_pub); 628c1d255d3SCy Schubert 629c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 630c1d255d3SCy Schubert skip_bootstrap_key: 631c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ) { 632c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no I-Auth tag"); 633c1d255d3SCy Schubert goto skip_i_auth_tag; 634c1d255d3SCy Schubert } 635c1d255d3SCy Schubert if (dpp_test == DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ) { 636c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - I-Auth tag mismatch"); 637c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 638c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 639c1d255d3SCy Schubert wpabuf_put_data(clear, u, curve->hash_len - 1); 640c1d255d3SCy Schubert wpabuf_put_u8(clear, u[curve->hash_len - 1] ^ 0x01); 641c1d255d3SCy Schubert goto skip_i_auth_tag; 642c1d255d3SCy Schubert } 643c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 644c1d255d3SCy Schubert 645c1d255d3SCy Schubert /* u in I-Auth tag attribute */ 646c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 647c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 648c1d255d3SCy Schubert wpabuf_put_data(clear, u, curve->hash_len); 649c1d255d3SCy Schubert 650c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 651c1d255d3SCy Schubert skip_i_auth_tag: 652c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ) { 653c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 654c1d255d3SCy Schubert goto skip_wrapped_data; 655c1d255d3SCy Schubert } 656c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 657c1d255d3SCy Schubert 658c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 659c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 660c1d255d3SCy Schubert octet = 0; 661c1d255d3SCy Schubert addr[1] = &octet; 662c1d255d3SCy Schubert len[1] = sizeof(octet); 663c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 664c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 665c1d255d3SCy Schubert 666c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 667c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 668c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 669c1d255d3SCy Schubert 670c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 671c1d255d3SCy Schubert if (aes_siv_encrypt(pkex->z, curve->hash_len, 672c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 673c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 674c1d255d3SCy Schubert goto fail; 675c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 676c1d255d3SCy Schubert wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 677c1d255d3SCy Schubert 678c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 679c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ) { 680c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 681c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK); 682c1d255d3SCy Schubert } 683c1d255d3SCy Schubert skip_wrapped_data: 684c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 685c1d255d3SCy Schubert 686c1d255d3SCy Schubert out: 687c1d255d3SCy Schubert wpabuf_free(clear); 688c1d255d3SCy Schubert return msg; 689c1d255d3SCy Schubert 690c1d255d3SCy Schubert fail: 691c1d255d3SCy Schubert wpabuf_free(msg); 692c1d255d3SCy Schubert msg = NULL; 693c1d255d3SCy Schubert goto out; 694c1d255d3SCy Schubert } 695c1d255d3SCy Schubert 696c1d255d3SCy Schubert 697c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, 698c1d255d3SCy Schubert const u8 *peer_mac, 699c1d255d3SCy Schubert const u8 *buf, size_t buflen) 700c1d255d3SCy Schubert { 701c1d255d3SCy Schubert const u8 *attr_status, *attr_id, *attr_key, *attr_group; 702c1d255d3SCy Schubert u16 attr_status_len, attr_id_len, attr_key_len, attr_group_len; 7034b72b91aSCy Schubert struct crypto_ec *ec = NULL; 704c1d255d3SCy Schubert struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 705c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 7064b72b91aSCy Schubert struct crypto_ec_point *Qr = NULL, *Y = NULL, *N = NULL; 7074b72b91aSCy Schubert u8 *x_coord = NULL, *y_coord = NULL; 708c1d255d3SCy Schubert size_t Jx_len, Kx_len; 709c1d255d3SCy Schubert u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; 710c1d255d3SCy Schubert const u8 *addr[4]; 711c1d255d3SCy Schubert size_t len[4]; 71232a95656SCy Schubert size_t num_elem; 713c1d255d3SCy Schubert u8 u[DPP_MAX_HASH_LEN]; 714c1d255d3SCy Schubert int res; 715c1d255d3SCy Schubert 716c1d255d3SCy Schubert if (pkex->failed || pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 717c1d255d3SCy Schubert return NULL; 718c1d255d3SCy Schubert 719c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 720c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP) { 721c1d255d3SCy Schubert wpa_printf(MSG_INFO, 722c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX Exchange Response"); 723c1d255d3SCy Schubert pkex->failed = 1; 724c1d255d3SCy Schubert return NULL; 725c1d255d3SCy Schubert } 726c1d255d3SCy Schubert 727c1d255d3SCy Schubert if (!is_zero_ether_addr(dpp_pkex_peer_mac_override)) { 728c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - peer_mac override " MACSTR, 729c1d255d3SCy Schubert MAC2STR(dpp_pkex_peer_mac_override)); 730c1d255d3SCy Schubert peer_mac = dpp_pkex_peer_mac_override; 731c1d255d3SCy Schubert } 732c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 733c1d255d3SCy Schubert 73432a95656SCy Schubert #ifdef CONFIG_DPP2 73532a95656SCy Schubert if (pkex->v2) { 73632a95656SCy Schubert const u8 *version; 73732a95656SCy Schubert u16 version_len; 73832a95656SCy Schubert 73932a95656SCy Schubert version = dpp_get_attr(buf, buflen, DPP_ATTR_PROTOCOL_VERSION, 74032a95656SCy Schubert &version_len); 74132a95656SCy Schubert if (!version || version_len < 1 || version[0] == 0) { 74232a95656SCy Schubert dpp_pkex_fail(pkex, 74332a95656SCy Schubert "Missing or invalid Protocol Version attribute"); 74432a95656SCy Schubert return NULL; 74532a95656SCy Schubert } 74632a95656SCy Schubert pkex->peer_version = version[0]; 74732a95656SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 74832a95656SCy Schubert pkex->peer_version); 74932a95656SCy Schubert } 75032a95656SCy Schubert #endif /* CONFIG_DPP2 */ 75132a95656SCy Schubert 752*a90b9d01SCy Schubert if (peer_mac) 753c1d255d3SCy Schubert os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 754c1d255d3SCy Schubert 755c1d255d3SCy Schubert attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, 756c1d255d3SCy Schubert &attr_status_len); 757c1d255d3SCy Schubert if (!attr_status || attr_status_len != 1) { 758c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No DPP Status attribute"); 759c1d255d3SCy Schubert return NULL; 760c1d255d3SCy Schubert } 761c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]); 762c1d255d3SCy Schubert 763c1d255d3SCy Schubert if (attr_status[0] == DPP_STATUS_BAD_GROUP) { 764c1d255d3SCy Schubert attr_group = dpp_get_attr(buf, buflen, 765c1d255d3SCy Schubert DPP_ATTR_FINITE_CYCLIC_GROUP, 766c1d255d3SCy Schubert &attr_group_len); 767c1d255d3SCy Schubert if (attr_group && attr_group_len == 2) { 768c1d255d3SCy Schubert wpa_msg(pkex->msg_ctx, MSG_INFO, DPP_EVENT_FAIL 769c1d255d3SCy Schubert "Peer indicated mismatching PKEX group - proposed %u", 770c1d255d3SCy Schubert WPA_GET_LE16(attr_group)); 771c1d255d3SCy Schubert return NULL; 772c1d255d3SCy Schubert } 773c1d255d3SCy Schubert } 774c1d255d3SCy Schubert 775c1d255d3SCy Schubert if (attr_status[0] != DPP_STATUS_OK) { 776c1d255d3SCy Schubert dpp_pkex_fail(pkex, "PKEX failed (peer indicated failure)"); 777c1d255d3SCy Schubert return NULL; 778c1d255d3SCy Schubert } 779c1d255d3SCy Schubert 780c1d255d3SCy Schubert attr_id_len = 0; 781c1d255d3SCy Schubert attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER, 782c1d255d3SCy Schubert &attr_id_len); 783c1d255d3SCy Schubert if (!dpp_pkex_identifier_match(attr_id, attr_id_len, 784c1d255d3SCy Schubert pkex->identifier)) { 785c1d255d3SCy Schubert dpp_pkex_fail(pkex, "PKEX code identifier mismatch"); 786c1d255d3SCy Schubert return NULL; 787c1d255d3SCy Schubert } 788c1d255d3SCy Schubert 789c1d255d3SCy Schubert /* N in Encrypted Key attribute */ 790c1d255d3SCy Schubert attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY, 791c1d255d3SCy Schubert &attr_key_len); 792c1d255d3SCy Schubert if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) { 793c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Missing Encrypted Key attribute"); 794c1d255d3SCy Schubert return NULL; 795c1d255d3SCy Schubert } 796c1d255d3SCy Schubert 79732a95656SCy Schubert /* Qr = H([MAC-Responder |] [identifier |] code) * Pr */ 79832a95656SCy Schubert Qr = dpp_pkex_derive_Qr(curve, pkex->v2 ? NULL : pkex->peer_mac, 799*a90b9d01SCy Schubert pkex->code, pkex->code_len, pkex->identifier, 800*a90b9d01SCy Schubert &ec); 801c1d255d3SCy Schubert if (!Qr) 802c1d255d3SCy Schubert goto fail; 803c1d255d3SCy Schubert 804c1d255d3SCy Schubert /* Y' = N - Qr */ 8054b72b91aSCy Schubert Y = crypto_ec_point_init(ec); 8064b72b91aSCy Schubert N = crypto_ec_point_from_bin(ec, attr_key); 8074b72b91aSCy Schubert if (!Y || !N || 8084b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, N) || 8094b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, N) || 8104b72b91aSCy Schubert crypto_ec_point_invert(ec, Qr) || 8114b72b91aSCy Schubert crypto_ec_point_add(ec, N, Qr, Y) || 8124b72b91aSCy Schubert crypto_ec_point_is_at_infinity(ec, Y) || 8134b72b91aSCy Schubert !crypto_ec_point_is_on_curve(ec, Y)) { 814c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid Encrypted Key value"); 815c1d255d3SCy Schubert pkex->t++; 816c1d255d3SCy Schubert goto fail; 817c1d255d3SCy Schubert } 8184b72b91aSCy Schubert crypto_ec_point_debug_print(ec, N, "DPP: N"); 8194b72b91aSCy Schubert crypto_ec_point_debug_print(ec, Y, "DPP: Y'"); 820c1d255d3SCy Schubert 821c1d255d3SCy Schubert pkex->exchange_done = 1; 822c1d255d3SCy Schubert 823c1d255d3SCy Schubert /* ECDH: J = a * Y' */ 8244b72b91aSCy Schubert x_coord = os_malloc(curve->prime_len); 8254b72b91aSCy Schubert y_coord = os_malloc(curve->prime_len); 8264b72b91aSCy Schubert if (!x_coord || !y_coord || 8274b72b91aSCy Schubert crypto_ec_point_to_bin(ec, Y, x_coord, y_coord)) 828c1d255d3SCy Schubert goto fail; 8294b72b91aSCy Schubert pkex->y = crypto_ec_key_set_pub(curve->ike_group, x_coord, y_coord, 8304b72b91aSCy Schubert curve->prime_len); 8314b72b91aSCy Schubert if (!pkex->y) 832c1d255d3SCy Schubert goto fail; 833c1d255d3SCy Schubert if (dpp_ecdh(pkex->own_bi->pubkey, pkex->y, Jx, &Jx_len) < 0) 834c1d255d3SCy Schubert goto fail; 835c1d255d3SCy Schubert 836c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 837c1d255d3SCy Schubert Jx, Jx_len); 838c1d255d3SCy Schubert 83932a95656SCy Schubert /* u = HMAC(J.x, [MAC-Initiator |] A.x | Y'.x | X.x) */ 8404b72b91aSCy Schubert A_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); 8414b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 8424b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 843c1d255d3SCy Schubert if (!A_pub || !Y_pub || !X_pub) 844c1d255d3SCy Schubert goto fail; 84532a95656SCy Schubert num_elem = 0; 84632a95656SCy Schubert if (!pkex->v2) { 84732a95656SCy Schubert addr[num_elem] = pkex->own_mac; 84832a95656SCy Schubert len[num_elem] = ETH_ALEN; 84932a95656SCy Schubert num_elem++; 85032a95656SCy Schubert } 85132a95656SCy Schubert addr[num_elem] = wpabuf_head(A_pub); 85232a95656SCy Schubert len[num_elem] = wpabuf_len(A_pub) / 2; 85332a95656SCy Schubert num_elem++; 85432a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 85532a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 85632a95656SCy Schubert num_elem++; 85732a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 85832a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 85932a95656SCy Schubert num_elem++; 86032a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) 86132a95656SCy Schubert < 0) 862c1d255d3SCy Schubert goto fail; 863c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len); 864c1d255d3SCy Schubert 865c1d255d3SCy Schubert /* K = x * Y' */ 866c1d255d3SCy Schubert if (dpp_ecdh(pkex->x, pkex->y, Kx, &Kx_len) < 0) 867c1d255d3SCy Schubert goto fail; 868c1d255d3SCy Schubert 869c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 870c1d255d3SCy Schubert Kx, Kx_len); 871c1d255d3SCy Schubert 87232a95656SCy Schubert /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ 87332a95656SCy Schubert res = dpp_pkex_derive_z(pkex->v2 ? NULL : pkex->own_mac, 87432a95656SCy Schubert pkex->v2 ? NULL : pkex->peer_mac, 87532a95656SCy Schubert DPP_VERSION, pkex->peer_version, 876c1d255d3SCy Schubert pkex->Mx, curve->prime_len, 877c1d255d3SCy Schubert attr_key /* N.x */, attr_key_len / 2, 878*a90b9d01SCy Schubert pkex->code, pkex->code_len, Kx, Kx_len, 879c1d255d3SCy Schubert pkex->z, curve->hash_len); 880c1d255d3SCy Schubert os_memset(Kx, 0, Kx_len); 881c1d255d3SCy Schubert if (res < 0) 882c1d255d3SCy Schubert goto fail; 883c1d255d3SCy Schubert 884c1d255d3SCy Schubert msg = dpp_pkex_build_commit_reveal_req(pkex, A_pub, u); 885c1d255d3SCy Schubert if (!msg) 886c1d255d3SCy Schubert goto fail; 887c1d255d3SCy Schubert 888c1d255d3SCy Schubert out: 889c1d255d3SCy Schubert wpabuf_free(A_pub); 890c1d255d3SCy Schubert wpabuf_free(X_pub); 891c1d255d3SCy Schubert wpabuf_free(Y_pub); 8924b72b91aSCy Schubert os_free(x_coord); 8934b72b91aSCy Schubert os_free(y_coord); 8944b72b91aSCy Schubert crypto_ec_point_deinit(Qr, 1); 8954b72b91aSCy Schubert crypto_ec_point_deinit(Y, 1); 8964b72b91aSCy Schubert crypto_ec_point_deinit(N, 1); 8974b72b91aSCy Schubert crypto_ec_deinit(ec); 898c1d255d3SCy Schubert return msg; 899c1d255d3SCy Schubert fail: 900c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing failed"); 901c1d255d3SCy Schubert goto out; 902c1d255d3SCy Schubert } 903c1d255d3SCy Schubert 904c1d255d3SCy Schubert 905c1d255d3SCy Schubert static struct wpabuf * 906c1d255d3SCy Schubert dpp_pkex_build_commit_reveal_resp(struct dpp_pkex *pkex, 907c1d255d3SCy Schubert const struct wpabuf *B_pub, const u8 *v) 908c1d255d3SCy Schubert { 909c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 910c1d255d3SCy Schubert struct wpabuf *msg = NULL; 911c1d255d3SCy Schubert const u8 *addr[2]; 912c1d255d3SCy Schubert size_t len[2]; 913c1d255d3SCy Schubert u8 octet; 914c1d255d3SCy Schubert u8 *wrapped; 915c1d255d3SCy Schubert struct wpabuf *clear = NULL; 916c1d255d3SCy Schubert size_t clear_len, attr_len; 917c1d255d3SCy Schubert 918c1d255d3SCy Schubert /* {B, v [bootstrapping info]}z */ 919c1d255d3SCy Schubert clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 920c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 921c1d255d3SCy Schubert attr_len = 4 + clear_len + AES_BLOCK_SIZE; 922c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 923c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) 924c1d255d3SCy Schubert attr_len += 5; 925c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 926c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, attr_len); 927c1d255d3SCy Schubert if (!clear || !msg) 928c1d255d3SCy Schubert goto fail; 929c1d255d3SCy Schubert 930c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 931c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP) { 932c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Bootstrap Key"); 933c1d255d3SCy Schubert goto skip_bootstrap_key; 934c1d255d3SCy Schubert } 935c1d255d3SCy Schubert if (dpp_test == DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP) { 936c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Bootstrap Key"); 937c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 938c1d255d3SCy Schubert wpabuf_put_le16(clear, 2 * curve->prime_len); 939c1d255d3SCy Schubert if (dpp_test_gen_invalid_key(clear, curve) < 0) 940c1d255d3SCy Schubert goto fail; 941c1d255d3SCy Schubert goto skip_bootstrap_key; 942c1d255d3SCy Schubert } 943c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 944c1d255d3SCy Schubert 945c1d255d3SCy Schubert /* B in Bootstrap Key attribute */ 946c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 947c1d255d3SCy Schubert wpabuf_put_le16(clear, wpabuf_len(B_pub)); 948c1d255d3SCy Schubert wpabuf_put_buf(clear, B_pub); 949c1d255d3SCy Schubert 950c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 951c1d255d3SCy Schubert skip_bootstrap_key: 952c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP) { 953c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no R-Auth tag"); 954c1d255d3SCy Schubert goto skip_r_auth_tag; 955c1d255d3SCy Schubert } 956c1d255d3SCy Schubert if (dpp_test == DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP) { 957c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - R-Auth tag mismatch"); 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 - 1); 961c1d255d3SCy Schubert wpabuf_put_u8(clear, v[curve->hash_len - 1] ^ 0x01); 962c1d255d3SCy Schubert goto skip_r_auth_tag; 963c1d255d3SCy Schubert } 964c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 965c1d255d3SCy Schubert 966c1d255d3SCy Schubert /* v in R-Auth tag attribute */ 967c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 968c1d255d3SCy Schubert wpabuf_put_le16(clear, curve->hash_len); 969c1d255d3SCy Schubert wpabuf_put_data(clear, v, curve->hash_len); 970c1d255d3SCy Schubert 971c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 972c1d255d3SCy Schubert skip_r_auth_tag: 973c1d255d3SCy Schubert if (dpp_test == DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP) { 974c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Wrapped Data"); 975c1d255d3SCy Schubert goto skip_wrapped_data; 976c1d255d3SCy Schubert } 977c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 978c1d255d3SCy Schubert 979c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 980c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 981c1d255d3SCy Schubert octet = 1; 982c1d255d3SCy Schubert addr[1] = &octet; 983c1d255d3SCy Schubert len[1] = sizeof(octet); 984c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 985c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 986c1d255d3SCy Schubert 987c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 988c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 989c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 990c1d255d3SCy Schubert 991c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 992c1d255d3SCy Schubert if (aes_siv_encrypt(pkex->z, curve->hash_len, 993c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 994c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 995c1d255d3SCy Schubert goto fail; 996c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 997c1d255d3SCy Schubert wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 998c1d255d3SCy Schubert 999c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1000c1d255d3SCy Schubert if (dpp_test == DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP) { 1001c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - attr after Wrapped Data"); 1002c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK); 1003c1d255d3SCy Schubert } 1004c1d255d3SCy Schubert skip_wrapped_data: 1005c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1006c1d255d3SCy Schubert 1007c1d255d3SCy Schubert out: 1008c1d255d3SCy Schubert wpabuf_free(clear); 1009c1d255d3SCy Schubert return msg; 1010c1d255d3SCy Schubert 1011c1d255d3SCy Schubert fail: 1012c1d255d3SCy Schubert wpabuf_free(msg); 1013c1d255d3SCy Schubert msg = NULL; 1014c1d255d3SCy Schubert goto out; 1015c1d255d3SCy Schubert } 1016c1d255d3SCy Schubert 1017c1d255d3SCy Schubert 1018c1d255d3SCy Schubert struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, 1019c1d255d3SCy Schubert const u8 *hdr, 1020c1d255d3SCy Schubert const u8 *buf, size_t buflen) 1021c1d255d3SCy Schubert { 1022c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 1023c1d255d3SCy Schubert size_t Jx_len, Lx_len; 1024c1d255d3SCy Schubert u8 Jx[DPP_MAX_SHARED_SECRET_LEN]; 1025c1d255d3SCy Schubert u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 1026c1d255d3SCy Schubert const u8 *wrapped_data, *b_key, *peer_u; 1027c1d255d3SCy Schubert u16 wrapped_data_len, b_key_len, peer_u_len = 0; 1028c1d255d3SCy Schubert const u8 *addr[4]; 1029c1d255d3SCy Schubert size_t len[4]; 103032a95656SCy Schubert size_t num_elem; 1031c1d255d3SCy Schubert u8 octet; 1032c1d255d3SCy Schubert u8 *unwrapped = NULL; 1033c1d255d3SCy Schubert size_t unwrapped_len = 0; 1034c1d255d3SCy Schubert struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 1035c1d255d3SCy Schubert struct wpabuf *B_pub = NULL; 1036c1d255d3SCy Schubert u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; 1037c1d255d3SCy Schubert 1038c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1039c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_REQ) { 1040c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1041c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX CR Request"); 1042c1d255d3SCy Schubert pkex->failed = 1; 1043c1d255d3SCy Schubert return NULL; 1044c1d255d3SCy Schubert } 1045c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1046c1d255d3SCy Schubert 1047c1d255d3SCy Schubert if (!pkex->exchange_done || pkex->failed || 1048c1d255d3SCy Schubert pkex->t >= PKEX_COUNTER_T_LIMIT || pkex->initiator) 1049c1d255d3SCy Schubert goto fail; 1050c1d255d3SCy Schubert 1051c1d255d3SCy Schubert wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 1052c1d255d3SCy Schubert &wrapped_data_len); 1053c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 1054c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1055c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 1056c1d255d3SCy Schubert goto fail; 1057c1d255d3SCy Schubert } 1058c1d255d3SCy Schubert 1059c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1060c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 1061c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 1062c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 1063c1d255d3SCy Schubert if (!unwrapped) 1064c1d255d3SCy Schubert goto fail; 1065c1d255d3SCy Schubert 1066c1d255d3SCy Schubert addr[0] = hdr; 1067c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 1068c1d255d3SCy Schubert octet = 0; 1069c1d255d3SCy Schubert addr[1] = &octet; 1070c1d255d3SCy Schubert len[1] = sizeof(octet); 1071c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1072c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1073c1d255d3SCy Schubert 1074c1d255d3SCy Schubert if (aes_siv_decrypt(pkex->z, curve->hash_len, 1075c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 1076c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 1077c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1078c1d255d3SCy Schubert "AES-SIV decryption failed - possible PKEX code mismatch"); 1079c1d255d3SCy Schubert pkex->failed = 1; 1080c1d255d3SCy Schubert pkex->t++; 1081c1d255d3SCy Schubert goto fail; 1082c1d255d3SCy Schubert } 1083c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 1084c1d255d3SCy Schubert unwrapped, unwrapped_len); 1085c1d255d3SCy Schubert 1086c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 1087c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 1088c1d255d3SCy Schubert goto fail; 1089c1d255d3SCy Schubert } 1090c1d255d3SCy Schubert 1091c1d255d3SCy Schubert b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 1092c1d255d3SCy Schubert &b_key_len); 1093c1d255d3SCy Schubert if (!b_key || b_key_len != 2 * curve->prime_len) { 1094c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 1095c1d255d3SCy Schubert goto fail; 1096c1d255d3SCy Schubert } 1097c1d255d3SCy Schubert pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 1098c1d255d3SCy Schubert b_key_len); 1099c1d255d3SCy Schubert if (!pkex->peer_bootstrap_key) { 1100c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 1101c1d255d3SCy Schubert goto fail; 1102c1d255d3SCy Schubert } 1103c1d255d3SCy Schubert dpp_debug_print_key("DPP: Peer bootstrap public key", 1104c1d255d3SCy Schubert pkex->peer_bootstrap_key); 1105c1d255d3SCy Schubert 1106c1d255d3SCy Schubert /* ECDH: J' = y * A' */ 1107c1d255d3SCy Schubert if (dpp_ecdh(pkex->y, pkex->peer_bootstrap_key, Jx, &Jx_len) < 0) 1108c1d255d3SCy Schubert goto fail; 1109c1d255d3SCy Schubert 1110c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 1111c1d255d3SCy Schubert Jx, Jx_len); 1112c1d255d3SCy Schubert 111332a95656SCy Schubert /* u' = HMAC(J'.x, [MAC-Initiator |] A'.x | Y.x | X'.x) */ 11144b72b91aSCy Schubert A_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); 11154b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 11164b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 1117c1d255d3SCy Schubert if (!A_pub || !Y_pub || !X_pub) 1118c1d255d3SCy Schubert goto fail; 111932a95656SCy Schubert num_elem = 0; 112032a95656SCy Schubert if (!pkex->v2) { 112132a95656SCy Schubert addr[num_elem] = pkex->peer_mac; 112232a95656SCy Schubert len[num_elem] = ETH_ALEN; 112332a95656SCy Schubert num_elem++; 112432a95656SCy Schubert } 112532a95656SCy Schubert addr[num_elem] = wpabuf_head(A_pub); 112632a95656SCy Schubert len[num_elem] = wpabuf_len(A_pub) / 2; 112732a95656SCy Schubert num_elem++; 112832a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 112932a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 113032a95656SCy Schubert num_elem++; 113132a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 113232a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 113332a95656SCy Schubert num_elem++; 113432a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, num_elem, addr, len, u) 113532a95656SCy Schubert < 0) 1136c1d255d3SCy Schubert goto fail; 1137c1d255d3SCy Schubert 1138c1d255d3SCy Schubert peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 1139c1d255d3SCy Schubert &peer_u_len); 1140c1d255d3SCy Schubert if (!peer_u || peer_u_len != curve->hash_len || 1141c1d255d3SCy Schubert os_memcmp(peer_u, u, curve->hash_len) != 0) { 1142c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid u (I-Auth tag) found"); 1143c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'", 1144c1d255d3SCy Schubert u, curve->hash_len); 1145c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len); 1146c1d255d3SCy Schubert pkex->t++; 1147c1d255d3SCy Schubert goto fail; 1148c1d255d3SCy Schubert } 1149c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received"); 1150c1d255d3SCy Schubert 1151c1d255d3SCy Schubert /* ECDH: L = b * X' */ 1152c1d255d3SCy Schubert if (dpp_ecdh(pkex->own_bi->pubkey, pkex->x, Lx, &Lx_len) < 0) 1153c1d255d3SCy Schubert goto fail; 1154c1d255d3SCy Schubert 1155c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 1156c1d255d3SCy Schubert Lx, Lx_len); 1157c1d255d3SCy Schubert 115832a95656SCy Schubert /* v = HMAC(L.x, [MAC-Responder |] B.x | X'.x | Y.x) */ 11594b72b91aSCy Schubert B_pub = crypto_ec_key_get_pubkey_point(pkex->own_bi->pubkey, 0); 1160c1d255d3SCy Schubert if (!B_pub) 1161c1d255d3SCy Schubert goto fail; 116232a95656SCy Schubert num_elem = 0; 116332a95656SCy Schubert if (!pkex->v2) { 116432a95656SCy Schubert addr[num_elem] = pkex->own_mac; 116532a95656SCy Schubert len[num_elem] = ETH_ALEN; 116632a95656SCy Schubert num_elem++; 116732a95656SCy Schubert } 116832a95656SCy Schubert addr[num_elem] = wpabuf_head(B_pub); 116932a95656SCy Schubert len[num_elem] = wpabuf_len(B_pub) / 2; 117032a95656SCy Schubert num_elem++; 117132a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 117232a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 117332a95656SCy Schubert num_elem++; 117432a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 117532a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 117632a95656SCy Schubert num_elem++; 117732a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) 117832a95656SCy Schubert < 0) 1179c1d255d3SCy Schubert goto fail; 1180c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len); 1181c1d255d3SCy Schubert 1182c1d255d3SCy Schubert msg = dpp_pkex_build_commit_reveal_resp(pkex, B_pub, v); 1183c1d255d3SCy Schubert if (!msg) 1184c1d255d3SCy Schubert goto fail; 1185c1d255d3SCy Schubert 1186c1d255d3SCy Schubert out: 1187c1d255d3SCy Schubert os_free(unwrapped); 1188c1d255d3SCy Schubert wpabuf_free(A_pub); 1189c1d255d3SCy Schubert wpabuf_free(B_pub); 1190c1d255d3SCy Schubert wpabuf_free(X_pub); 1191c1d255d3SCy Schubert wpabuf_free(Y_pub); 1192c1d255d3SCy Schubert return msg; 1193c1d255d3SCy Schubert fail: 1194c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1195c1d255d3SCy Schubert "DPP: PKEX Commit-Reveal Request processing failed"); 1196c1d255d3SCy Schubert goto out; 1197c1d255d3SCy Schubert } 1198c1d255d3SCy Schubert 1199c1d255d3SCy Schubert 1200c1d255d3SCy Schubert int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, 1201c1d255d3SCy Schubert const u8 *buf, size_t buflen) 1202c1d255d3SCy Schubert { 1203c1d255d3SCy Schubert const struct dpp_curve_params *curve = pkex->own_bi->curve; 1204c1d255d3SCy Schubert const u8 *wrapped_data, *b_key, *peer_v; 1205c1d255d3SCy Schubert u16 wrapped_data_len, b_key_len, peer_v_len = 0; 1206c1d255d3SCy Schubert const u8 *addr[4]; 1207c1d255d3SCy Schubert size_t len[4]; 120832a95656SCy Schubert size_t num_elem; 1209c1d255d3SCy Schubert u8 octet; 1210c1d255d3SCy Schubert u8 *unwrapped = NULL; 1211c1d255d3SCy Schubert size_t unwrapped_len = 0; 1212c1d255d3SCy Schubert int ret = -1; 1213c1d255d3SCy Schubert u8 v[DPP_MAX_HASH_LEN]; 1214c1d255d3SCy Schubert size_t Lx_len; 1215c1d255d3SCy Schubert u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 1216c1d255d3SCy Schubert struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 1217c1d255d3SCy Schubert 1218c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 1219c1d255d3SCy Schubert if (dpp_test == DPP_TEST_STOP_AT_PKEX_CR_RESP) { 1220c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1221c1d255d3SCy Schubert "DPP: TESTING - stop at PKEX CR Response"); 1222c1d255d3SCy Schubert pkex->failed = 1; 1223c1d255d3SCy Schubert goto fail; 1224c1d255d3SCy Schubert } 1225c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 1226c1d255d3SCy Schubert 1227c1d255d3SCy Schubert if (!pkex->exchange_done || pkex->failed || 1228c1d255d3SCy Schubert pkex->t >= PKEX_COUNTER_T_LIMIT || !pkex->initiator) 1229c1d255d3SCy Schubert goto fail; 1230c1d255d3SCy Schubert 1231c1d255d3SCy Schubert wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 1232c1d255d3SCy Schubert &wrapped_data_len); 1233c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 1234c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1235c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 1236c1d255d3SCy Schubert goto fail; 1237c1d255d3SCy Schubert } 1238c1d255d3SCy Schubert 1239c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1240c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 1241c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 1242c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 1243c1d255d3SCy Schubert if (!unwrapped) 1244c1d255d3SCy Schubert goto fail; 1245c1d255d3SCy Schubert 1246c1d255d3SCy Schubert addr[0] = hdr; 1247c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 1248c1d255d3SCy Schubert octet = 1; 1249c1d255d3SCy Schubert addr[1] = &octet; 1250c1d255d3SCy Schubert len[1] = sizeof(octet); 1251c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1252c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1253c1d255d3SCy Schubert 1254c1d255d3SCy Schubert if (aes_siv_decrypt(pkex->z, curve->hash_len, 1255c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 1256c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 1257c1d255d3SCy Schubert dpp_pkex_fail(pkex, 1258c1d255d3SCy Schubert "AES-SIV decryption failed - possible PKEX code mismatch"); 1259c1d255d3SCy Schubert pkex->t++; 1260c1d255d3SCy Schubert goto fail; 1261c1d255d3SCy Schubert } 1262c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 1263c1d255d3SCy Schubert unwrapped, unwrapped_len); 1264c1d255d3SCy Schubert 1265c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 1266c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Invalid attribute in unwrapped data"); 1267c1d255d3SCy Schubert goto fail; 1268c1d255d3SCy Schubert } 1269c1d255d3SCy Schubert 1270c1d255d3SCy Schubert b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 1271c1d255d3SCy Schubert &b_key_len); 1272c1d255d3SCy Schubert if (!b_key || b_key_len != 2 * curve->prime_len) { 1273c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid peer bootstrapping key found"); 1274c1d255d3SCy Schubert goto fail; 1275c1d255d3SCy Schubert } 1276c1d255d3SCy Schubert pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 1277c1d255d3SCy Schubert b_key_len); 1278c1d255d3SCy Schubert if (!pkex->peer_bootstrap_key) { 1279c1d255d3SCy Schubert dpp_pkex_fail(pkex, "Peer bootstrapping key is invalid"); 1280c1d255d3SCy Schubert goto fail; 1281c1d255d3SCy Schubert } 1282c1d255d3SCy Schubert dpp_debug_print_key("DPP: Peer bootstrap public key", 1283c1d255d3SCy Schubert pkex->peer_bootstrap_key); 1284c1d255d3SCy Schubert 1285c1d255d3SCy Schubert /* ECDH: L' = x * B' */ 1286c1d255d3SCy Schubert if (dpp_ecdh(pkex->x, pkex->peer_bootstrap_key, Lx, &Lx_len) < 0) 1287c1d255d3SCy Schubert goto fail; 1288c1d255d3SCy Schubert 1289c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 1290c1d255d3SCy Schubert Lx, Lx_len); 1291c1d255d3SCy Schubert 129232a95656SCy Schubert /* v' = HMAC(L.x, [MAC-Responder |] B'.x | X.x | Y'.x) */ 12934b72b91aSCy Schubert B_pub = crypto_ec_key_get_pubkey_point(pkex->peer_bootstrap_key, 0); 12944b72b91aSCy Schubert X_pub = crypto_ec_key_get_pubkey_point(pkex->x, 0); 12954b72b91aSCy Schubert Y_pub = crypto_ec_key_get_pubkey_point(pkex->y, 0); 1296c1d255d3SCy Schubert if (!B_pub || !X_pub || !Y_pub) 1297c1d255d3SCy Schubert goto fail; 129832a95656SCy Schubert num_elem = 0; 129932a95656SCy Schubert if (!pkex->v2) { 130032a95656SCy Schubert addr[num_elem] = pkex->peer_mac; 130132a95656SCy Schubert len[num_elem] = ETH_ALEN; 130232a95656SCy Schubert num_elem++; 130332a95656SCy Schubert } 130432a95656SCy Schubert addr[num_elem] = wpabuf_head(B_pub); 130532a95656SCy Schubert len[num_elem] = wpabuf_len(B_pub) / 2; 130632a95656SCy Schubert num_elem++; 130732a95656SCy Schubert addr[num_elem] = wpabuf_head(X_pub); 130832a95656SCy Schubert len[num_elem] = wpabuf_len(X_pub) / 2; 130932a95656SCy Schubert num_elem++; 131032a95656SCy Schubert addr[num_elem] = wpabuf_head(Y_pub); 131132a95656SCy Schubert len[num_elem] = wpabuf_len(Y_pub) / 2; 131232a95656SCy Schubert num_elem++; 131332a95656SCy Schubert if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, num_elem, addr, len, v) 131432a95656SCy Schubert < 0) 1315c1d255d3SCy Schubert goto fail; 1316c1d255d3SCy Schubert 1317c1d255d3SCy Schubert peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG, 1318c1d255d3SCy Schubert &peer_v_len); 1319c1d255d3SCy Schubert if (!peer_v || peer_v_len != curve->hash_len || 1320c1d255d3SCy Schubert os_memcmp(peer_v, v, curve->hash_len) != 0) { 1321c1d255d3SCy Schubert dpp_pkex_fail(pkex, "No valid v (R-Auth tag) found"); 1322c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'", 1323c1d255d3SCy Schubert v, curve->hash_len); 1324c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len); 1325c1d255d3SCy Schubert pkex->t++; 1326c1d255d3SCy Schubert goto fail; 1327c1d255d3SCy Schubert } 1328c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received"); 1329c1d255d3SCy Schubert 1330c1d255d3SCy Schubert ret = 0; 1331c1d255d3SCy Schubert out: 1332c1d255d3SCy Schubert wpabuf_free(B_pub); 1333c1d255d3SCy Schubert wpabuf_free(X_pub); 1334c1d255d3SCy Schubert wpabuf_free(Y_pub); 1335c1d255d3SCy Schubert os_free(unwrapped); 1336c1d255d3SCy Schubert return ret; 1337c1d255d3SCy Schubert fail: 1338c1d255d3SCy Schubert goto out; 1339c1d255d3SCy Schubert } 1340c1d255d3SCy Schubert 1341c1d255d3SCy Schubert 1342c1d255d3SCy Schubert struct dpp_bootstrap_info * 1343c1d255d3SCy Schubert dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, 1344c1d255d3SCy Schubert unsigned int freq) 1345c1d255d3SCy Schubert { 1346c1d255d3SCy Schubert struct dpp_bootstrap_info *bi; 1347c1d255d3SCy Schubert 1348c1d255d3SCy Schubert bi = os_zalloc(sizeof(*bi)); 1349c1d255d3SCy Schubert if (!bi) 1350c1d255d3SCy Schubert return NULL; 1351c1d255d3SCy Schubert bi->id = dpp_next_id(dpp); 1352c1d255d3SCy Schubert bi->type = DPP_BOOTSTRAP_PKEX; 1353*a90b9d01SCy Schubert if (peer) 1354c1d255d3SCy Schubert os_memcpy(bi->mac_addr, peer, ETH_ALEN); 1355*a90b9d01SCy Schubert if (freq) { 1356c1d255d3SCy Schubert bi->num_freq = 1; 1357c1d255d3SCy Schubert bi->freq[0] = freq; 1358*a90b9d01SCy Schubert } 1359c1d255d3SCy Schubert bi->curve = pkex->own_bi->curve; 1360c1d255d3SCy Schubert bi->pubkey = pkex->peer_bootstrap_key; 1361c1d255d3SCy Schubert pkex->peer_bootstrap_key = NULL; 1362c1d255d3SCy Schubert if (dpp_bootstrap_key_hash(bi) < 0) { 1363c1d255d3SCy Schubert dpp_bootstrap_info_free(bi); 1364c1d255d3SCy Schubert return NULL; 1365c1d255d3SCy Schubert } 1366*a90b9d01SCy Schubert os_memcpy(pkex->own_bi->peer_pubkey_hash, bi->pubkey_hash, 1367*a90b9d01SCy Schubert SHA256_MAC_LEN); 1368c1d255d3SCy Schubert dpp_pkex_free(pkex); 1369c1d255d3SCy Schubert dl_list_add(&dpp->bootstrap, &bi->list); 1370c1d255d3SCy Schubert return bi; 1371c1d255d3SCy Schubert } 1372c1d255d3SCy Schubert 1373c1d255d3SCy Schubert 1374c1d255d3SCy Schubert void dpp_pkex_free(struct dpp_pkex *pkex) 1375c1d255d3SCy Schubert { 1376c1d255d3SCy Schubert if (!pkex) 1377c1d255d3SCy Schubert return; 1378c1d255d3SCy Schubert 1379c1d255d3SCy Schubert os_free(pkex->identifier); 1380c1d255d3SCy Schubert os_free(pkex->code); 13814b72b91aSCy Schubert crypto_ec_key_deinit(pkex->x); 13824b72b91aSCy Schubert crypto_ec_key_deinit(pkex->y); 13834b72b91aSCy Schubert crypto_ec_key_deinit(pkex->peer_bootstrap_key); 1384c1d255d3SCy Schubert wpabuf_free(pkex->exchange_req); 1385c1d255d3SCy Schubert wpabuf_free(pkex->exchange_resp); 1386*a90b9d01SCy Schubert wpabuf_free(pkex->enc_key); 1387c1d255d3SCy Schubert os_free(pkex); 1388c1d255d3SCy Schubert } 1389