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