From e85b660129302fb113382c524f30705fa176bc51 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Oct 2017 11:43:41 +0200 Subject: [PATCH] DPP: Add DPP Status attribute into Peer Discovery Response This was added in DPP tech spec v0.2.7 to allow result of network introduction to be reported. Signed-off-by: Jouni Malinen --- src/ap/dpp_hostapd.c | 91 ++++++++++++++++++++++----------- src/common/dpp.c | 55 ++++++++++++++------ src/common/dpp.h | 13 +++-- src/common/wpa_ctrl.h | 1 + wpa_supplicant/dpp_supplicant.c | 47 +++++++++++++---- 5 files changed, 146 insertions(+), 61 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index b8b04749b..943e20648 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -890,6 +890,46 @@ static void hostapd_dpp_rx_auth_conf(struct hostapd_data *hapd, const u8 *src, } +static void hostapd_dpp_send_peer_disc_resp(struct hostapd_data *hapd, + const u8 *src, unsigned int freq, + u8 trans_id, + enum dpp_status_error status) +{ + struct wpabuf *msg; + + msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, + 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector)); + if (!msg) + return; + + /* Transaction ID */ + wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, trans_id); + + /* DPP Status */ + wpabuf_put_le16(msg, DPP_ATTR_STATUS); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, status); + + /* DPP Connector */ + if (status == DPP_STATUS_OK) { + wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); + wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector)); + wpabuf_put_str(msg, hapd->conf->dpp_connector); + } + + wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR + " status=%d", MAC2STR(src), status); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d status=%d", MAC2STR(src), freq, + DPP_PA_PEER_DISCOVERY_RESP, status); + hostapd_drv_send_action(hapd, freq, 0, src, + wpabuf_head(msg), wpabuf_len(msg)); + wpabuf_free(msg); +} + + static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, const u8 *src, const u8 *buf, size_t len, @@ -901,7 +941,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, struct dpp_introduction intro; os_time_t expire; int expiration; - struct wpabuf *msg; + enum dpp_status_error res; wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR, MAC2STR(src)); @@ -941,14 +981,24 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, return; } - if (dpp_peer_intro(&intro, hapd->conf->dpp_connector, - wpabuf_head(hapd->conf->dpp_netaccesskey), - wpabuf_len(hapd->conf->dpp_netaccesskey), - wpabuf_head(hapd->conf->dpp_csign), - wpabuf_len(hapd->conf->dpp_csign), - connector, connector_len, &expire) < 0) { + res = dpp_peer_intro(&intro, hapd->conf->dpp_connector, + wpabuf_head(hapd->conf->dpp_netaccesskey), + wpabuf_len(hapd->conf->dpp_netaccesskey), + wpabuf_head(hapd->conf->dpp_csign), + wpabuf_len(hapd->conf->dpp_csign), + connector, connector_len, &expire); + if (res == 255) { wpa_printf(MSG_INFO, - "DPP: Network Introduction protocol resulted in failure"); + "DPP: Network Introduction protocol resulted in internal failure (peer " + MACSTR ")", MAC2STR(src)); + return; + } + if (res != DPP_STATUS_OK) { + wpa_printf(MSG_INFO, + "DPP: Network Introduction protocol resulted in failure (peer " + MACSTR " status %d)", MAC2STR(src), res); + hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], + res); return; } @@ -966,29 +1016,8 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd, return; } - msg = dpp_alloc_msg(DPP_PA_PEER_DISCOVERY_RESP, - 5 + 4 + os_strlen(hapd->conf->dpp_connector)); - if (!msg) - return; - - /* Transaction ID */ - wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID); - wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, trans_id[0]); - - /* DPP Connector */ - wpabuf_put_le16(msg, DPP_ATTR_CONNECTOR); - wpabuf_put_le16(msg, os_strlen(hapd->conf->dpp_connector)); - wpabuf_put_str(msg, hapd->conf->dpp_connector); - - wpa_printf(MSG_DEBUG, "DPP: Send Peer Discovery Response to " MACSTR, - MAC2STR(src)); - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR - " freq=%u type=%d", MAC2STR(src), freq, - DPP_PA_PEER_DISCOVERY_RESP); - hostapd_drv_send_action(hapd, freq, 0, src, - wpabuf_head(msg), wpabuf_len(msg)); - wpabuf_free(msg); + hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0], + DPP_STATUS_OK); } diff --git a/src/common/dpp.c b/src/common/dpp.c index ae5fbd384..f969cb35f 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -4356,11 +4356,11 @@ struct dpp_signed_connector_info { size_t payload_len; }; -static int +static enum dpp_status_error dpp_process_signed_connector(struct dpp_signed_connector_info *info, EVP_PKEY *csign_pub, const char *connector) { - int ret = -1; + enum dpp_status_error ret = 255; const char *pos, *end, *signed_start, *signed_end; struct wpabuf *kid = NULL; unsigned char *prot_hdr = NULL, *signature = NULL; @@ -4394,6 +4394,7 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, end = os_strchr(pos, '.'); if (!end) { wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } prot_hdr = base64_url_decode((const unsigned char *) pos, @@ -4401,18 +4402,22 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, if (!prot_hdr) { wpa_printf(MSG_DEBUG, "DPP: Failed to base64url decode signedConnector JWS Protected Header"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector - JWS Protected Header", prot_hdr, prot_hdr_len); kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md); - if (!kid) + if (!kid) { + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; + } if (wpabuf_len(kid) != SHA256_MAC_LEN) { wpa_printf(MSG_DEBUG, "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)", (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } @@ -4421,6 +4426,7 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, if (!end) { wpa_printf(MSG_DEBUG, "DPP: Missing dot(2) in signedConnector"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } signed_end = end - 1; @@ -4429,6 +4435,7 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, if (!info->payload) { wpa_printf(MSG_DEBUG, "DPP: Failed to base64url decode signedConnector JWS Payload"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } wpa_hexdump_ascii(MSG_DEBUG, @@ -4440,18 +4447,22 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, if (!signature) { wpa_printf(MSG_DEBUG, "DPP: Failed to base64url decode signedConnector signature"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature", signature, signature_len); - if (dpp_check_pubkey_match(csign_pub, kid) < 0) + if (dpp_check_pubkey_match(csign_pub, kid) < 0) { + ret = DPP_STATUS_NO_MATCH; goto fail; + } if (signature_len & 0x01) { wpa_printf(MSG_DEBUG, "DPP: Unexpected signedConnector signature length (%d)", (int) signature_len); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } @@ -4492,10 +4503,11 @@ dpp_process_signed_connector(struct dpp_signed_connector_info *info, wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyFinal failed (res=%d): %s", res, ERR_error_string(ERR_get_error(), NULL)); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } - ret = 0; + ret = DPP_STATUS_OK; fail: EC_KEY_free(eckey); EVP_MD_CTX_destroy(md_ctx); @@ -4554,7 +4566,7 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth, } if (dpp_process_signed_connector(&info, csign_pub, - signed_connector) < 0) + signed_connector) != DPP_STATUS_OK) goto fail; if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) { @@ -5021,15 +5033,16 @@ fail: } -int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, - const u8 *net_access_key, size_t net_access_key_len, - const u8 *csign_key, size_t csign_key_len, - const u8 *peer_connector, size_t peer_connector_len, - os_time_t *expiry) +enum dpp_status_error +dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, + const u8 *net_access_key, size_t net_access_key_len, + const u8 *csign_key, size_t csign_key_len, + const u8 *peer_connector, size_t peer_connector_len, + os_time_t *expiry) { struct json_token *root = NULL, *netkey, *token; struct json_token *own_root = NULL; - int ret = -1; + enum dpp_status_error ret = 255, res; EVP_PKEY *own_key = NULL, *peer_key = NULL; struct wpabuf *own_key_pub = NULL; const struct dpp_curve_params *curve, *own_curve; @@ -5097,18 +5110,23 @@ int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, os_memcpy(signed_connector, peer_connector, peer_connector_len); signed_connector[peer_connector_len] = '\0'; - if (dpp_process_signed_connector(&info, csign, signed_connector) < 0) + res = dpp_process_signed_connector(&info, csign, signed_connector); + if (res != DPP_STATUS_OK) { + ret = res; goto fail; + } root = json_parse((const char *) info.payload, info.payload_len); if (!root) { wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } if (!dpp_connector_match_groups(own_root, root)) { wpa_printf(MSG_DEBUG, "DPP: Peer connector does not include compatible group netrole with own connector"); + ret = DPP_STATUS_NO_MATCH; goto fail; } @@ -5121,6 +5139,7 @@ int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, if (dpp_key_expired(token->string, expiry)) { wpa_printf(MSG_DEBUG, "DPP: Connector (netAccessKey) has expired"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } } @@ -5128,18 +5147,22 @@ int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, netkey = json_get_member(root, "netAccessKey"); if (!netkey || netkey->type != JSON_OBJECT) { wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } peer_key = dpp_parse_jwk(netkey, &curve); - if (!peer_key) + if (!peer_key) { + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; + } dpp_debug_print_key("DPP: Received netAccessKey", peer_key); if (own_curve != curve) { wpa_printf(MSG_DEBUG, "DPP: Mismatching netAccessKey curves (%s != %s)", own_curve->name, curve->name); + ret = DPP_STATUS_INVALID_CONNECTOR; goto fail; } @@ -5173,9 +5196,9 @@ int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, goto fail; } - ret = 0; + ret = DPP_STATUS_OK; fail: - if (ret < 0) + if (ret != DPP_STATUS_OK) os_memset(intro, 0, sizeof(*intro)); os_memset(Nx, 0, sizeof(Nx)); EVP_PKEY_CTX_free(ctx); diff --git a/src/common/dpp.h b/src/common/dpp.h index 5f4922eee..905d1f138 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -63,6 +63,8 @@ enum dpp_status_error { DPP_STATUS_BAD_GROUP = 4, DPP_STATUS_CONFIGURE_FAILURE = 5, DPP_STATUS_RESPONSE_PENDING = 6, + DPP_STATUS_INVALID_CONNECTOR = 7, + DPP_STATUS_NO_MATCH = 8, }; #define DPP_CAPAB_ENROLLEE BIT(0) @@ -292,11 +294,12 @@ dpp_keygen_configurator(const char *curve, const u8 *privkey, size_t privkey_len); int dpp_configurator_own_config(struct dpp_authentication *auth, const char *curve); -int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, - const u8 *net_access_key, size_t net_access_key_len, - const u8 *csign_key, size_t csign_key_len, - const u8 *peer_connector, size_t peer_connector_len, - os_time_t *expiry); +enum dpp_status_error +dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, + const u8 *net_access_key, size_t net_access_key_len, + const u8 *csign_key, size_t csign_key_len, + const u8 *peer_connector, size_t peer_connector_len, + os_time_t *expiry); struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi, const u8 *own_mac, const char *identifier, diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 18eeeb726..6e9dcf14a 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -171,6 +171,7 @@ extern "C" { #define DPP_EVENT_TX "DPP-TX " #define DPP_EVENT_TX_STATUS "DPP-TX-STATUS " #define DPP_EVENT_FAIL "DPP-FAIL " +#define DPP_EVENT_INTRO "DPP-INTRO " /* MESH events */ #define MESH_GROUP_STARTED "MESH-GROUP-STARTED " diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 0715556de..874b90992 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1243,14 +1243,15 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len) { struct wpa_ssid *ssid; - const u8 *connector, *trans_id; - u16 connector_len, trans_id_len; + const u8 *connector, *trans_id, *status; + u16 connector_len, trans_id_len, status_len; struct dpp_introduction intro; struct rsn_pmksa_cache_entry *entry; struct os_time now; struct os_reltime rnow; os_time_t expiry; unsigned int seconds; + enum dpp_status_error res; wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Response from " MACSTR, MAC2STR(src)); @@ -1278,12 +1279,32 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, if (!trans_id || trans_id_len != 1) { wpa_printf(MSG_DEBUG, "DPP: Peer did not include Transaction ID"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_transaction_id", MAC2STR(src)); goto fail; } if (trans_id[0] != TRANSACTION_ID) { wpa_printf(MSG_DEBUG, "DPP: Ignore frame with unexpected Transaction ID %u", trans_id[0]); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=transaction_id_mismatch", MAC2STR(src)); + goto fail; + } + + status = dpp_get_attr(buf, len, DPP_ATTR_STATUS, &status_len); + if (!status || status_len != 1) { + wpa_printf(MSG_DEBUG, "DPP: Peer did not include Status"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_status", MAC2STR(src)); + goto fail; + } + if (status[0] != DPP_STATUS_OK) { + wpa_printf(MSG_DEBUG, + "DPP: Peer rejected network introduction: Status %u", + status[0]); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " status=%u", MAC2STR(src), status[0]); goto fail; } @@ -1291,17 +1312,22 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, if (!connector) { wpa_printf(MSG_DEBUG, "DPP: Peer did not include its Connector"); - return; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=missing_connector", MAC2STR(src)); + goto fail; } - if (dpp_peer_intro(&intro, ssid->dpp_connector, - ssid->dpp_netaccesskey, - ssid->dpp_netaccesskey_len, - ssid->dpp_csign, - ssid->dpp_csign_len, - connector, connector_len, &expiry) < 0) { + res = dpp_peer_intro(&intro, ssid->dpp_connector, + ssid->dpp_netaccesskey, + ssid->dpp_netaccesskey_len, + ssid->dpp_csign, + ssid->dpp_csign_len, + connector, connector_len, &expiry); + if (res != DPP_STATUS_OK) { wpa_printf(MSG_INFO, "DPP: Network Introduction protocol resulted in failure"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " fail=peer_connector_validation_failed", MAC2STR(src)); goto fail; } @@ -1325,6 +1351,9 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s, entry->network_ctx = ssid; wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR + " status=%u", MAC2STR(src), status[0]); + wpa_printf(MSG_DEBUG, "DPP: Try connection again after successful network introduction"); if (wpa_supplicant_fast_associate(wpa_s) != 1) {