}
+static bool hapd_dpp_connector_available(struct hostapd_data *hapd)
+{
+ if (!hapd->wpa_auth ||
+ !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
+ !(hapd->conf->wpa & WPA_PROTO_RSN)) {
+ wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
+ return false;
+ }
+
+ if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
+ !hapd->conf->dpp_csign) {
+ wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
+ return false;
+ }
+
+ return true;
+}
+
+
static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
const u8 *src,
const u8 *buf, size_t len,
int expiration;
enum dpp_status_error res;
+ os_memset(&intro, 0, sizeof(intro));
+
wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
MAC2STR(src));
- if (!hapd->wpa_auth ||
- !(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) ||
- !(hapd->conf->wpa & WPA_PROTO_RSN)) {
- wpa_printf(MSG_DEBUG, "DPP: DPP AKM not in use");
+ if (!hapd_dpp_connector_available(hapd))
return;
- }
-
- if (!hapd->conf->dpp_connector || !hapd->conf->dpp_netaccesskey ||
- !hapd->conf->dpp_csign) {
- wpa_printf(MSG_DEBUG, "DPP: No own Connector/keys set");
- return;
- }
os_get_time(&now);
wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in internal failure (peer "
MACSTR ")", MAC2STR(src));
- return;
+ goto done;
}
if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO,
MACSTR " status %d)", MAC2STR(src), res);
hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
res);
- return;
+ goto done;
}
#ifdef CONFIG_DPP3
hostapd_dpp_send_peer_disc_resp(hapd, src, freq,
trans_id[0],
DPP_STATUS_NO_MATCH);
- return;
+ goto done;
}
}
#endif /* CONFIG_DPP3 */
intro.pmkid, expiration,
WPA_KEY_MGMT_DPP) < 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
- return;
+ goto done;
}
hostapd_dpp_send_peer_disc_resp(hapd, src, freq, trans_id[0],
DPP_STATUS_OK);
+done:
+ dpp_peer_intro_deinit(&intro);
}
hostapd_dpp_pb_pkex_init(hapd, freq, src, r_hash);
}
+
+static void
+hostapd_dpp_rx_priv_peer_intro_query(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ const u8 *trans_id, *version;
+ u16 trans_id_len, version_len;
+ struct wpabuf *msg;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Query from "
+ MACSTR, MAC2STR(src));
+
+ if (!hapd_dpp_connector_available(hapd))
+ return;
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ return;
+ }
+
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Protocol Version");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Transaction ID %u, Version %u",
+ trans_id[0], version[0]);
+
+ len = 5 + 5 + 4 + os_strlen(hapd->conf->dpp_connector);
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_NOTIFY, len);
+ 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]);
+
+ /* Protocol Version */
+ conn_ver = dpp_get_connector_version(hapd->conf->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, ver);
+
+ /* 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 Private Peer Introduction Notify 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_PRIV_PEER_INTRO_NOTIFY);
+ hostapd_drv_send_action(hapd, freq, 0, src,
+ wpabuf_head(msg), wpabuf_len(msg));
+ wpabuf_free(msg);
+}
+
+
+static void
+hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src,
+ const u8 *hdr, const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct crypto_ec_key *own_key;
+ const struct dpp_curve_params *curve;
+ enum hpke_kem_id kem_id;
+ enum hpke_kdf_id kdf_id;
+ enum hpke_aead_id aead_id;
+ const u8 *aad = hdr;
+ size_t aad_len = DPP_HDR_LEN;
+ struct wpabuf *pt;
+ const u8 *trans_id, *wrapped, *version, *connector;
+ u16 trans_id_len, wrapped_len, version_len, connector_len;
+ struct os_time now;
+ struct dpp_introduction intro;
+ os_time_t expire;
+ int expiration;
+ enum dpp_status_error res;
+
+ os_memset(&intro, 0, sizeof(intro));
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Update from "
+ MACSTR, MAC2STR(src));
+
+ if (!hapd_dpp_connector_available(hapd))
+ return;
+
+ os_get_time(&now);
+
+ if (hapd->conf->dpp_netaccesskey_expiry &&
+ (os_time_t) hapd->conf->dpp_netaccesskey_expiry < now.sec) {
+ wpa_printf(MSG_INFO, "DPP: Own netAccessKey expired");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ if (!trans_id || trans_id_len != 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Transaction ID");
+ return;
+ }
+
+ wrapped = dpp_get_attr(buf, len, DPP_ATTR_WRAPPED_DATA,
+ &wrapped_len);
+ if (!wrapped) {
+ wpa_printf(MSG_DEBUG, "DPP: Peer did not include Wrapped Data");
+ return;
+ }
+
+ own_key = dpp_set_keypair(&curve,
+ wpabuf_head(hapd->conf->dpp_netaccesskey),
+ wpabuf_len(hapd->conf->dpp_netaccesskey));
+ if (!own_key) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey");
+ return;
+ }
+
+ if (dpp_hpke_suite(curve->ike_group, &kem_id, &kdf_id, &aead_id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Unsupported curve %d",
+ curve->ike_group);
+ crypto_ec_key_deinit(own_key);
+ return;
+ }
+
+ pt = hpke_base_open(kem_id, kdf_id, aead_id, own_key, NULL, 0,
+ aad, aad_len, wrapped, wrapped_len);
+ crypto_ec_key_deinit(own_key);
+ if (!pt) {
+ wpa_printf(MSG_INFO, "DPP: Failed to decrypt Connector");
+ return;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE-Decrypted Wrapped Data", pt);
+
+ connector = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt),
+ DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ goto done;
+ }
+
+ version = dpp_get_attr(wpabuf_head(pt), wpabuf_len(pt),
+ DPP_ATTR_PROTOCOL_VERSION, &version_len);
+ if (!version || version_len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include Protocol Version");
+ goto done;
+ }
+
+ 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 internal failure (peer "
+ MACSTR ")", MAC2STR(src));
+ goto done;
+ }
+ if (res != DPP_STATUS_OK) {
+ wpa_printf(MSG_INFO,
+ "DPP: Network Introduction protocol resulted in failure (peer "
+ MACSTR " status %d)", MAC2STR(src), res);
+ goto done;
+ }
+
+ if (intro.peer_version && intro.peer_version >= 2) {
+ u8 attr_version = 1;
+
+ if (version && version_len >= 1)
+ attr_version = version[0];
+ if (attr_version != intro.peer_version) {
+ wpa_printf(MSG_INFO,
+ "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
+ intro.peer_version, attr_version);
+ goto done;
+ }
+ }
+
+ if (!expire || (os_time_t) hapd->conf->dpp_netaccesskey_expiry < expire)
+ expire = hapd->conf->dpp_netaccesskey_expiry;
+ if (expire)
+ expiration = expire - now.sec;
+ else
+ expiration = 0;
+
+ if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+ intro.pmkid, expiration,
+ WPA_KEY_MGMT_DPP) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
+ goto done;
+ }
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction completed with "
+ MACSTR, MAC2STR(src));
+
+done:
+ dpp_peer_intro_deinit(&intro);
+ wpabuf_free(pt);
+}
+
#endif /* CONFIG_DPP3 */
hostapd_dpp_rx_pb_presence_announcement(hapd, src, hdr,
buf, len, freq);
break;
+ case DPP_PA_PRIV_PEER_INTRO_QUERY:
+ hostapd_dpp_rx_priv_peer_intro_query(hapd, src, hdr,
+ buf, len, freq);
+ break;
+ case DPP_PA_PRIV_PEER_INTRO_UPDATE:
+ hostapd_dpp_rx_priv_peer_intro_update(hapd, src, hdr,
+ buf, len, freq);
+ break;
#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
struct json_token *root = NULL, *netkey, *token;
struct json_token *own_root = NULL;
enum dpp_status_error ret = 255, res;
- struct crypto_ec_key *own_key = NULL, *peer_key = NULL;
+ struct crypto_ec_key *own_key = NULL;
struct wpabuf *own_key_pub = NULL;
const struct dpp_curve_params *curve, *own_curve;
struct dpp_signed_connector_info info;
goto fail;
}
- peer_key = dpp_parse_jwk(netkey, &curve);
- if (!peer_key) {
+ intro->peer_key = dpp_parse_jwk(netkey, &curve);
+ if (!intro->peer_key) {
ret = DPP_STATUS_INVALID_CONNECTOR;
goto fail;
}
- dpp_debug_print_key("DPP: Received netAccessKey", peer_key);
+ dpp_debug_print_key("DPP: Received netAccessKey", intro->peer_key);
if (own_curve != curve) {
wpa_printf(MSG_DEBUG,
}
/* ECDH: N = nk * PK */
- if (dpp_ecdh(own_key, peer_key, Nx, &Nx_len) < 0)
+ if (dpp_ecdh(own_key, intro->peer_key, Nx, &Nx_len) < 0)
goto fail;
wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)",
intro->pmk_len = curve->hash_len;
/* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */
- if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) {
+ if (dpp_derive_pmkid(curve, own_key, intro->peer_key, intro->pmkid) <
+ 0) {
wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID");
goto fail;
}
+#ifdef CONFIG_DPP3
+ if (dpp_hpke_suite(curve->ike_group, &intro->kem_id, &intro->kdf_id,
+ &intro->aead_id) < 0) {
+ wpa_printf(MSG_ERROR, "DPP: Unsupported group %d",
+ curve->ike_group);
+ goto fail;
+ }
+#endif /* CONFIG_DPP3 */
+
ret = DPP_STATUS_OK;
fail:
if (ret != DPP_STATUS_OK)
- os_memset(intro, 0, sizeof(*intro));
+ dpp_peer_intro_deinit(intro);
os_memset(Nx, 0, sizeof(Nx));
os_free(info.payload);
crypto_ec_key_deinit(own_key);
wpabuf_free(own_key_pub);
- crypto_ec_key_deinit(peer_key);
json_free(root);
json_free(own_root);
return ret;
}
+void dpp_peer_intro_deinit(struct dpp_introduction *intro)
+{
+ if (!intro)
+ return;
+
+ crypto_ec_key_deinit(intro->peer_key);
+ os_memset(intro, 0, sizeof(*intro));
+}
+
+
#ifdef CONFIG_DPP3
int dpp_get_connector_version(const char *connector)
{
DPP_PA_PKEX_EXCHANGE_REQ = 18,
DPP_PA_PB_PRESENCE_ANNOUNCEMENT = 19,
DPP_PA_PB_PRESENCE_ANNOUNCEMENT_RESP = 20,
+ DPP_PA_PRIV_PEER_INTRO_QUERY = 21,
+ DPP_PA_PRIV_PEER_INTRO_NOTIFY = 22,
+ DPP_PA_PRIV_PEER_INTRO_UPDATE = 23,
};
enum dpp_attribute_id {
u8 pmk[PMK_LEN_MAX];
size_t pmk_len;
int peer_version;
+ struct crypto_ec_key *peer_key;
+ enum hpke_kem_id kem_id;
+ enum hpke_kdf_id kdf_id;
+ enum hpke_aead_id aead_id;
};
struct dpp_relay_config {
const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len,
os_time_t *expiry);
+void dpp_peer_intro_deinit(struct dpp_introduction *intro);
int dpp_get_connector_version(const char *connector);
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
const u8 *own_mac,
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
void dpp_pfs_free(struct dpp_pfs *pfs);
+struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
+ const u8 *privkey, size_t privkey_len);
+int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
+ enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id);
+
struct wpabuf * dpp_build_csr(struct dpp_authentication *auth,
const char *name);
int dpp_validate_csr(struct dpp_authentication *auth, const struct wpabuf *csr);
#ifdef CONFIG_DPP3
+
int dpp_derive_auth_i(struct dpp_authentication *auth, u8 *auth_i)
{
int ret = -1, res;
wpabuf_free(pex);
return ret;
}
+
+
+int dpp_hpke_suite(int iana_group, enum hpke_kem_id *kem_id,
+ enum hpke_kdf_id *kdf_id, enum hpke_aead_id *aead_id)
+{
+ switch (iana_group) {
+ case 19:
+ *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
+ *kdf_id = HPKE_KDF_HKDF_SHA256;
+ *aead_id = HPKE_AEAD_AES_128_GCM;
+ return 0;
+ case 20:
+ *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
+ *kdf_id = HPKE_KDF_HKDF_SHA384;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 21:
+ *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
+ *kdf_id = HPKE_KDF_HKDF_SHA512;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 28:
+ *kem_id = HPKE_DHKEM_P256_HKDF_SHA256;
+ *kdf_id = HPKE_KDF_HKDF_SHA256;
+ *aead_id = HPKE_AEAD_AES_128_GCM;
+ return 0;
+ case 29:
+ *kem_id = HPKE_DHKEM_P384_HKDF_SHA384;
+ *kdf_id = HPKE_KDF_HKDF_SHA384;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ case 30:
+ *kem_id = HPKE_DHKEM_P521_HKDF_SHA512;
+ *kdf_id = HPKE_KDF_HKDF_SHA512;
+ *aead_id = HPKE_AEAD_AES_256_GCM;
+ return 0;
+ }
+
+ return -1;
+}
+
#endif /* CONFIG_DPP3 */
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
const u8 *privkey, size_t privkey_len);
-struct crypto_ec_key * dpp_set_keypair(const struct dpp_curve_params **curve,
- const u8 *privkey, size_t privkey_len);
struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve);
int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, unsigned int hash_len);
int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, unsigned int hash_len);
{ STR_LEN(dpp_csign) },
{ STR_LEN(dpp_pp_key) },
{ INT_RANGE(dpp_pfs, 0, 2) },
+ { INT_RANGE(dpp_connector_privacy, 0, 1) },
#endif /* CONFIG_DPP */
{ INT_RANGE(owe_group, 0, 65535) },
{ INT_RANGE(owe_only, 0, 1) },
STR(dpp_csign);
STR(dpp_pp_key);
INT(dpp_pfs);
+ INT(dpp_connector_privacy);
#endif /* CONFIG_DPP */
INT(owe_group);
INT(owe_only);
*/
int dpp_pfs_fallback;
+ /**
+ * dpp_connector_privacy - Network introduction type
+ * 0: unprotected variant from DPP R1
+ * 1: privacy protecting (station Connector encrypted) variant from
+ * DPP R3
+ */
+ int dpp_connector_privacy;
+
/**
* owe_group - OWE DH Group
*
}
}
+
+static void
+wpas_dpp_tx_priv_intro_status(struct wpa_supplicant *wpa_s,
+ unsigned int freq, const u8 *dst,
+ const u8 *src, const u8 *bssid,
+ const u8 *data, size_t data_len,
+ enum offchannel_send_action_result result)
+{
+ const char *res_txt;
+
+ res_txt = result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
+ (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
+ "FAILED");
+ wpa_printf(MSG_DEBUG, "DPP: TX status: freq=%u dst=" MACSTR
+ " result=%s (DPP Private Peer Introduction Update)",
+ freq, MAC2STR(dst), res_txt);
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX_STATUS "dst=" MACSTR
+ " freq=%u result=%s", MAC2STR(dst), freq, res_txt);
+
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR " version=%u",
+ MAC2STR(src), wpa_s->dpp_intro_peer_version);
+
+ wpa_printf(MSG_DEBUG,
+ "DPP: Try connection again after successful network introduction");
+ if (wpa_supplicant_fast_associate(wpa_s) != 1) {
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+}
+
+
+static int
+wpas_dpp_send_private_peer_intro_update(struct wpa_supplicant *wpa_s,
+ struct dpp_introduction *intro,
+ struct wpa_ssid *ssid,
+ const u8 *dst, unsigned int freq)
+{
+ struct wpabuf *pt, *msg, *enc_ct;
+ size_t len;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+ const u8 *aad;
+ size_t aad_len;
+ unsigned int wait_time;
+
+ wpa_printf(MSG_DEBUG, "HPKE(kem_id=%u kdf_id=%u aead_id=%u)",
+ intro->kem_id, intro->kdf_id, intro->aead_id);
+
+ /* Plaintext for HPKE */
+ len = 5 + 4 + os_strlen(ssid->dpp_connector);
+ pt = wpabuf_alloc(len);
+ if (!pt)
+ return -1;
+
+ /* Protocol Version */
+ conn_ver = dpp_get_connector_version(ssid->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+ wpabuf_put_le16(pt, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(pt, 1);
+ wpabuf_put_u8(pt, ver);
+
+ /* Connector */
+ wpabuf_put_le16(pt, DPP_ATTR_CONNECTOR);
+ wpabuf_put_le16(pt, os_strlen(ssid->dpp_connector));
+ wpabuf_put_str(pt, ssid->dpp_connector);
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Plaintext for HPKE", pt);
+
+ /* HPKE(pt) using AP's public key (from its Connector) */
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, 0);
+ if (!msg) {
+ wpabuf_free(pt);
+ return -1;
+ }
+ aad = wpabuf_head_u8(msg) + 2; /* from the OUI field (inclusive) */
+ aad_len = DPP_HDR_LEN; /* to the DPP Frame Type field (inclusive) */
+ wpa_hexdump(MSG_MSGDUMP, "DPP: AAD for HPKE", aad, aad_len);
+
+ enc_ct = hpke_base_seal(intro->kem_id, intro->kdf_id, intro->aead_id,
+ intro->peer_key, NULL, 0, aad, aad_len,
+ wpabuf_head(pt), wpabuf_len(pt));
+ wpabuf_free(pt);
+ wpabuf_free(msg);
+ if (!enc_ct) {
+ wpa_printf(MSG_INFO, "DPP: HPKE Seal(Connector) failed");
+ return -1;
+ }
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: HPKE enc|ct", enc_ct);
+
+ /* HPKE(pt) to generate payload for Wrapped Data */
+ len = 5 + 4 + wpabuf_len(enc_ct);
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_UPDATE, len);
+ if (!msg) {
+ wpabuf_free(enc_ct);
+ return -1;
+ }
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, TRANSACTION_ID);
+
+ /* Wrapped Data */
+ wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA);
+ wpabuf_put_le16(msg, wpabuf_len(enc_ct));
+ wpabuf_put_buf(msg, enc_ct);
+ wpabuf_free(enc_ct);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Update", msg);
+
+ /* TODO: Timeout on AP response */
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(dst), freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
+ offchannel_send_action(wpa_s, freq, dst, wpa_s->own_addr, broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_priv_intro_status, 0);
+ wpabuf_free(msg);
+
+ return 0;
+}
+
+
+static void
+wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant *wpa_s,
+ const u8 *src, const u8 *hdr,
+ const u8 *buf, size_t len,
+ unsigned int freq)
+{
+ struct wpa_ssid *ssid;
+ const u8 *connector, *trans_id, *version;
+ u16 connector_len, trans_id_len, version_len;
+ u8 peer_version = 1;
+ 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;
+
+ os_memset(&intro, 0, sizeof(intro));
+
+ wpa_printf(MSG_DEBUG, "DPP: Private Peer Introduction Notify from "
+ MACSTR, MAC2STR(src));
+ if (is_zero_ether_addr(wpa_s->dpp_intro_bssid) ||
+ os_memcmp(src, wpa_s->dpp_intro_bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "DPP: Not waiting for response from "
+ MACSTR " - drop", MAC2STR(src));
+ return;
+ }
+ offchannel_send_action_done(wpa_s);
+
+ for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+ if (ssid == wpa_s->dpp_intro_network)
+ break;
+ }
+ if (!ssid || !ssid->dpp_connector || !ssid->dpp_netaccesskey ||
+ !ssid->dpp_csign) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Profile not found for network introduction");
+ return;
+ }
+
+ trans_id = dpp_get_attr(buf, len, DPP_ATTR_TRANSACTION_ID,
+ &trans_id_len);
+ 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;
+ }
+
+ connector = dpp_get_attr(buf, len, DPP_ATTR_CONNECTOR, &connector_len);
+ if (!connector) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include its Connector");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_connector", MAC2STR(src));
+ goto fail;
+ }
+
+ version = dpp_get_attr(buf, len, DPP_ATTR_PROTOCOL_VERSION,
+ &version_len);
+ if (!version || version_len < 1) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Peer did not include valid Version");
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_INTRO "peer=" MACSTR
+ " fail=missing_version", MAC2STR(src));
+ goto fail;
+ }
+
+ 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));
+ wpas_dpp_send_conn_status_result(wpa_s, res);
+ goto fail;
+ }
+
+ peer_version = version[0];
+ if (intro.peer_version && intro.peer_version >= 2 &&
+ peer_version != intro.peer_version) {
+ wpa_printf(MSG_INFO,
+ "DPP: Protocol version mismatch (Connector: %d Attribute: %d",
+ intro.peer_version, peer_version);
+ wpas_dpp_send_conn_status_result(wpa_s, DPP_STATUS_NO_MATCH);
+ goto fail;
+ }
+ wpa_s->dpp_intro_peer_version = peer_version;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (!entry)
+ goto fail;
+ entry->dpp_pfs = peer_version >= 2;
+ os_memcpy(entry->aa, src, ETH_ALEN);
+ os_memcpy(entry->pmkid, intro.pmkid, PMKID_LEN);
+ os_memcpy(entry->pmk, intro.pmk, intro.pmk_len);
+ entry->pmk_len = intro.pmk_len;
+ entry->akmp = WPA_KEY_MGMT_DPP;
+ if (expiry) {
+ os_get_time(&now);
+ seconds = expiry - now.sec;
+ } else {
+ seconds = 86400 * 7;
+ }
+
+ if (wpas_dpp_send_private_peer_intro_update(wpa_s, &intro, ssid, src,
+ freq) < 0) {
+ os_free(entry);
+ goto fail;
+ }
+
+ os_get_reltime(&rnow);
+ entry->expiration = rnow.sec + seconds;
+ entry->reauth_time = rnow.sec + seconds;
+ entry->network_ctx = ssid;
+ wpa_sm_pmksa_cache_add_entry(wpa_s->wpa, entry);
+
+ /* Association will be initiated from TX status handler for the Private
+ * Peer Intro Update: wpas_dpp_tx_priv_intro_status() */
+
+fail:
+ dpp_peer_intro_deinit(&intro);
+}
+
#endif /* CONFIG_DPP3 */
wpas_dpp_rx_pb_presence_announcement_resp(wpa_s, src, hdr,
buf, len, freq);
break;
+ case DPP_PA_PRIV_PEER_INTRO_NOTIFY:
+ wpas_dpp_rx_priv_peer_intro_notify(wpa_s, src, hdr,
+ buf, len, freq);
+ break;
#endif /* CONFIG_DPP3 */
default:
wpa_printf(MSG_DEBUG,
}
+#ifdef CONFIG_DPP3
+static int wpas_dpp_start_private_peer_intro(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ struct wpa_bss *bss)
+{
+ struct wpabuf *msg;
+ unsigned int wait_time;
+ size_t len;
+ u8 ver = DPP_VERSION;
+ int conn_ver;
+
+ len = 5 + 5;
+ msg = dpp_alloc_msg(DPP_PA_PRIV_PEER_INTRO_QUERY, len);
+ if (!msg)
+ return -1;
+
+ /* Transaction ID */
+ wpabuf_put_le16(msg, DPP_ATTR_TRANSACTION_ID);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, TRANSACTION_ID);
+
+ conn_ver = dpp_get_connector_version(ssid->dpp_connector);
+ if (conn_ver > 0 && ver != conn_ver) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Use Connector version %d instead of current protocol version %d",
+ conn_ver, ver);
+ ver = conn_ver;
+ }
+
+ /* Protocol Version */
+ wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION);
+ wpabuf_put_le16(msg, 1);
+ wpabuf_put_u8(msg, ver);
+
+ wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Private Peer Intro Query", msg);
+
+ /* TODO: Timeout on AP response */
+ wait_time = wpa_s->max_remain_on_chan;
+ if (wait_time > 2000)
+ wait_time = 2000;
+ wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d",
+ MAC2STR(bss->bssid), bss->freq, DPP_PA_PRIV_PEER_INTRO_QUERY);
+ offchannel_send_action(wpa_s, bss->freq, bss->bssid, wpa_s->own_addr,
+ broadcast,
+ wpabuf_head(msg), wpabuf_len(msg),
+ wait_time, wpas_dpp_tx_introduction_status, 0);
+ wpabuf_free(msg);
+
+ /* Request this connection attempt to terminate - new one will be
+ * started when network introduction protocol completes */
+ os_memcpy(wpa_s->dpp_intro_bssid, bss->bssid, ETH_ALEN);
+ wpa_s->dpp_intro_network = ssid;
+ return 1;
+}
+#endif /* CONFIG_DPP3 */
+
+
int wpas_dpp_check_connect(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
struct wpa_bss *bss)
{
}
wpa_printf(MSG_DEBUG,
- "DPP: Starting network introduction protocol to derive PMKSA for "
- MACSTR, MAC2STR(bss->bssid));
+ "DPP: Starting %snetwork introduction protocol to derive PMKSA for "
+ MACSTR,
+ ssid->dpp_connector_privacy ? "private " : "",
+ MAC2STR(bss->bssid));
if (wpa_s->wpa_state == WPA_SCANNING)
wpa_supplicant_set_state(wpa_s, wpa_s->scan_prev_wpa_state);
+#ifdef CONFIG_DPP3
+ if (ssid->dpp_connector_privacy)
+ return wpas_dpp_start_private_peer_intro(wpa_s, ssid, bss);
+#endif /* CONFIG_DPP3 */
+
len = 5 + 4 + os_strlen(ssid->dpp_connector);
#ifdef CONFIG_DPP2
len += 5;
# 2: do not allow PFS to be used
#dpp_pfs=0
+# DPP Network introduction type
+# 0: unprotected variant from DPP R1 (default)
+# 1: privacy protecting (station Connector encrypted) variant from
+# DPP R3
+#dpp_connector_privacy=0
+
# Whether beacon protection is enabled
# This depends on management frame protection (ieee80211w) being enabled and
# beacon protection support indication from the driver.
int dpp_gas_dialog_token;
u8 dpp_intro_bssid[ETH_ALEN];
void *dpp_intro_network;
+ u8 dpp_intro_peer_version;
struct dpp_pkex *dpp_pkex;
struct dpp_bootstrap_info *dpp_pkex_bi;
char *dpp_pkex_code;