DPP2: Configuration Result message generation and processing

Use this new message from Enrollee to Configurator to indicate result of
the config object provisioning if both devices support protocol version
2 or newer.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2019-03-14 17:05:02 +02:00 committed by Jouni Malinen
parent 8b6c834ff9
commit 22f90b32f1
4 changed files with 456 additions and 30 deletions

View File

@ -354,6 +354,16 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst,
return; return;
} }
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
wpa_printf(MSG_DEBUG,
"DPP: Complete exchange on configuration result");
dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL;
return;
}
#endif /* CONFIG_DPP2 */
if (hapd->dpp_auth->remove_on_tx_status) { if (hapd->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"DPP: Terminate authentication exchange due to an earlier error"); "DPP: Terminate authentication exchange due to an earlier error");
@ -1072,6 +1082,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
struct hostapd_data *hapd = ctx; struct hostapd_data *hapd = ctx;
const u8 *pos; const u8 *pos;
struct dpp_authentication *auth = hapd->dpp_auth; struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
if (!auth || !auth->auth_success) { if (!auth || !auth->auth_success) {
wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress"); wpa_printf(MSG_DEBUG, "DPP: No matching exchange in progress");
@ -1107,12 +1118,35 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
} }
hostapd_dpp_handle_config_obj(hapd, auth); hostapd_dpp_handle_config_obj(hapd, auth);
dpp_auth_deinit(hapd->dpp_auth); status = DPP_STATUS_OK;
hapd->dpp_auth = NULL;
return;
fail: fail:
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED); if (status != DPP_STATUS_OK)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
struct wpabuf *msg;
wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
msg = dpp_build_conf_result(auth, status);
if (!msg)
goto fail2;
wpa_msg(hapd->msg_ctx, MSG_INFO,
DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
MAC2STR(addr), auth->curr_freq,
DPP_PA_CONFIGURATION_RESULT);
hostapd_drv_send_action(hapd, auth->curr_freq, 0,
addr, wpabuf_head(msg),
wpabuf_len(msg));
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
auth->connect_on_tx_status = 1;
return;
}
fail2:
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; hapd->dpp_auth = NULL;
} }
@ -1281,6 +1315,63 @@ static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src,
} }
#ifdef CONFIG_DPP2
static void hostapd_dpp_config_result_wait_timeout(void *eloop_ctx,
void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct dpp_authentication *auth = hapd->dpp_auth;
if (!auth || !auth->waiting_conf_result)
return;
wpa_printf(MSG_DEBUG,
"DPP: Timeout while waiting for Configuration Result");
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(auth);
hapd->dpp_auth = NULL;
}
static void hostapd_dpp_rx_conf_result(struct hostapd_data *hapd, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
struct dpp_authentication *auth = hapd->dpp_auth;
enum dpp_status_error status;
wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
MAC2STR(src));
if (!auth || !auth->waiting_conf_result) {
wpa_printf(MSG_DEBUG,
"DPP: No DPP Configuration waiting for result - drop");
return;
}
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
return;
}
status = dpp_conf_result_rx(auth, hdr, buf, len);
hostapd_drv_send_action_cancel_wait(hapd);
hostapd_dpp_listen_stop(hapd);
if (status == DPP_STATUS_OK)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_SENT);
else
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(auth);
hapd->dpp_auth = NULL;
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
}
#endif /* CONFIG_DPP2 */
static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd, static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd,
const u8 *src, unsigned int freq, const u8 *src, unsigned int freq,
u8 trans_id, u8 trans_id,
@ -1744,6 +1835,11 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src,
hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len, hostapd_dpp_rx_pkex_commit_reveal_resp(hapd, src, hdr, buf, len,
freq); freq);
break; break;
#ifdef CONFIG_DPP2
case DPP_PA_CONFIGURATION_RESULT:
hostapd_dpp_rx_conf_result(hapd, src, hdr, buf, len);
break;
#endif /* CONFIG_DPP2 */
default: default:
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type); "DPP: Ignored unsupported frame subtype %d", type);
@ -1790,11 +1886,28 @@ hostapd_dpp_gas_req_handler(struct hostapd_data *hapd, const u8 *sa,
void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok) void hostapd_dpp_gas_status_handler(struct hostapd_data *hapd, int ok)
{ {
if (!hapd->dpp_auth) struct dpp_authentication *auth = hapd->dpp_auth;
if (!auth)
return; return;
wpa_printf(MSG_DEBUG, "DPP: Configuration exchange completed (ok=%d)",
ok);
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
auth->waiting_conf_result = 1;
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout,
hapd, NULL);
eloop_register_timeout(2, 0,
hostapd_dpp_config_result_wait_timeout,
hapd, NULL);
return;
}
#endif /* CONFIG_DPP2 */
hostapd_drv_send_action_cancel_wait(hapd); hostapd_drv_send_action_cancel_wait(hapd);
if (ok) if (ok)
@ -2070,6 +2183,10 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd)
eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL);
eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_resp_retry_timeout, hapd, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(hostapd_dpp_config_result_wait_timeout, hapd,
NULL);
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(hapd->dpp_auth); dpp_auth_deinit(hapd->dpp_auth);
hapd->dpp_auth = NULL; hapd->dpp_auth = NULL;
hostapd_dpp_pkex_remove(hapd, "*"); hostapd_dpp_pkex_remove(hapd, "*");

View File

@ -4441,6 +4441,7 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
wpabuf_head(conf), wpabuf_len(conf)); wpabuf_head(conf), wpabuf_len(conf));
} }
status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE; status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
auth->conf_resp_status = status;
/* { E-nonce, configurationObject}ke */ /* { E-nonce, configurationObject}ke */
clear_len = 4 + e_nonce_len; clear_len = 4 + e_nonce_len;
@ -4613,6 +4614,7 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
goto fail; goto fail;
} }
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
os_memcpy(auth->e_nonce, e_nonce, e_nonce_len);
config_attr = dpp_get_attr(unwrapped, unwrapped_len, config_attr = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_CONFIG_ATTR_OBJ, DPP_ATTR_CONFIG_ATTR_OBJ,
@ -5486,6 +5488,8 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
size_t unwrapped_len = 0; size_t unwrapped_len = 0;
int ret = -1; int ret = -1;
auth->conf_resp_status = 255;
if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) {
dpp_auth_fail(auth, "Invalid attribute in config response"); dpp_auth_fail(auth, "Invalid attribute in config response");
return -1; return -1;
@ -5546,6 +5550,7 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
"Missing or invalid required DPP Status attribute"); "Missing or invalid required DPP Status attribute");
goto fail; goto fail;
} }
auth->conf_resp_status = status[0];
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
if (status[0] != DPP_STATUS_OK) { if (status[0] != DPP_STATUS_OK) {
dpp_auth_fail(auth, "Configurator rejected configuration"); dpp_auth_fail(auth, "Configurator rejected configuration");
@ -5572,6 +5577,146 @@ fail:
} }
#ifdef CONFIG_DPP2
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *hdr,
const u8 *attr_start, size_t attr_len)
{
const u8 *wrapped_data, *status, *e_nonce;
u16 wrapped_data_len, status_len, e_nonce_len;
const u8 *addr[2];
size_t len[2];
u8 *unwrapped = NULL;
size_t unwrapped_len = 0;
enum dpp_status_error ret = 256;
wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA,
&wrapped_data_len);
if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) {
dpp_auth_fail(auth,
"Missing or invalid required Wrapped Data attribute");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data",
wrapped_data, wrapped_data_len);
attr_len = wrapped_data - 4 - attr_start;
addr[0] = hdr;
len[0] = DPP_HDR_LEN;
addr[1] = attr_start;
len[1] = attr_len;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext",
wrapped_data, wrapped_data_len);
unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE;
unwrapped = os_malloc(unwrapped_len);
if (!unwrapped)
goto fail;
if (aes_siv_decrypt(auth->ke, auth->curve->hash_len,
wrapped_data, wrapped_data_len,
2, addr, len, unwrapped) < 0) {
dpp_auth_fail(auth, "AES-SIV decryption failed");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext",
unwrapped, unwrapped_len);
if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) {
dpp_auth_fail(auth, "Invalid attribute in unwrapped data");
goto fail;
}
e_nonce = dpp_get_attr(unwrapped, unwrapped_len,
DPP_ATTR_ENROLLEE_NONCE,
&e_nonce_len);
if (!e_nonce || e_nonce_len != auth->curve->nonce_len) {
dpp_auth_fail(auth,
"Missing or invalid Enrollee Nonce attribute");
goto fail;
}
wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len);
if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) {
dpp_auth_fail(auth, "Enrollee Nonce mismatch");
wpa_hexdump(MSG_DEBUG, "DPP: Expected Enrollee Nonce",
auth->e_nonce, e_nonce_len);
goto fail;
}
status = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_STATUS,
&status_len);
if (!status || status_len < 1) {
dpp_auth_fail(auth,
"Missing or invalid required DPP Status attribute");
goto fail;
}
wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]);
ret = status[0];
fail:
bin_clear_free(unwrapped, unwrapped_len);
return ret;
}
#endif /* CONFIG_DPP2 */
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status)
{
struct wpabuf *msg, *clear;
size_t nonce_len, clear_len, attr_len;
const u8 *addr[2];
size_t len[2];
u8 *wrapped;
nonce_len = auth->curve->nonce_len;
clear_len = 5 + 4 + nonce_len;
attr_len = 4 + clear_len + AES_BLOCK_SIZE;
clear = wpabuf_alloc(clear_len);
msg = dpp_alloc_msg(DPP_PA_CONFIGURATION_RESULT, attr_len);
if (!clear || !msg)
return NULL;
/* DPP Status */
dpp_build_attr_status(clear, status);
/* E-nonce */
wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE);
wpabuf_put_le16(clear, nonce_len);
wpabuf_put_data(clear, auth->e_nonce, nonce_len);
/* OUI, OUI type, Crypto Suite, DPP frame type */
addr[0] = wpabuf_head_u8(msg) + 2;
len[0] = 3 + 1 + 1 + 1;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]);
/* Attributes before Wrapped Data (none) */
addr[1] = wpabuf_put(msg, 0);
len[1] = 0;
wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]);
/* Wrapped Data */
wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE);
wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear);
if (aes_siv_encrypt(auth->ke, auth->curve->hash_len,
wpabuf_head(clear), wpabuf_len(clear),
2, addr, len, wrapped) < 0)
goto fail;
wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Result attributes", msg);
wpabuf_free(clear);
return msg;
fail:
wpabuf_free(clear);
wpabuf_free(msg);
return NULL;
}
void dpp_configurator_free(struct dpp_configurator *conf) void dpp_configurator_free(struct dpp_configurator *conf)
{ {
if (!conf) if (!conf)

View File

@ -28,6 +28,7 @@ enum dpp_public_action_frame_type {
DPP_PA_PKEX_EXCHANGE_RESP = 8, DPP_PA_PKEX_EXCHANGE_RESP = 8,
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9, DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10, DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
DPP_PA_CONFIGURATION_RESULT = 11,
}; };
enum dpp_attribute_id { enum dpp_attribute_id {
@ -69,6 +70,7 @@ enum dpp_status_error {
DPP_STATUS_RESPONSE_PENDING = 6, DPP_STATUS_RESPONSE_PENDING = 6,
DPP_STATUS_INVALID_CONNECTOR = 7, DPP_STATUS_INVALID_CONNECTOR = 7,
DPP_STATUS_NO_MATCH = 8, DPP_STATUS_NO_MATCH = 8,
DPP_STATUS_CONFIG_REJECTED = 9,
}; };
#define DPP_CAPAB_ENROLLEE BIT(0) #define DPP_CAPAB_ENROLLEE BIT(0)
@ -173,6 +175,7 @@ struct dpp_authentication {
u8 waiting_pubkey_hash[SHA256_MAC_LEN]; u8 waiting_pubkey_hash[SHA256_MAC_LEN];
int response_pending; int response_pending;
enum dpp_status_error auth_resp_status; enum dpp_status_error auth_resp_status;
enum dpp_status_error conf_resp_status;
u8 peer_mac_addr[ETH_ALEN]; u8 peer_mac_addr[ETH_ALEN];
u8 i_nonce[DPP_MAX_NONCE_LEN]; u8 i_nonce[DPP_MAX_NONCE_LEN];
u8 r_nonce[DPP_MAX_NONCE_LEN]; u8 r_nonce[DPP_MAX_NONCE_LEN];
@ -208,6 +211,8 @@ struct dpp_authentication {
u8 allowed_roles; u8 allowed_roles;
int configurator; int configurator;
int remove_on_tx_status; int remove_on_tx_status;
int connect_on_tx_status;
int waiting_conf_result;
int auth_success; int auth_success;
struct wpabuf *conf_req; struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */ const struct wpabuf *conf_resp; /* owned by GAS server */
@ -393,6 +398,11 @@ dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
size_t attr_len); size_t attr_len);
int dpp_conf_resp_rx(struct dpp_authentication *auth, int dpp_conf_resp_rx(struct dpp_authentication *auth,
const struct wpabuf *resp); const struct wpabuf *resp);
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
const u8 *hdr,
const u8 *attr_start, size_t attr_len);
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
enum dpp_status_error status);
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
size_t len); size_t len);
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len); const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);

View File

@ -364,6 +364,18 @@ static void wpas_dpp_auth_resp_retry(struct wpa_supplicant *wpa_s)
} }
static void wpas_dpp_try_to_connect(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network");
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_s->scan_runs = 0;
wpa_s->normal_scans = 0;
wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s, static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
unsigned int freq, const u8 *dst, unsigned int freq, const u8 *dst,
const u8 *src, const u8 *bssid, const u8 *src, const u8 *bssid,
@ -387,6 +399,17 @@ static void wpas_dpp_tx_status(struct wpa_supplicant *wpa_s,
return; return;
} }
#ifdef CONFIG_DPP2
if (auth->connect_on_tx_status) {
wpa_printf(MSG_DEBUG,
"DPP: Try to connect after completed configuration result");
wpas_dpp_try_to_connect(wpa_s);
dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL;
return;
}
#endif /* CONFIG_DPP2 */
if (wpa_s->dpp_auth->remove_on_tx_status) { if (wpa_s->dpp_auth->remove_on_tx_status) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"DPP: Terminate authentication exchange due to an earlier error"); "DPP: Terminate authentication exchange due to an earlier error");
@ -1165,6 +1188,27 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
{ {
struct wpa_ssid *ssid; struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
if (auth->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
res = wpa_drv_get_capa(wpa_s, &capa);
if (res == 0 &&
!(capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) &&
!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) {
wpa_printf(MSG_DEBUG,
"DPP: SAE not supported by the driver");
return NULL;
}
#else /* CONFIG_SAE */
wpa_printf(MSG_DEBUG, "DPP: SAE not supported in the build");
return NULL;
#endif /* CONFIG_SAE */
}
#endif /* CONFIG_DPP2 */
ssid = wpa_config_add_network(wpa_s->conf); ssid = wpa_config_add_network(wpa_s->conf);
if (!ssid) if (!ssid)
return NULL; return NULL;
@ -1236,17 +1280,17 @@ fail:
} }
static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s, static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
struct dpp_authentication *auth) struct dpp_authentication *auth)
{ {
struct wpa_ssid *ssid; struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1) if (wpa_s->conf->dpp_config_processing < 1)
return; return 0;
ssid = wpas_dpp_add_network(wpa_s, auth); ssid = wpas_dpp_add_network(wpa_s, auth);
if (!ssid) if (!ssid)
return; return -1;
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_NETWORK_ID "%d", ssid->id);
if (wpa_s->conf->dpp_config_processing == 2) if (wpa_s->conf->dpp_config_processing == 2)
@ -1259,20 +1303,24 @@ static void wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_NO_CONFIG_WRITE */ #endif /* CONFIG_NO_CONFIG_WRITE */
if (wpa_s->conf->dpp_config_processing < 2) if (wpa_s->conf->dpp_config_processing < 2)
return; return 0;
wpa_printf(MSG_DEBUG, "DPP: Trying to connect to the new network"); #ifdef CONFIG_DPP2
wpa_s->disconnected = 0; if (auth->peer_version >= 2) {
wpa_s->reassociate = 1; wpa_printf(MSG_DEBUG,
wpa_s->scan_runs = 0; "DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
wpa_s->normal_scans = 0; auth->connect_on_tx_status = 1;
wpa_supplicant_cancel_sched_scan(wpa_s); return 0;
wpa_supplicant_req_scan(wpa_s, 0, 0); }
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
return 0;
} }
static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
struct dpp_authentication *auth) struct dpp_authentication *auth)
{ {
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED); wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
if (auth->ssid_len) if (auth->ssid_len)
@ -1324,7 +1372,7 @@ static void wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
} }
} }
wpas_dpp_process_config(wpa_s, auth); return wpas_dpp_process_config(wpa_s, auth);
} }
@ -1336,6 +1384,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
struct wpa_supplicant *wpa_s = ctx; struct wpa_supplicant *wpa_s = ctx;
const u8 *pos; const u8 *pos;
struct dpp_authentication *auth = wpa_s->dpp_auth; struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
wpa_s->dpp_gas_dialog_token = -1; wpa_s->dpp_gas_dialog_token = -1;
@ -1373,13 +1423,40 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail; goto fail;
} }
wpas_dpp_handle_config_obj(wpa_s, auth); res = wpas_dpp_handle_config_obj(wpa_s, auth);
dpp_auth_deinit(wpa_s->dpp_auth); if (res < 0)
wpa_s->dpp_auth = NULL; goto fail;
return;
status = DPP_STATUS_OK;
fail: fail:
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED); if (status != DPP_STATUS_OK)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
struct wpabuf *msg;
wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result");
msg = dpp_build_conf_result(auth, status);
if (!msg)
goto fail2;
wpa_msg(wpa_s, MSG_INFO,
DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
MAC2STR(addr), auth->curr_freq,
DPP_PA_CONFIGURATION_RESULT);
offchannel_send_action(wpa_s, auth->curr_freq,
addr, wpa_s->own_addr, broadcast,
wpabuf_head(msg),
wpabuf_len(msg),
500, wpas_dpp_tx_status, 0);
wpabuf_free(msg);
/* This exchange will be terminated in the TX status handler */
return;
}
fail2:
#endif /* CONFIG_DPP2 */
dpp_auth_deinit(wpa_s->dpp_auth); dpp_auth_deinit(wpa_s->dpp_auth);
wpa_s->dpp_auth = NULL; wpa_s->dpp_auth = NULL;
} }
@ -1562,6 +1639,62 @@ static void wpas_dpp_rx_auth_conf(struct wpa_supplicant *wpa_s, const u8 *src,
} }
#ifdef CONFIG_DPP2
static void wpas_dpp_config_result_wait_timeout(void *eloop_ctx,
void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct dpp_authentication *auth = wpa_s->dpp_auth;
if (!auth || !auth->waiting_conf_result)
return;
wpa_printf(MSG_DEBUG,
"DPP: Timeout while waiting for Configuration Result");
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(auth);
wpa_s->dpp_auth = NULL;
}
static void wpas_dpp_rx_conf_result(struct wpa_supplicant *wpa_s, const u8 *src,
const u8 *hdr, const u8 *buf, size_t len)
{
struct dpp_authentication *auth = wpa_s->dpp_auth;
enum dpp_status_error status;
wpa_printf(MSG_DEBUG, "DPP: Configuration Result from " MACSTR,
MAC2STR(src));
if (!auth || !auth->waiting_conf_result) {
wpa_printf(MSG_DEBUG,
"DPP: No DPP Configuration waiting for result - drop");
return;
}
if (os_memcmp(src, auth->peer_mac_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "DPP: MAC address mismatch (expected "
MACSTR ") - drop", MAC2STR(auth->peer_mac_addr));
return;
}
status = dpp_conf_result_rx(auth, hdr, buf, len);
offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s);
if (status == DPP_STATUS_OK)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_SENT);
else
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_FAILED);
dpp_auth_deinit(auth);
wpa_s->dpp_auth = NULL;
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
}
#endif /* CONFIG_DPP2 */
static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
const u8 *src, const u8 *src,
const u8 *buf, size_t len) const u8 *buf, size_t len)
@ -2105,6 +2238,11 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src,
wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len, wpas_dpp_rx_pkex_commit_reveal_resp(wpa_s, src, hdr, buf, len,
freq); freq);
break; break;
#ifdef CONFIG_DPP2
case DPP_PA_CONFIGURATION_RESULT:
wpas_dpp_rx_conf_result(wpa_s, src, hdr, buf, len);
break;
#endif /* CONFIG_DPP2 */
default: default:
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"DPP: Ignored unsupported frame subtype %d", type); "DPP: Ignored unsupported frame subtype %d", type);
@ -2174,6 +2312,21 @@ wpas_dpp_gas_status_handler(void *ctx, struct wpabuf *resp, int ok)
ok); ok);
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
if (ok && auth->peer_version >= 2 &&
auth->conf_resp_status == DPP_STATUS_OK) {
wpa_printf(MSG_DEBUG, "DPP: Wait for Configuration Result");
auth->waiting_conf_result = 1;
auth->conf_resp = NULL;
wpabuf_free(resp);
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout,
wpa_s, NULL);
eloop_register_timeout(2, 0,
wpas_dpp_config_result_wait_timeout,
wpa_s, NULL);
return;
}
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s); wpas_dpp_listen_stop(wpa_s);
if (ok) if (ok)
@ -2286,10 +2439,8 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
curve = get_param(cmd, " curve="); curve = get_param(cmd, " curve=");
wpas_dpp_set_testing_options(wpa_s, auth); wpas_dpp_set_testing_options(wpa_s, auth);
if (wpas_dpp_set_configurator(wpa_s, auth, cmd) == 0 && if (wpas_dpp_set_configurator(wpa_s, auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0) { dpp_configurator_own_config(auth, curve, 0) == 0)
wpas_dpp_handle_config_obj(wpa_s, auth); ret = wpas_dpp_handle_config_obj(wpa_s, auth);
ret = 0;
}
dpp_auth_deinit(auth); dpp_auth_deinit(auth);
os_free(curve); os_free(curve);
@ -2610,6 +2761,9 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s)
eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_reply_wait_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_init_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_dpp_auth_resp_retry_timeout, wpa_s, NULL);
#ifdef CONFIG_DPP2
eloop_cancel_timeout(wpas_dpp_config_result_wait_timeout, wpa_s, NULL);
#endif /* CONFIG_DPP2 */
offchannel_send_action_done(wpa_s); offchannel_send_action_done(wpa_s);
wpas_dpp_listen_stop(wpa_s); wpas_dpp_listen_stop(wpa_s);
dpp_bootstrap_del(wpa_s, 0); dpp_bootstrap_del(wpa_s, 0);