pasn->send_mgmt = p2p->cfg->pasn_send_mgmt;
pasn->prepare_data_element = p2p->cfg->prepare_data_element;
pasn->parse_data_element = p2p->cfg->parse_data_element;
+ pasn->validate_custom_pmkid = p2p->cfg->pasn_validate_pmkid;
pasn->freq = freq;
}
struct wpabuf *extra_ies, *req;
int ret = 0;
u8 *pasn_extra_ies = NULL;
+ u8 pmkid[PMKID_LEN];
if (!peer_addr) {
p2p_dbg(p2p, "Peer address NULL");
return -1;
}
+ if (os_get_random(pmkid, PMKID_LEN) < 0) {
+ wpabuf_free(req);
+ wpabuf_free(extra_ies);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG,
+ "P2P2: Use new random PMKID for pairing verification",
+ pmkid, PMKID_LEN);
+ pasn_set_custom_pmkid(pasn, pmkid);
+
if (p2p_prepare_pasn_extra_ie(p2p, extra_ies, req, true)) {
p2p_dbg(p2p, "Prepare PASN extra IEs failed");
ret = -1;
derive_kek);
wpabuf_free(dev->action_frame_wrapper);
dev->action_frame_wrapper = resp;
+ if (msg.dira && msg.dira_len &&
+ p2p_validate_dira(p2p, dev, msg.dira,
+ msg.dira_len)) {
+ struct wpa_ie_data rsn_data;
+
+ if (wpa_parse_wpa_ie_rsn(elems.rsn_ie - 2,
+ elems.rsn_ie_len + 2,
+ &rsn_data) == 0 &&
+ rsn_data.num_pmkid)
+ pasn_set_custom_pmkid(dev->pasn,
+ rsn_data.pmkid);
+ }
} else if (data && data_len >= 1 && data[0] == P2P_GO_NEG_REQ) {
struct wpabuf *resp;
}
+static int p2p_validate_custom_pmkid(struct p2p_data *p2p,
+ struct p2p_device *dev, const u8 *pmkid)
+{
+ if (dev->pasn->custom_pmkid_valid &&
+ os_memcmp(dev->pasn->custom_pmkid, pmkid, PMKID_LEN) == 0) {
+ p2p_dbg(p2p, "Customized PMKID valid");
+ return 0;
+ }
+ return -1;
+}
+
+
+static int p2p_pasn_pmksa_get_pmk(struct p2p_data *p2p, const u8 *addr,
+ u8 *pmkid, u8 *pmk, size_t *pmk_len)
+{
+ struct p2p_device *dev;
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev) {
+ p2p_dbg(p2p, "PASN: Peer not found " MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ if (dev->role == P2P_ROLE_PAIRING_INITIATOR)
+ return pasn_initiator_pmksa_cache_get(p2p->initiator_pmksa,
+ addr, pmkid, pmk,
+ pmk_len);
+ else
+ return pasn_responder_pmksa_cache_get(p2p->responder_pmksa,
+ addr, pmkid, pmk,
+ pmk_len);
+}
+
+
+int p2p_pasn_validate_and_update_pmkid(struct p2p_data *p2p, const u8 *addr,
+ const u8 *rsn_pmkid)
+{
+ size_t pmk_len;
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN_MAX];
+ struct p2p_device *dev;
+
+ if (!p2p)
+ return -1;
+
+ dev = p2p_get_device(p2p, addr);
+ if (!dev || !dev->pasn) {
+ p2p_dbg(p2p, "P2P PASN: Peer not found " MACSTR,
+ MAC2STR(addr));
+ return -1;
+ }
+
+ if (p2p_validate_custom_pmkid(p2p, dev, rsn_pmkid))
+ return -1;
+
+ if (p2p_pasn_pmksa_get_pmk(p2p, addr, pmkid, pmk, &pmk_len)) {
+ p2p_dbg(p2p, "P2P PASN: Failed to get PMK from cache");
+ return -1;
+ }
+
+ p2p_pasn_pmksa_set_pmk(p2p, p2p->cfg->dev_addr, addr, pmk, pmk_len,
+ rsn_pmkid);
+ return 0;
+}
+
+
int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
size_t data_len, bool acked, bool verify)
{
pasn->frame = NULL;
pasn_register_callbacks(pasn, p2p->cfg->cb_ctx,
- p2p->cfg->pasn_send_mgmt, NULL);
+ p2p->cfg->pasn_send_mgmt,
+ p2p->cfg->pasn_validate_pmkid);
auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
if (dev->role == P2P_ROLE_PAIRING_INITIATOR && auth_transaction == 2) {
* Returns: 0 on success, -1 on failure
*/
int (*parse_data_element)(void *ctx, const u8 *data, size_t len);
+
+ /**
+ * pasn_validate_pmkid - Function handler to validate RSN PMKID
+ * @ctx: Callback context from cb_ctx
+ * @addr: Peer MAC address
+ * @pmkid: PMKID in the PASN frame
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*pasn_validate_pmkid)(void *ctx, const u8 *addr, const u8 *pmkid);
};
size_t len, int freq);
int p2p_prepare_data_element(struct p2p_data *p2p, const u8 *peer_addr);
int p2p_parse_data_element(struct p2p_data *p2p, const u8 *data, size_t len);
+int p2p_pasn_validate_and_update_pmkid(struct p2p_data *p2p, const u8 *addr,
+ const u8 *pmkid);
int p2p_pasn_auth_tx_status(struct p2p_data *p2p, const u8 *data,
size_t data_len, bool acked, bool verify);
int p2p_config_sae_password(struct p2p_data *p2p, const char *pw);