1c1d255d3SCy Schubert /* 2c1d255d3SCy Schubert * DPP reconfiguration 3c1d255d3SCy Schubert * Copyright (c) 2020, The Linux Foundation 4c1d255d3SCy Schubert * 5c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license. 6c1d255d3SCy Schubert * See README for more details. 7c1d255d3SCy Schubert */ 8c1d255d3SCy Schubert 9c1d255d3SCy Schubert #include "utils/includes.h" 10c1d255d3SCy Schubert 11c1d255d3SCy Schubert #include "utils/common.h" 12c1d255d3SCy Schubert #include "utils/json.h" 13c1d255d3SCy Schubert #include "crypto/crypto.h" 14c1d255d3SCy Schubert #include "crypto/random.h" 15c1d255d3SCy Schubert #include "crypto/aes.h" 16c1d255d3SCy Schubert #include "crypto/aes_siv.h" 17c1d255d3SCy Schubert #include "dpp.h" 18c1d255d3SCy Schubert #include "dpp_i.h" 19c1d255d3SCy Schubert 20c1d255d3SCy Schubert 21c1d255d3SCy Schubert #ifdef CONFIG_DPP2 22c1d255d3SCy Schubert 23c1d255d3SCy Schubert static void dpp_build_attr_csign_key_hash(struct wpabuf *msg, const u8 *hash) 24c1d255d3SCy Schubert { 25c1d255d3SCy Schubert if (hash) { 26c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Configurator C-sign key Hash"); 27c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_C_SIGN_KEY_HASH); 28c1d255d3SCy Schubert wpabuf_put_le16(msg, SHA256_MAC_LEN); 29c1d255d3SCy Schubert wpabuf_put_data(msg, hash, SHA256_MAC_LEN); 30c1d255d3SCy Schubert } 31c1d255d3SCy Schubert } 32c1d255d3SCy Schubert 33c1d255d3SCy Schubert 34c1d255d3SCy Schubert struct wpabuf * dpp_build_reconfig_announcement(const u8 *csign_key, 35c1d255d3SCy Schubert size_t csign_key_len, 36c1d255d3SCy Schubert const u8 *net_access_key, 37c1d255d3SCy Schubert size_t net_access_key_len, 38c1d255d3SCy Schubert struct dpp_reconfig_id *id) 39c1d255d3SCy Schubert { 40c1d255d3SCy Schubert struct wpabuf *msg = NULL; 414b72b91aSCy Schubert struct crypto_ec_key *csign = NULL; 42c1d255d3SCy Schubert struct wpabuf *uncomp; 43c1d255d3SCy Schubert u8 hash[SHA256_MAC_LEN]; 44c1d255d3SCy Schubert const u8 *addr[1]; 45c1d255d3SCy Schubert size_t len[1]; 46c1d255d3SCy Schubert int res; 47c1d255d3SCy Schubert size_t attr_len; 48c1d255d3SCy Schubert const struct dpp_curve_params *own_curve; 494b72b91aSCy Schubert struct crypto_ec_key *own_key; 50c1d255d3SCy Schubert struct wpabuf *a_nonce = NULL, *e_id = NULL; 51c1d255d3SCy Schubert 52c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Build Reconfig Announcement frame"); 53c1d255d3SCy Schubert 54c1d255d3SCy Schubert own_key = dpp_set_keypair(&own_curve, net_access_key, 55c1d255d3SCy Schubert net_access_key_len); 56c1d255d3SCy Schubert if (!own_key) { 57c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 58c1d255d3SCy Schubert goto fail; 59c1d255d3SCy Schubert } 60c1d255d3SCy Schubert 614b72b91aSCy Schubert csign = crypto_ec_key_parse_pub(csign_key, csign_key_len); 62c1d255d3SCy Schubert if (!csign) { 63c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 64c1d255d3SCy Schubert "DPP: Failed to parse local C-sign-key information"); 65c1d255d3SCy Schubert goto fail; 66c1d255d3SCy Schubert } 67c1d255d3SCy Schubert 684b72b91aSCy Schubert uncomp = crypto_ec_key_get_pubkey_point(csign, 1); 694b72b91aSCy Schubert crypto_ec_key_deinit(csign); 70c1d255d3SCy Schubert if (!uncomp) 71c1d255d3SCy Schubert goto fail; 72c1d255d3SCy Schubert addr[0] = wpabuf_head(uncomp); 73c1d255d3SCy Schubert len[0] = wpabuf_len(uncomp); 74c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed C-sign key", addr[0], len[0]); 75c1d255d3SCy Schubert res = sha256_vector(1, addr, len, hash); 76c1d255d3SCy Schubert wpabuf_free(uncomp); 77c1d255d3SCy Schubert if (res < 0) 78c1d255d3SCy Schubert goto fail; 79c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: kid = SHA256(uncompressed C-sign key)", 80c1d255d3SCy Schubert hash, SHA256_MAC_LEN); 81c1d255d3SCy Schubert 82c1d255d3SCy Schubert if (dpp_update_reconfig_id(id) < 0) { 83c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "DPP: Failed to generate E'-id"); 84c1d255d3SCy Schubert goto fail; 85c1d255d3SCy Schubert } 86c1d255d3SCy Schubert 874b72b91aSCy Schubert a_nonce = crypto_ec_key_get_pubkey_point(id->a_nonce, 0); 884b72b91aSCy Schubert e_id = crypto_ec_key_get_pubkey_point(id->e_prime_id, 0); 89c1d255d3SCy Schubert if (!a_nonce || !e_id) 90c1d255d3SCy Schubert goto fail; 91c1d255d3SCy Schubert 92c1d255d3SCy Schubert attr_len = 4 + SHA256_MAC_LEN; 93c1d255d3SCy Schubert attr_len += 4 + 2; 94c1d255d3SCy Schubert attr_len += 4 + wpabuf_len(a_nonce); 95c1d255d3SCy Schubert attr_len += 4 + wpabuf_len(e_id); 96c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_RECONFIG_ANNOUNCEMENT, attr_len); 97c1d255d3SCy Schubert if (!msg) 98c1d255d3SCy Schubert goto fail; 99c1d255d3SCy Schubert 100c1d255d3SCy Schubert /* Configurator C-sign key Hash */ 101c1d255d3SCy Schubert dpp_build_attr_csign_key_hash(msg, hash); 102c1d255d3SCy Schubert 103c1d255d3SCy Schubert /* Finite Cyclic Group attribute */ 104c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Finite Cyclic Group: %u", 105c1d255d3SCy Schubert own_curve->ike_group); 106c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 107c1d255d3SCy Schubert wpabuf_put_le16(msg, 2); 108c1d255d3SCy Schubert wpabuf_put_le16(msg, own_curve->ike_group); 109c1d255d3SCy Schubert 110c1d255d3SCy Schubert /* A-NONCE */ 111c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_A_NONCE); 112c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(a_nonce)); 113c1d255d3SCy Schubert wpabuf_put_buf(msg, a_nonce); 114c1d255d3SCy Schubert 115c1d255d3SCy Schubert /* E'-id */ 116c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_E_PRIME_ID); 117c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(e_id)); 118c1d255d3SCy Schubert wpabuf_put_buf(msg, e_id); 119c1d255d3SCy Schubert 120c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 121c1d255d3SCy Schubert "DPP: Reconfig Announcement frame attributes", msg); 122c1d255d3SCy Schubert fail: 123c1d255d3SCy Schubert wpabuf_free(a_nonce); 124c1d255d3SCy Schubert wpabuf_free(e_id); 1254b72b91aSCy Schubert crypto_ec_key_deinit(own_key); 126c1d255d3SCy Schubert return msg; 127c1d255d3SCy Schubert } 128c1d255d3SCy Schubert 129c1d255d3SCy Schubert 130c1d255d3SCy Schubert static struct wpabuf * dpp_reconfig_build_req(struct dpp_authentication *auth) 131c1d255d3SCy Schubert { 132c1d255d3SCy Schubert struct wpabuf *msg; 133c1d255d3SCy Schubert size_t attr_len; 134*a90b9d01SCy Schubert u8 ver = DPP_VERSION; 135c1d255d3SCy Schubert 136c1d255d3SCy Schubert /* Build DPP Reconfig Authentication Request frame attributes */ 137c1d255d3SCy Schubert attr_len = 4 + 1 + 4 + 1 + 4 + os_strlen(auth->conf->connector) + 138c1d255d3SCy Schubert 4 + auth->curve->nonce_len; 139c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_REQ, attr_len); 140c1d255d3SCy Schubert if (!msg) 141c1d255d3SCy Schubert return NULL; 142c1d255d3SCy Schubert 143c1d255d3SCy Schubert /* Transaction ID */ 144c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 145c1d255d3SCy Schubert wpabuf_put_le16(msg, 1); 146c1d255d3SCy Schubert wpabuf_put_u8(msg, auth->transaction_id); 147c1d255d3SCy Schubert 148*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 149*a90b9d01SCy Schubert if (dpp_test == DPP_TEST_NO_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { 150*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - no Protocol Version"); 151*a90b9d01SCy Schubert goto skip_proto_ver; 152*a90b9d01SCy Schubert } 153*a90b9d01SCy Schubert if (dpp_test == DPP_TEST_INVALID_PROTOCOL_VERSION_RECONFIG_AUTH_REQ) { 154*a90b9d01SCy Schubert wpa_printf(MSG_INFO, "DPP: TESTING - invalid Protocol Version"); 155*a90b9d01SCy Schubert ver = 1; 156*a90b9d01SCy Schubert } 157*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 158*a90b9d01SCy Schubert 159c1d255d3SCy Schubert /* Protocol Version */ 160c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 161c1d255d3SCy Schubert wpabuf_put_le16(msg, 1); 162*a90b9d01SCy Schubert wpabuf_put_u8(msg, ver); 163*a90b9d01SCy Schubert 164*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 165*a90b9d01SCy Schubert skip_proto_ver: 166*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 167c1d255d3SCy Schubert 168c1d255d3SCy Schubert /* DPP Connector */ 169c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 170c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(auth->conf->connector)); 171c1d255d3SCy Schubert wpabuf_put_str(msg, auth->conf->connector); 172c1d255d3SCy Schubert 173c1d255d3SCy Schubert /* C-nonce */ 174c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONFIGURATOR_NONCE); 175c1d255d3SCy Schubert wpabuf_put_le16(msg, auth->curve->nonce_len); 176c1d255d3SCy Schubert wpabuf_put_data(msg, auth->c_nonce, auth->curve->nonce_len); 177c1d255d3SCy Schubert 178c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 179c1d255d3SCy Schubert "DPP: Reconfig Authentication Request frame attributes", 180c1d255d3SCy Schubert msg); 181c1d255d3SCy Schubert 182c1d255d3SCy Schubert return msg; 183c1d255d3SCy Schubert } 184c1d255d3SCy Schubert 185c1d255d3SCy Schubert 186c1d255d3SCy Schubert static int 187c1d255d3SCy Schubert dpp_configurator_build_own_connector(struct dpp_configurator *conf, 188c1d255d3SCy Schubert const struct dpp_curve_params *curve) 189c1d255d3SCy Schubert { 190c1d255d3SCy Schubert struct wpabuf *dppcon = NULL; 191c1d255d3SCy Schubert int ret = -1; 192c1d255d3SCy Schubert 193c1d255d3SCy Schubert if (conf->connector) 194c1d255d3SCy Schubert return 0; /* already generated */ 195c1d255d3SCy Schubert 196c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 197c1d255d3SCy Schubert "DPP: Sign own Configurator Connector for reconfiguration with curve %s", 198c1d255d3SCy Schubert conf->curve->name); 199c1d255d3SCy Schubert conf->connector_key = dpp_gen_keypair(curve); 200c1d255d3SCy Schubert if (!conf->connector_key) 201c1d255d3SCy Schubert goto fail; 202c1d255d3SCy Schubert 203c1d255d3SCy Schubert /* Connector (JSON dppCon object) */ 204c1d255d3SCy Schubert dppcon = wpabuf_alloc(1000 + 2 * curve->prime_len * 4 / 3); 205c1d255d3SCy Schubert if (!dppcon) 206c1d255d3SCy Schubert goto fail; 207c1d255d3SCy Schubert json_start_object(dppcon, NULL); 208c1d255d3SCy Schubert json_start_array(dppcon, "groups"); 209c1d255d3SCy Schubert json_start_object(dppcon, NULL); 210c1d255d3SCy Schubert json_add_string(dppcon, "groupId", "*"); 211c1d255d3SCy Schubert json_value_sep(dppcon); 212c1d255d3SCy Schubert json_add_string(dppcon, "netRole", "configurator"); 213c1d255d3SCy Schubert json_end_object(dppcon); 214c1d255d3SCy Schubert json_end_array(dppcon); 215c1d255d3SCy Schubert json_value_sep(dppcon); 216c1d255d3SCy Schubert if (dpp_build_jwk(dppcon, "netAccessKey", conf->connector_key, NULL, 217c1d255d3SCy Schubert curve) < 0) { 218c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); 219c1d255d3SCy Schubert goto fail; 220c1d255d3SCy Schubert } 221c1d255d3SCy Schubert json_end_object(dppcon); 222c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", 223c1d255d3SCy Schubert (const char *) wpabuf_head(dppcon)); 224c1d255d3SCy Schubert 225c1d255d3SCy Schubert conf->connector = dpp_sign_connector(conf, dppcon); 226c1d255d3SCy Schubert if (!conf->connector) 227c1d255d3SCy Schubert goto fail; 228c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: signedConnector: %s", conf->connector); 229c1d255d3SCy Schubert 230c1d255d3SCy Schubert ret = 0; 231c1d255d3SCy Schubert fail: 232c1d255d3SCy Schubert wpabuf_free(dppcon); 233c1d255d3SCy Schubert return ret; 234c1d255d3SCy Schubert } 235c1d255d3SCy Schubert 236c1d255d3SCy Schubert 237c1d255d3SCy Schubert struct dpp_authentication * 238c1d255d3SCy Schubert dpp_reconfig_init(struct dpp_global *dpp, void *msg_ctx, 239c1d255d3SCy Schubert struct dpp_configurator *conf, unsigned int freq, u16 group, 240c1d255d3SCy Schubert const u8 *a_nonce_attr, size_t a_nonce_len, 241c1d255d3SCy Schubert const u8 *e_id_attr, size_t e_id_len) 242c1d255d3SCy Schubert { 243c1d255d3SCy Schubert struct dpp_authentication *auth; 244c1d255d3SCy Schubert const struct dpp_curve_params *curve; 2454b72b91aSCy Schubert struct crypto_ec_key *a_nonce, *e_prime_id; 2464b72b91aSCy Schubert struct crypto_ec_point *e_id; 247c1d255d3SCy Schubert 248c1d255d3SCy Schubert curve = dpp_get_curve_ike_group(group); 249c1d255d3SCy Schubert if (!curve) { 250c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 251c1d255d3SCy Schubert "DPP: Unsupported group %u - cannot reconfigure", 252c1d255d3SCy Schubert group); 253c1d255d3SCy Schubert return NULL; 254c1d255d3SCy Schubert } 255c1d255d3SCy Schubert 256c1d255d3SCy Schubert if (!a_nonce_attr) { 257c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Missing required A-NONCE attribute"); 258c1d255d3SCy Schubert return NULL; 259c1d255d3SCy Schubert } 260c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: A-NONCE", a_nonce_attr, a_nonce_len); 261c1d255d3SCy Schubert a_nonce = dpp_set_pubkey_point(conf->csign, a_nonce_attr, a_nonce_len); 262c1d255d3SCy Schubert if (!a_nonce) { 263c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Invalid A-NONCE"); 264c1d255d3SCy Schubert return NULL; 265c1d255d3SCy Schubert } 266c1d255d3SCy Schubert dpp_debug_print_key("A-NONCE", a_nonce); 267c1d255d3SCy Schubert 268c1d255d3SCy Schubert if (!e_id_attr) { 269c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Missing required E'-id attribute"); 270c1d255d3SCy Schubert return NULL; 271c1d255d3SCy Schubert } 272c1d255d3SCy Schubert e_prime_id = dpp_set_pubkey_point(conf->csign, e_id_attr, e_id_len); 273c1d255d3SCy Schubert if (!e_prime_id) { 274c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Invalid E'-id"); 2754b72b91aSCy Schubert crypto_ec_key_deinit(a_nonce); 276c1d255d3SCy Schubert return NULL; 277c1d255d3SCy Schubert } 278c1d255d3SCy Schubert dpp_debug_print_key("E'-id", e_prime_id); 279c1d255d3SCy Schubert e_id = dpp_decrypt_e_id(conf->pp_key, a_nonce, e_prime_id); 2804b72b91aSCy Schubert crypto_ec_key_deinit(a_nonce); 2814b72b91aSCy Schubert crypto_ec_key_deinit(e_prime_id); 282c1d255d3SCy Schubert if (!e_id) { 283c1d255d3SCy Schubert wpa_printf(MSG_INFO, "DPP: Could not decrypt E'-id"); 284c1d255d3SCy Schubert return NULL; 285c1d255d3SCy Schubert } 286c1d255d3SCy Schubert /* TODO: could use E-id to determine whether reconfiguration with this 287c1d255d3SCy Schubert * Enrollee has already been started and is waiting for updated 288c1d255d3SCy Schubert * configuration instead of replying again before such configuration 289c1d255d3SCy Schubert * becomes available */ 2904b72b91aSCy Schubert crypto_ec_point_deinit(e_id, 1); 291c1d255d3SCy Schubert 292c1d255d3SCy Schubert auth = dpp_alloc_auth(dpp, msg_ctx); 293c1d255d3SCy Schubert if (!auth) 294c1d255d3SCy Schubert return NULL; 295c1d255d3SCy Schubert 296c1d255d3SCy Schubert auth->conf = conf; 297c1d255d3SCy Schubert auth->reconfig = 1; 298c1d255d3SCy Schubert auth->initiator = 1; 299c1d255d3SCy Schubert auth->waiting_auth_resp = 1; 300c1d255d3SCy Schubert auth->allowed_roles = DPP_CAPAB_CONFIGURATOR; 301c1d255d3SCy Schubert auth->configurator = 1; 302c1d255d3SCy Schubert auth->curve = curve; 303c1d255d3SCy Schubert auth->transaction_id = 1; 304c1d255d3SCy Schubert if (freq && dpp_prepare_channel_list(auth, freq, NULL, 0) < 0) 305c1d255d3SCy Schubert goto fail; 306c1d255d3SCy Schubert 307c1d255d3SCy Schubert if (dpp_configurator_build_own_connector(conf, curve) < 0) 308c1d255d3SCy Schubert goto fail; 309c1d255d3SCy Schubert 310c1d255d3SCy Schubert if (random_get_bytes(auth->c_nonce, auth->curve->nonce_len)) { 311c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "DPP: Failed to generate C-nonce"); 312c1d255d3SCy Schubert goto fail; 313c1d255d3SCy Schubert } 314c1d255d3SCy Schubert 315c1d255d3SCy Schubert auth->reconfig_req_msg = dpp_reconfig_build_req(auth); 316c1d255d3SCy Schubert if (!auth->reconfig_req_msg) 317c1d255d3SCy Schubert goto fail; 318c1d255d3SCy Schubert 319c1d255d3SCy Schubert out: 320c1d255d3SCy Schubert return auth; 321c1d255d3SCy Schubert fail: 322c1d255d3SCy Schubert dpp_auth_deinit(auth); 323c1d255d3SCy Schubert auth = NULL; 324c1d255d3SCy Schubert goto out; 325c1d255d3SCy Schubert } 326c1d255d3SCy Schubert 327c1d255d3SCy Schubert 328c1d255d3SCy Schubert static int dpp_reconfig_build_resp(struct dpp_authentication *auth, 329c1d255d3SCy Schubert const char *own_connector, 330c1d255d3SCy Schubert struct wpabuf *conn_status) 331c1d255d3SCy Schubert { 332c1d255d3SCy Schubert struct wpabuf *msg = NULL, *clear, *pr = NULL; 333c1d255d3SCy Schubert u8 *attr_start, *attr_end; 334c1d255d3SCy Schubert size_t clear_len, attr_len, len[2]; 335c1d255d3SCy Schubert const u8 *addr[2]; 336c1d255d3SCy Schubert u8 *wrapped; 337c1d255d3SCy Schubert int res = -1; 338c1d255d3SCy Schubert 339c1d255d3SCy Schubert /* Build DPP Reconfig Authentication Response frame attributes */ 340c1d255d3SCy Schubert clear_len = 4 + auth->curve->nonce_len + 341c1d255d3SCy Schubert 4 + wpabuf_len(conn_status); 342c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 343c1d255d3SCy Schubert if (!clear) 344c1d255d3SCy Schubert goto fail; 345c1d255d3SCy Schubert 346c1d255d3SCy Schubert /* C-nonce (wrapped) */ 347c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE); 348c1d255d3SCy Schubert wpabuf_put_le16(clear, auth->curve->nonce_len); 349c1d255d3SCy Schubert wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len); 350c1d255d3SCy Schubert 351c1d255d3SCy Schubert /* Connection Status (wrapped) */ 352c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_CONN_STATUS); 353c1d255d3SCy Schubert wpabuf_put_le16(clear, wpabuf_len(conn_status)); 354c1d255d3SCy Schubert wpabuf_put_buf(clear, conn_status); 355c1d255d3SCy Schubert 3564b72b91aSCy Schubert pr = crypto_ec_key_get_pubkey_point(auth->own_protocol_key, 0); 357c1d255d3SCy Schubert if (!pr) 358c1d255d3SCy Schubert goto fail; 359c1d255d3SCy Schubert 360c1d255d3SCy Schubert attr_len = 4 + 1 + 4 + 1 + 361c1d255d3SCy Schubert 4 + os_strlen(own_connector) + 362c1d255d3SCy Schubert 4 + auth->curve->nonce_len + 363c1d255d3SCy Schubert 4 + wpabuf_len(pr) + 364c1d255d3SCy Schubert 4 + wpabuf_len(clear) + AES_BLOCK_SIZE; 365c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_RESP, attr_len); 366c1d255d3SCy Schubert if (!msg) 367c1d255d3SCy Schubert goto fail; 368c1d255d3SCy Schubert 369c1d255d3SCy Schubert attr_start = wpabuf_put(msg, 0); 370c1d255d3SCy Schubert 371c1d255d3SCy Schubert /* Transaction ID */ 372c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); 373c1d255d3SCy Schubert wpabuf_put_le16(msg, 1); 374c1d255d3SCy Schubert wpabuf_put_u8(msg, auth->transaction_id); 375c1d255d3SCy Schubert 376c1d255d3SCy Schubert /* Protocol Version */ 377c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); 378c1d255d3SCy Schubert wpabuf_put_le16(msg, 1); 379c1d255d3SCy Schubert wpabuf_put_u8(msg, DPP_VERSION); 380c1d255d3SCy Schubert 381c1d255d3SCy Schubert /* R-Connector */ 382c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); 383c1d255d3SCy Schubert wpabuf_put_le16(msg, os_strlen(own_connector)); 384c1d255d3SCy Schubert wpabuf_put_str(msg, own_connector); 385c1d255d3SCy Schubert 386c1d255d3SCy Schubert /* E-nonce */ 387c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_ENROLLEE_NONCE); 388c1d255d3SCy Schubert wpabuf_put_le16(msg, auth->curve->nonce_len); 389c1d255d3SCy Schubert wpabuf_put_data(msg, auth->e_nonce, auth->curve->nonce_len); 390c1d255d3SCy Schubert 391c1d255d3SCy Schubert /* Responder Protocol Key (Pr) */ 392c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY); 393c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(pr)); 394c1d255d3SCy Schubert wpabuf_put_buf(msg, pr); 395c1d255d3SCy Schubert 396c1d255d3SCy Schubert attr_end = wpabuf_put(msg, 0); 397c1d255d3SCy Schubert 398c1d255d3SCy Schubert /* OUI, OUI type, Crypto Suite, DPP frame type */ 399c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 400c1d255d3SCy Schubert len[0] = 3 + 1 + 1 + 1; 401c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 402c1d255d3SCy Schubert 403c1d255d3SCy Schubert /* Attributes before Wrapped Data */ 404c1d255d3SCy Schubert addr[1] = attr_start; 405c1d255d3SCy Schubert len[1] = attr_end - attr_start; 406c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 407c1d255d3SCy Schubert 408c1d255d3SCy Schubert /* Wrapped Data: {C-nonce, E-nonce, Connection Status}ke */ 409c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 410c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 411c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 412c1d255d3SCy Schubert 413c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 414c1d255d3SCy Schubert if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 415c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 416c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 417c1d255d3SCy Schubert goto fail; 418c1d255d3SCy Schubert 419c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 420c1d255d3SCy Schubert "DPP: Reconfig Authentication Response frame attributes", 421c1d255d3SCy Schubert msg); 422c1d255d3SCy Schubert 423c1d255d3SCy Schubert wpabuf_free(auth->reconfig_resp_msg); 424c1d255d3SCy Schubert auth->reconfig_resp_msg = msg; 425c1d255d3SCy Schubert 426c1d255d3SCy Schubert res = 0; 427c1d255d3SCy Schubert out: 428c1d255d3SCy Schubert wpabuf_free(clear); 429c1d255d3SCy Schubert wpabuf_free(pr); 430c1d255d3SCy Schubert return res; 431c1d255d3SCy Schubert fail: 432c1d255d3SCy Schubert wpabuf_free(msg); 433c1d255d3SCy Schubert goto out; 434c1d255d3SCy Schubert } 435c1d255d3SCy Schubert 436c1d255d3SCy Schubert 437c1d255d3SCy Schubert struct dpp_authentication * 438c1d255d3SCy Schubert dpp_reconfig_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, 439c1d255d3SCy Schubert const char *own_connector, 440c1d255d3SCy Schubert const u8 *net_access_key, size_t net_access_key_len, 441c1d255d3SCy Schubert const u8 *csign_key, size_t csign_key_len, 442c1d255d3SCy Schubert unsigned int freq, const u8 *hdr, 443c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len) 444c1d255d3SCy Schubert { 445c1d255d3SCy Schubert struct dpp_authentication *auth = NULL; 446c1d255d3SCy Schubert const u8 *trans_id, *version, *i_connector, *c_nonce; 447c1d255d3SCy Schubert u16 trans_id_len, version_len, i_connector_len, c_nonce_len; 448c1d255d3SCy Schubert struct dpp_signed_connector_info info; 449c1d255d3SCy Schubert enum dpp_status_error res; 450c1d255d3SCy Schubert struct json_token *root = NULL, *own_root = NULL, *token; 451c1d255d3SCy Schubert unsigned char *own_conn = NULL; 452c1d255d3SCy Schubert struct wpabuf *conn_status = NULL; 453c1d255d3SCy Schubert 454c1d255d3SCy Schubert os_memset(&info, 0, sizeof(info)); 455c1d255d3SCy Schubert 456c1d255d3SCy Schubert trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID, 457c1d255d3SCy Schubert &trans_id_len); 458c1d255d3SCy Schubert if (!trans_id || trans_id_len != 1) { 459c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 460c1d255d3SCy Schubert "DPP: Peer did not include Transaction ID"); 461c1d255d3SCy Schubert goto fail; 462c1d255d3SCy Schubert } 463c1d255d3SCy Schubert 464c1d255d3SCy Schubert version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 465c1d255d3SCy Schubert &version_len); 466c1d255d3SCy Schubert if (!version || version_len < 1 || version[0] < 2) { 467c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 468c1d255d3SCy Schubert "DPP: Missing or invalid Protocol Version attribute"); 469c1d255d3SCy Schubert goto fail; 470c1d255d3SCy Schubert } 471c1d255d3SCy Schubert 472c1d255d3SCy Schubert i_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR, 473c1d255d3SCy Schubert &i_connector_len); 474c1d255d3SCy Schubert if (!i_connector) { 475c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Missing I-Connector attribute"); 476c1d255d3SCy Schubert goto fail; 477c1d255d3SCy Schubert } 478c1d255d3SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "DPP: I-Connector", 479c1d255d3SCy Schubert i_connector, i_connector_len); 480c1d255d3SCy Schubert 481c1d255d3SCy Schubert c_nonce = dpp_get_attr(attr_start, attr_len, 482c1d255d3SCy Schubert DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 483c1d255d3SCy Schubert if (!c_nonce || c_nonce_len > DPP_MAX_NONCE_LEN) { 484c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 485c1d255d3SCy Schubert "DPP: Missing or invalid C-nonce attribute"); 486c1d255d3SCy Schubert goto fail; 487c1d255d3SCy Schubert } 488c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 489c1d255d3SCy Schubert 490c1d255d3SCy Schubert res = dpp_check_signed_connector(&info, csign_key, csign_key_len, 491c1d255d3SCy Schubert i_connector, i_connector_len); 492c1d255d3SCy Schubert if (res != DPP_STATUS_OK) { 493c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Invalid I-Connector"); 494c1d255d3SCy Schubert goto fail; 495c1d255d3SCy Schubert } 496c1d255d3SCy Schubert 497c1d255d3SCy Schubert root = json_parse((const char *) info.payload, info.payload_len); 498c1d255d3SCy Schubert own_root = dpp_parse_own_connector(own_connector); 499c1d255d3SCy Schubert if (!root || !own_root || 500c1d255d3SCy Schubert !dpp_connector_match_groups(own_root, root, true)) { 501c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 502c1d255d3SCy Schubert "DPP: I-Connector does not include compatible group netrole with own connector"); 503c1d255d3SCy Schubert goto fail; 504c1d255d3SCy Schubert } 505c1d255d3SCy Schubert 506c1d255d3SCy Schubert token = json_get_member(root, "expiry"); 507c1d255d3SCy Schubert if (token && token->type == JSON_STRING && 508c1d255d3SCy Schubert dpp_key_expired(token->string, NULL)) { 509c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 510c1d255d3SCy Schubert "DPP: I-Connector (netAccessKey) has expired"); 511c1d255d3SCy Schubert goto fail; 512c1d255d3SCy Schubert } 513c1d255d3SCy Schubert 514c1d255d3SCy Schubert token = json_get_member(root, "netAccessKey"); 515c1d255d3SCy Schubert if (!token || token->type != JSON_OBJECT) { 516c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 517c1d255d3SCy Schubert goto fail; 518c1d255d3SCy Schubert } 519c1d255d3SCy Schubert 520c1d255d3SCy Schubert auth = dpp_alloc_auth(dpp, msg_ctx); 521c1d255d3SCy Schubert if (!auth) 522c1d255d3SCy Schubert return NULL; 523c1d255d3SCy Schubert 524c1d255d3SCy Schubert auth->reconfig = 1; 525c1d255d3SCy Schubert auth->allowed_roles = DPP_CAPAB_ENROLLEE; 526c1d255d3SCy Schubert if (dpp_prepare_channel_list(auth, freq, NULL, 0) < 0) 527c1d255d3SCy Schubert goto fail; 528c1d255d3SCy Schubert 529c1d255d3SCy Schubert auth->transaction_id = trans_id[0]; 530c1d255d3SCy Schubert 531c1d255d3SCy Schubert auth->peer_version = version[0]; 532c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 533c1d255d3SCy Schubert auth->peer_version); 534c1d255d3SCy Schubert 535c1d255d3SCy Schubert os_memcpy(auth->c_nonce, c_nonce, c_nonce_len); 536c1d255d3SCy Schubert 537c1d255d3SCy Schubert if (dpp_reconfig_derive_ke_responder(auth, net_access_key, 538c1d255d3SCy Schubert net_access_key_len, token) < 0) 539c1d255d3SCy Schubert goto fail; 540c1d255d3SCy Schubert 541c1d255d3SCy Schubert if (c_nonce_len != auth->curve->nonce_len) { 542c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 543c1d255d3SCy Schubert "DPP: Unexpected C-nonce length %u (curve nonce len %zu)", 544c1d255d3SCy Schubert c_nonce_len, auth->curve->nonce_len); 545c1d255d3SCy Schubert goto fail; 546c1d255d3SCy Schubert } 547c1d255d3SCy Schubert 548c1d255d3SCy Schubert /* Build Connection Status object */ 549c1d255d3SCy Schubert /* TODO: Get appropriate result value */ 550c1d255d3SCy Schubert /* TODO: ssid64 and channelList */ 551c1d255d3SCy Schubert conn_status = dpp_build_conn_status(DPP_STATUS_NO_AP, NULL, 0, NULL); 552c1d255d3SCy Schubert if (!conn_status) 553c1d255d3SCy Schubert goto fail; 554c1d255d3SCy Schubert 555c1d255d3SCy Schubert if (dpp_reconfig_build_resp(auth, own_connector, conn_status) < 0) 556c1d255d3SCy Schubert goto fail; 557c1d255d3SCy Schubert 558c1d255d3SCy Schubert out: 559c1d255d3SCy Schubert os_free(info.payload); 560c1d255d3SCy Schubert os_free(own_conn); 561c1d255d3SCy Schubert json_free(root); 562c1d255d3SCy Schubert json_free(own_root); 563c1d255d3SCy Schubert wpabuf_free(conn_status); 564c1d255d3SCy Schubert return auth; 565c1d255d3SCy Schubert fail: 566c1d255d3SCy Schubert dpp_auth_deinit(auth); 567c1d255d3SCy Schubert auth = NULL; 568c1d255d3SCy Schubert goto out; 569c1d255d3SCy Schubert } 570c1d255d3SCy Schubert 571c1d255d3SCy Schubert 572c1d255d3SCy Schubert struct wpabuf * 573c1d255d3SCy Schubert dpp_reconfig_build_conf(struct dpp_authentication *auth) 574c1d255d3SCy Schubert { 575c1d255d3SCy Schubert struct wpabuf *msg = NULL, *clear; 576c1d255d3SCy Schubert u8 *attr_start, *attr_end; 577c1d255d3SCy Schubert size_t clear_len, attr_len, len[2]; 578c1d255d3SCy Schubert const u8 *addr[2]; 579c1d255d3SCy Schubert u8 *wrapped; 580c1d255d3SCy Schubert u8 flags; 581c1d255d3SCy Schubert 582c1d255d3SCy Schubert /* Build DPP Reconfig Authentication Confirm frame attributes */ 583c1d255d3SCy Schubert clear_len = 4 + 1 + 4 + 1 + 2 * (4 + auth->curve->nonce_len) + 584c1d255d3SCy Schubert 4 + 1; 585c1d255d3SCy Schubert clear = wpabuf_alloc(clear_len); 586c1d255d3SCy Schubert if (!clear) 587c1d255d3SCy Schubert goto fail; 588c1d255d3SCy Schubert 589c1d255d3SCy Schubert /* Transaction ID */ 590c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_TRANSACTION_ID); 591c1d255d3SCy Schubert wpabuf_put_le16(clear, 1); 592c1d255d3SCy Schubert wpabuf_put_u8(clear, auth->transaction_id); 593c1d255d3SCy Schubert 594c1d255d3SCy Schubert /* Protocol Version */ 595c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_PROTOCOL_VERSION); 596c1d255d3SCy Schubert wpabuf_put_le16(clear, 1); 597c1d255d3SCy Schubert wpabuf_put_u8(clear, auth->peer_version); 598c1d255d3SCy Schubert 599c1d255d3SCy Schubert /* C-nonce (wrapped) */ 600c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_CONFIGURATOR_NONCE); 601c1d255d3SCy Schubert wpabuf_put_le16(clear, auth->curve->nonce_len); 602c1d255d3SCy Schubert wpabuf_put_data(clear, auth->c_nonce, auth->curve->nonce_len); 603c1d255d3SCy Schubert 604c1d255d3SCy Schubert /* E-nonce (wrapped) */ 605c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 606c1d255d3SCy Schubert wpabuf_put_le16(clear, auth->curve->nonce_len); 607c1d255d3SCy Schubert wpabuf_put_data(clear, auth->e_nonce, auth->curve->nonce_len); 608c1d255d3SCy Schubert 609c1d255d3SCy Schubert /* Reconfig-Flags (wrapped) */ 610c1d255d3SCy Schubert flags = DPP_CONFIG_REPLACEKEY; 611c1d255d3SCy Schubert wpabuf_put_le16(clear, DPP_ATTR_RECONFIG_FLAGS); 612c1d255d3SCy Schubert wpabuf_put_le16(clear, 1); 613c1d255d3SCy Schubert wpabuf_put_u8(clear, flags); 614c1d255d3SCy Schubert 615c1d255d3SCy Schubert attr_len = 4 + wpabuf_len(clear) + AES_BLOCK_SIZE; 616c1d255d3SCy Schubert attr_len += 4 + 1; 617c1d255d3SCy Schubert msg = dpp_alloc_msg(DPP_PA_RECONFIG_AUTH_CONF, attr_len); 618c1d255d3SCy Schubert if (!msg) 619c1d255d3SCy Schubert goto fail; 620c1d255d3SCy Schubert 621c1d255d3SCy Schubert attr_start = wpabuf_put(msg, 0); 622c1d255d3SCy Schubert 623c1d255d3SCy Schubert /* DPP Status */ 624c1d255d3SCy Schubert dpp_build_attr_status(msg, DPP_STATUS_OK); 625c1d255d3SCy Schubert 626c1d255d3SCy Schubert attr_end = wpabuf_put(msg, 0); 627c1d255d3SCy Schubert 628c1d255d3SCy Schubert /* OUI, OUI type, Crypto Suite, DPP frame type */ 629c1d255d3SCy Schubert addr[0] = wpabuf_head_u8(msg) + 2; 630c1d255d3SCy Schubert len[0] = 3 + 1 + 1 + 1; 631c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 632c1d255d3SCy Schubert 633c1d255d3SCy Schubert /* Attributes before Wrapped Data */ 634c1d255d3SCy Schubert addr[1] = attr_start; 635c1d255d3SCy Schubert len[1] = attr_end - attr_start; 636c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 637c1d255d3SCy Schubert 638c1d255d3SCy Schubert /* Wrapped Data */ 639c1d255d3SCy Schubert wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 640c1d255d3SCy Schubert wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 641c1d255d3SCy Schubert wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 642c1d255d3SCy Schubert 643c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 644c1d255d3SCy Schubert if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 645c1d255d3SCy Schubert wpabuf_head(clear), wpabuf_len(clear), 646c1d255d3SCy Schubert 2, addr, len, wrapped) < 0) 647c1d255d3SCy Schubert goto fail; 648c1d255d3SCy Schubert 649c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, 650c1d255d3SCy Schubert "DPP: Reconfig Authentication Confirm frame attributes", 651c1d255d3SCy Schubert msg); 652c1d255d3SCy Schubert 653c1d255d3SCy Schubert out: 654c1d255d3SCy Schubert wpabuf_free(clear); 655c1d255d3SCy Schubert return msg; 656c1d255d3SCy Schubert fail: 657c1d255d3SCy Schubert wpabuf_free(msg); 658c1d255d3SCy Schubert msg = NULL; 659c1d255d3SCy Schubert goto out; 660c1d255d3SCy Schubert } 661c1d255d3SCy Schubert 662c1d255d3SCy Schubert 663c1d255d3SCy Schubert struct wpabuf * 664c1d255d3SCy Schubert dpp_reconfig_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, 665c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len) 666c1d255d3SCy Schubert { 667c1d255d3SCy Schubert const u8 *trans_id, *version, *r_connector, *r_proto, *wrapped_data, 668c1d255d3SCy Schubert *c_nonce, *e_nonce, *conn_status; 669c1d255d3SCy Schubert u16 trans_id_len, version_len, r_connector_len, r_proto_len, 670c1d255d3SCy Schubert wrapped_data_len, c_nonce_len, e_nonce_len, conn_status_len; 671c1d255d3SCy Schubert struct wpabuf *conf = NULL; 672c1d255d3SCy Schubert char *signed_connector = NULL; 673c1d255d3SCy Schubert struct dpp_signed_connector_info info; 674c1d255d3SCy Schubert enum dpp_status_error res; 675c1d255d3SCy Schubert struct json_token *root = NULL, *token, *conn_status_json = NULL; 676c1d255d3SCy Schubert const u8 *addr[2]; 677c1d255d3SCy Schubert size_t len[2]; 678c1d255d3SCy Schubert u8 *unwrapped = NULL; 679c1d255d3SCy Schubert size_t unwrapped_len = 0; 680c1d255d3SCy Schubert 681c1d255d3SCy Schubert os_memset(&info, 0, sizeof(info)); 682c1d255d3SCy Schubert 683c1d255d3SCy Schubert if (!auth->reconfig || !auth->configurator) 684c1d255d3SCy Schubert goto fail; 685c1d255d3SCy Schubert 686c1d255d3SCy Schubert wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 687c1d255d3SCy Schubert &wrapped_data_len); 688c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 689c1d255d3SCy Schubert dpp_auth_fail(auth, 690c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 691c1d255d3SCy Schubert goto fail; 692c1d255d3SCy Schubert } 693c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data", 694c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 695c1d255d3SCy Schubert attr_len = wrapped_data - 4 - attr_start; 696c1d255d3SCy Schubert 697c1d255d3SCy Schubert trans_id = dpp_get_attr(attr_start, attr_len, DPP_ATTR_TRANSACTION_ID, 698c1d255d3SCy Schubert &trans_id_len); 699c1d255d3SCy Schubert if (!trans_id || trans_id_len != 1) { 700c1d255d3SCy Schubert dpp_auth_fail(auth, "Peer did not include Transaction ID"); 701c1d255d3SCy Schubert goto fail; 702c1d255d3SCy Schubert } 703c1d255d3SCy Schubert if (trans_id[0] != auth->transaction_id) { 704c1d255d3SCy Schubert dpp_auth_fail(auth, "Transaction ID mismatch"); 705c1d255d3SCy Schubert goto fail; 706c1d255d3SCy Schubert } 707c1d255d3SCy Schubert 708c1d255d3SCy Schubert version = dpp_get_attr(attr_start, attr_len, DPP_ATTR_PROTOCOL_VERSION, 709c1d255d3SCy Schubert &version_len); 710c1d255d3SCy Schubert if (!version || version_len < 1 || version[0] < 2) { 711c1d255d3SCy Schubert dpp_auth_fail(auth, 712c1d255d3SCy Schubert "Missing or invalid Protocol Version attribute"); 713c1d255d3SCy Schubert goto fail; 714c1d255d3SCy Schubert } 715c1d255d3SCy Schubert auth->peer_version = version[0]; 716c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Peer protocol version %u", 717c1d255d3SCy Schubert auth->peer_version); 718c1d255d3SCy Schubert 719c1d255d3SCy Schubert r_connector = dpp_get_attr(attr_start, attr_len, DPP_ATTR_CONNECTOR, 720c1d255d3SCy Schubert &r_connector_len); 721c1d255d3SCy Schubert if (!r_connector) { 722c1d255d3SCy Schubert dpp_auth_fail(auth, " Missing R-Connector attribute"); 723c1d255d3SCy Schubert goto fail; 724c1d255d3SCy Schubert } 725c1d255d3SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "DPP: R-Connector", 726c1d255d3SCy Schubert r_connector, r_connector_len); 727c1d255d3SCy Schubert 728c1d255d3SCy Schubert e_nonce = dpp_get_attr(attr_start, attr_len, 729c1d255d3SCy Schubert DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len); 730c1d255d3SCy Schubert if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 731c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid E-nonce"); 732c1d255d3SCy Schubert goto fail; 733c1d255d3SCy Schubert } 734c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len); 735c1d255d3SCy Schubert os_memcpy(auth->e_nonce, e_nonce, e_nonce_len); 736c1d255d3SCy Schubert 737c1d255d3SCy Schubert r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY, 738c1d255d3SCy Schubert &r_proto_len); 739c1d255d3SCy Schubert if (!r_proto) { 740c1d255d3SCy Schubert dpp_auth_fail(auth, 741c1d255d3SCy Schubert "Missing required Responder Protocol Key attribute"); 742c1d255d3SCy Schubert goto fail; 743c1d255d3SCy Schubert } 744c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key", 745c1d255d3SCy Schubert r_proto, r_proto_len); 746c1d255d3SCy Schubert 747c1d255d3SCy Schubert signed_connector = os_malloc(r_connector_len + 1); 748c1d255d3SCy Schubert if (!signed_connector) 749c1d255d3SCy Schubert goto fail; 750c1d255d3SCy Schubert os_memcpy(signed_connector, r_connector, r_connector_len); 751c1d255d3SCy Schubert signed_connector[r_connector_len] = '\0'; 752c1d255d3SCy Schubert 753c1d255d3SCy Schubert res = dpp_process_signed_connector(&info, auth->conf->csign, 754c1d255d3SCy Schubert signed_connector); 755c1d255d3SCy Schubert if (res != DPP_STATUS_OK) { 756c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid R-Connector"); 757c1d255d3SCy Schubert goto fail; 758c1d255d3SCy Schubert } 759c1d255d3SCy Schubert 760c1d255d3SCy Schubert root = json_parse((const char *) info.payload, info.payload_len); 761c1d255d3SCy Schubert if (!root) { 762c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid Connector payload"); 763c1d255d3SCy Schubert goto fail; 764c1d255d3SCy Schubert } 765c1d255d3SCy Schubert 766c1d255d3SCy Schubert /* Do not check netAccessKey expiration for reconfiguration to allow 767c1d255d3SCy Schubert * expired Connector to be updated. */ 768c1d255d3SCy Schubert 769c1d255d3SCy Schubert token = json_get_member(root, "netAccessKey"); 770c1d255d3SCy Schubert if (!token || token->type != JSON_OBJECT) { 771c1d255d3SCy Schubert dpp_auth_fail(auth, "No netAccessKey object found"); 772c1d255d3SCy Schubert goto fail; 773c1d255d3SCy Schubert } 774c1d255d3SCy Schubert 775c1d255d3SCy Schubert if (dpp_reconfig_derive_ke_initiator(auth, r_proto, r_proto_len, 776c1d255d3SCy Schubert token) < 0) 777c1d255d3SCy Schubert goto fail; 778c1d255d3SCy Schubert 779c1d255d3SCy Schubert addr[0] = hdr; 780c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 781c1d255d3SCy Schubert addr[1] = attr_start; 782c1d255d3SCy Schubert len[1] = attr_len; 783c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 784c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 785c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 786c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 787c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 788c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 789c1d255d3SCy Schubert if (!unwrapped) 790c1d255d3SCy Schubert goto fail; 791c1d255d3SCy Schubert if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 792c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 793c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 794c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed"); 795c1d255d3SCy Schubert goto fail; 796c1d255d3SCy Schubert } 797c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 798c1d255d3SCy Schubert unwrapped, unwrapped_len); 799c1d255d3SCy Schubert 800c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 801c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 802c1d255d3SCy Schubert goto fail; 803c1d255d3SCy Schubert } 804c1d255d3SCy Schubert 805c1d255d3SCy Schubert c_nonce = dpp_get_attr(unwrapped, unwrapped_len, 806c1d255d3SCy Schubert DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 807c1d255d3SCy Schubert if (!c_nonce || c_nonce_len != auth->curve->nonce_len || 808c1d255d3SCy Schubert os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) { 809c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid C-nonce"); 810c1d255d3SCy Schubert goto fail; 811c1d255d3SCy Schubert } 812c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 813c1d255d3SCy Schubert 814c1d255d3SCy Schubert conn_status = dpp_get_attr(unwrapped, unwrapped_len, 815c1d255d3SCy Schubert DPP_ATTR_CONN_STATUS, &conn_status_len); 816c1d255d3SCy Schubert if (!conn_status) { 817c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing Connection Status attribute"); 818c1d255d3SCy Schubert goto fail; 819c1d255d3SCy Schubert } 820c1d255d3SCy Schubert wpa_hexdump_ascii(MSG_DEBUG, "DPP: connStatus", 821c1d255d3SCy Schubert conn_status, conn_status_len); 822c1d255d3SCy Schubert 823c1d255d3SCy Schubert conn_status_json = json_parse((const char *) conn_status, 824c1d255d3SCy Schubert conn_status_len); 825c1d255d3SCy Schubert if (!conn_status_json) { 826c1d255d3SCy Schubert dpp_auth_fail(auth, "Could not parse connStatus"); 827c1d255d3SCy Schubert goto fail; 828c1d255d3SCy Schubert } 829c1d255d3SCy Schubert /* TODO: use connStatus information */ 830c1d255d3SCy Schubert 831c1d255d3SCy Schubert conf = dpp_reconfig_build_conf(auth); 832c1d255d3SCy Schubert if (conf) 833c1d255d3SCy Schubert auth->reconfig_success = true; 834c1d255d3SCy Schubert 835c1d255d3SCy Schubert out: 836c1d255d3SCy Schubert json_free(root); 837c1d255d3SCy Schubert json_free(conn_status_json); 838c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len); 839c1d255d3SCy Schubert os_free(info.payload); 840c1d255d3SCy Schubert os_free(signed_connector); 841c1d255d3SCy Schubert return conf; 842c1d255d3SCy Schubert fail: 843c1d255d3SCy Schubert wpabuf_free(conf); 844c1d255d3SCy Schubert conf = NULL; 845c1d255d3SCy Schubert goto out; 846c1d255d3SCy Schubert } 847c1d255d3SCy Schubert 848c1d255d3SCy Schubert 849c1d255d3SCy Schubert int dpp_reconfig_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, 850c1d255d3SCy Schubert const u8 *attr_start, size_t attr_len) 851c1d255d3SCy Schubert { 852c1d255d3SCy Schubert const u8 *trans_id, *version, *wrapped_data, *c_nonce, *e_nonce, 853c1d255d3SCy Schubert *reconfig_flags, *status; 854c1d255d3SCy Schubert u16 trans_id_len, version_len, wrapped_data_len, c_nonce_len, 855c1d255d3SCy Schubert e_nonce_len, reconfig_flags_len, status_len; 856c1d255d3SCy Schubert const u8 *addr[2]; 857c1d255d3SCy Schubert size_t len[2]; 858c1d255d3SCy Schubert u8 *unwrapped = NULL; 859c1d255d3SCy Schubert size_t unwrapped_len = 0; 860c1d255d3SCy Schubert int res = -1; 861c1d255d3SCy Schubert u8 flags; 862c1d255d3SCy Schubert 863c1d255d3SCy Schubert if (!auth->reconfig || auth->configurator) 864c1d255d3SCy Schubert goto fail; 865c1d255d3SCy Schubert 866c1d255d3SCy Schubert wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 867c1d255d3SCy Schubert &wrapped_data_len); 868c1d255d3SCy Schubert if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 869c1d255d3SCy Schubert dpp_auth_fail(auth, 870c1d255d3SCy Schubert "Missing or invalid required Wrapped Data attribute"); 871c1d255d3SCy Schubert goto fail; 872c1d255d3SCy Schubert } 873c1d255d3SCy Schubert wpa_hexdump(MSG_MSGDUMP, "DPP: Wrapped Data", 874c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 875c1d255d3SCy Schubert attr_len = wrapped_data - 4 - attr_start; 876c1d255d3SCy Schubert 877c1d255d3SCy Schubert status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 878c1d255d3SCy Schubert &status_len); 879c1d255d3SCy Schubert if (!status || status_len < 1) { 880c1d255d3SCy Schubert dpp_auth_fail(auth, 881c1d255d3SCy Schubert "Missing or invalid required DPP Status attribute"); 882c1d255d3SCy Schubert goto fail; 883c1d255d3SCy Schubert } 884c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 885c1d255d3SCy Schubert if (status[0] != DPP_STATUS_OK) { 886c1d255d3SCy Schubert dpp_auth_fail(auth, 887c1d255d3SCy Schubert "Reconfiguration did not complete successfully"); 888c1d255d3SCy Schubert goto fail; 889c1d255d3SCy Schubert } 890c1d255d3SCy Schubert 891c1d255d3SCy Schubert addr[0] = hdr; 892c1d255d3SCy Schubert len[0] = DPP_HDR_LEN; 893c1d255d3SCy Schubert addr[1] = attr_start; 894c1d255d3SCy Schubert len[1] = attr_len; 895c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 896c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 897c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 898c1d255d3SCy Schubert wrapped_data, wrapped_data_len); 899c1d255d3SCy Schubert unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 900c1d255d3SCy Schubert unwrapped = os_malloc(unwrapped_len); 901c1d255d3SCy Schubert if (!unwrapped) 902c1d255d3SCy Schubert goto fail; 903c1d255d3SCy Schubert if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 904c1d255d3SCy Schubert wrapped_data, wrapped_data_len, 905c1d255d3SCy Schubert 2, addr, len, unwrapped) < 0) { 906c1d255d3SCy Schubert dpp_auth_fail(auth, "AES-SIV decryption failed"); 907c1d255d3SCy Schubert goto fail; 908c1d255d3SCy Schubert } 909c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 910c1d255d3SCy Schubert unwrapped, unwrapped_len); 911c1d255d3SCy Schubert 912c1d255d3SCy Schubert if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 913c1d255d3SCy Schubert dpp_auth_fail(auth, "Invalid attribute in unwrapped data"); 914c1d255d3SCy Schubert goto fail; 915c1d255d3SCy Schubert } 916c1d255d3SCy Schubert 917c1d255d3SCy Schubert trans_id = dpp_get_attr(unwrapped, unwrapped_len, 918c1d255d3SCy Schubert DPP_ATTR_TRANSACTION_ID, &trans_id_len); 919c1d255d3SCy Schubert if (!trans_id || trans_id_len != 1 || 920c1d255d3SCy Schubert trans_id[0] != auth->transaction_id) { 921c1d255d3SCy Schubert dpp_auth_fail(auth, 922c1d255d3SCy Schubert "Peer did not include valid Transaction ID"); 923c1d255d3SCy Schubert goto fail; 924c1d255d3SCy Schubert } 925c1d255d3SCy Schubert 926c1d255d3SCy Schubert version = dpp_get_attr(unwrapped, unwrapped_len, 927c1d255d3SCy Schubert DPP_ATTR_PROTOCOL_VERSION, &version_len); 928c1d255d3SCy Schubert if (!version || version_len < 1 || version[0] != DPP_VERSION) { 929c1d255d3SCy Schubert dpp_auth_fail(auth, 930c1d255d3SCy Schubert "Missing or invalid Protocol Version attribute"); 931c1d255d3SCy Schubert goto fail; 932c1d255d3SCy Schubert } 933c1d255d3SCy Schubert 934c1d255d3SCy Schubert c_nonce = dpp_get_attr(unwrapped, unwrapped_len, 935c1d255d3SCy Schubert DPP_ATTR_CONFIGURATOR_NONCE, &c_nonce_len); 936c1d255d3SCy Schubert if (!c_nonce || c_nonce_len != auth->curve->nonce_len || 937c1d255d3SCy Schubert os_memcmp(c_nonce, auth->c_nonce, c_nonce_len) != 0) { 938c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid C-nonce"); 939c1d255d3SCy Schubert goto fail; 940c1d255d3SCy Schubert } 941c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: C-nonce", c_nonce, c_nonce_len); 942c1d255d3SCy Schubert 943c1d255d3SCy Schubert e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 944c1d255d3SCy Schubert DPP_ATTR_ENROLLEE_NONCE, &e_nonce_len); 945c1d255d3SCy Schubert if (!e_nonce || e_nonce_len != auth->curve->nonce_len || 946c1d255d3SCy Schubert os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 947c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid E-nonce"); 948c1d255d3SCy Schubert goto fail; 949c1d255d3SCy Schubert } 950c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", e_nonce, e_nonce_len); 951c1d255d3SCy Schubert 952c1d255d3SCy Schubert reconfig_flags = dpp_get_attr(unwrapped, unwrapped_len, 953c1d255d3SCy Schubert DPP_ATTR_RECONFIG_FLAGS, 954c1d255d3SCy Schubert &reconfig_flags_len); 955c1d255d3SCy Schubert if (!reconfig_flags || reconfig_flags_len < 1) { 956c1d255d3SCy Schubert dpp_auth_fail(auth, "Missing or invalid Reconfig-Flags"); 957c1d255d3SCy Schubert goto fail; 958c1d255d3SCy Schubert } 959c1d255d3SCy Schubert flags = reconfig_flags[0] & BIT(0); 960c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "DPP: Reconfig Flags connectorKey=%u", flags); 961c1d255d3SCy Schubert auth->reconfig_connector_key = flags; 962c1d255d3SCy Schubert 963c1d255d3SCy Schubert auth->reconfig_success = true; 964c1d255d3SCy Schubert res = 0; 965c1d255d3SCy Schubert fail: 966c1d255d3SCy Schubert bin_clear_free(unwrapped, unwrapped_len); 967c1d255d3SCy Schubert return res; 968c1d255d3SCy Schubert } 969c1d255d3SCy Schubert 970c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */ 971