diff mbox series

[PATCHv3,2/3] DPP: expose enrollee pubkey hash for identification

Message ID 20210511105618.72497-2-kazikcz@gmail.com
State New
Headers show
Series [PATCHv3,1/3] DPP: move DPP_EVENT_AUTH_SUCCESS to a helper | expand

Commit Message

Michal Kazior May 11, 2021, 10:56 a.m. UTC
From: Michal Kazior <michal@plume.com>

Just like with WPA-PSK and keyids it may be
desired to identify connecting clients to provide
additional network filtering.

This does:

 - extend DPP_EVENT_AUTH_SUCCESS to expose public
   key hash of the peer so the system can pick it
   up and use for identification later

 - store public key hash in PMKSA from DPP Network
   Intro for later use

 - extend sta mib to print out the dpp_pkhash
   from PMKSA if present

 - extend AP_STA_CONNECTED to include the
   dpp_pkhash from PMKSA if present

Signed-off-by: Michal Kazior <michal@plume.com>
---

Notes:
    v3:
     - remove unnecessary empty newline in dpp_auth.c
     - fix memleak of peer_key after dpp_peer_intro()
       by making it hand over the pkhash instead of
       key (this also avoids openssl code in
       dpp_hostapd.c)
     - dont duplicate dpp_pkhash string if its 0
       length so that NULL checks can actually skip
       some logic
    
    v2:
     - fixed type warnings (char vs u8)
     - dropped "hostap" salt for the pkhash
     - dropped DPP_EVENT_AUTH_PK_HASH and reused
       DPP_EVENT_AUTH_SUCCESS (as a result this fixed
       some cases where PK_HASH wasn't signalled as
       expected)
     - adjusted commit log

 src/ap/ctrl_iface_ap.c          |  8 +++++++
 src/ap/dpp_hostapd.c            |  8 ++++---
 src/ap/pmksa_cache_auth.c       |  1 +
 src/ap/pmksa_cache_auth.h       |  1 +
 src/ap/sta_info.c               | 24 +++++++++++++++++----
 src/ap/sta_info.h               |  2 ++
 src/ap/wpa_auth.c               | 33 +++++++++++++++++++++++++++++
 src/ap/wpa_auth.h               |  4 ++++
 src/common/dpp.c                | 15 ++++++++++---
 src/common/dpp.h                |  4 +++-
 src/common/dpp_crypto.c         | 37 +++++++++++++++++++++++++++++++++
 wpa_supplicant/dpp_supplicant.c |  2 +-
 12 files changed, 127 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 28e40ba9c..e663a60cb 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -208,6 +208,7 @@  static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 {
 	int len, res, ret, i;
 	const char *keyid;
+	const char *dpp_pkhash;
 
 	if (!sta)
 		return 0;
@@ -377,6 +378,13 @@  static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
 			len += ret;
 	}
 
+	dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
+	if (dpp_pkhash) {
+		ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=%s\n", dpp_pkhash);
+		if (!os_snprintf_error(buflen - len, ret))
+			len += ret;
+	}
+
 	return len;
 }
 
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index f0b4bc034..46b031003 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -1587,6 +1587,7 @@  static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 	os_time_t expire;
 	int expiration;
 	enum dpp_status_error res;
+	char pkhash[SHA256_MAC_LEN*2 + 1];
 
 	wpa_printf(MSG_DEBUG, "DPP: Peer Discovery Request from " MACSTR,
 		   MAC2STR(src));
@@ -1631,7 +1632,8 @@  static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 			     wpabuf_len(hapd->conf->dpp_netaccesskey),
 			     wpabuf_head(hapd->conf->dpp_csign),
 			     wpabuf_len(hapd->conf->dpp_csign),
-			     connector, connector_len, &expire);
+			     connector, connector_len, &expire,
+			     pkhash, sizeof(pkhash));
 	if (res == 255) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Network Introduction protocol resulted in internal failure (peer "
@@ -1654,9 +1656,9 @@  static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
 	else
 		expiration = 0;
 
-	if (wpa_auth_pmksa_add2(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
+	if (wpa_auth_pmksa_add3(hapd->wpa_auth, src, intro.pmk, intro.pmk_len,
 				intro.pmkid, expiration,
-				WPA_KEY_MGMT_DPP) < 0) {
+				WPA_KEY_MGMT_DPP, pkhash) < 0) {
 		wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
 		return;
 	}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index fe5f81717..29d2b500a 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -40,6 +40,7 @@  static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
 {
 	os_free(entry->vlan_desc);
 	os_free(entry->identity);
+	os_free(entry->dpp_pkhash);
 	wpabuf_free(entry->cui);
 #ifndef CONFIG_NO_RADIUS
 	radius_free_class(&entry->radius_class);
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 2ef217435..59e7e698f 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -23,6 +23,7 @@  struct rsn_pmksa_cache_entry {
 	int akmp; /* WPA_KEY_MGMT_* */
 	u8 spa[ETH_ALEN];
 
+	char *dpp_pkhash;
 	u8 *identity;
 	size_t identity_len;
 	struct wpabuf *cui;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index ccd1ed931..9a80efd4d 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1260,6 +1260,13 @@  const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
 }
 
 
+const char * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	return wpa_auth_get_dpp_pkhash(sta->wpa_sm);
+}
+
+
 void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 			   int authorized)
 {
@@ -1298,10 +1305,13 @@  void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 					sta->addr, authorized, dev_addr);
 
 	if (authorized) {
+		const char *dpp_pkhash;
 		const char *keyid;
+		char dpp_pkhash_buf[100];
 		char keyid_buf[100];
 		char ip_addr[100];
 
+		dpp_pkhash_buf[0] = '\0';
 		keyid_buf[0] = '\0';
 		ip_addr[0] = '\0';
 #ifdef CONFIG_P2P
@@ -1319,14 +1329,20 @@  void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 				    " keyid=%s", keyid);
 		}
 
-		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s",
-			buf, ip_addr, keyid_buf);
+		dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
+		if (dpp_pkhash) {
+			os_snprintf(dpp_pkhash_buf, sizeof(dpp_pkhash_buf),
+				    " dpp_pkhash=%s", dpp_pkhash);
+		}
+
+		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s%s",
+			buf, ip_addr, keyid_buf, dpp_pkhash_buf);
 
 		if (hapd->msg_ctx_parent &&
 		    hapd->msg_ctx_parent != hapd->msg_ctx)
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
-					  AP_STA_CONNECTED "%s%s%s",
-					  buf, ip_addr, keyid_buf);
+					  AP_STA_CONNECTED "%s%s%s%s",
+					  buf, ip_addr, keyid_buf, dpp_pkhash_buf);
 	} else {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
 
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 27e72f9a0..254e4f39f 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -385,6 +385,8 @@  void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
 int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
 const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
 				  struct sta_info *sta);
+const char * ap_sta_wpa_get_dpp_pkhash(struct hostapd_data *hapd,
+				       struct sta_info *sta);
 void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
 		       const u8 *addr, u16 reason);
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 59cd46aa4..f6575acdb 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -4681,6 +4681,16 @@  const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
 }
 
 
+const char * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm)
+{
+	if (!sm)
+		return NULL;
+	if (!sm->pmksa)
+		return NULL;
+	return sm->pmksa->dpp_pkhash;
+}
+
+
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
 {
 	if (!sm)
@@ -4842,6 +4852,29 @@  int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 }
 
 
+int wpa_auth_pmksa_add3(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+			int session_timeout, int akmp, const char *dpp_pkhash)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	if (wpa_auth->conf.disable_pmksa_caching)
+		return -1;
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK (2)", pmk, PMK_LEN);
+	entry = pmksa_cache_auth_add(wpa_auth->pmksa, pmk, pmk_len, pmkid,
+				 NULL, 0, wpa_auth->addr, addr, session_timeout,
+				 NULL, akmp);
+	if (!entry)
+		return -1;
+
+	if (dpp_pkhash && os_strlen(dpp_pkhash) > 0)
+		entry->dpp_pkhash = os_strdup(dpp_pkhash);
+
+	return 0;
+}
+
+
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index eaa2cafc8..7dc80fded 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -401,6 +401,7 @@  void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
 int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
 int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
 const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
+const char * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm);
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
 int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
 int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
@@ -425,6 +426,9 @@  void wpa_auth_add_sae_pmkid(struct wpa_state_machine *sm, const u8 *pmkid);
 int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
 			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
 			int session_timeout, int akmp);
+int wpa_auth_pmksa_add3(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+			int session_timeout, int akmp, const char *dpp_pkhash);
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr);
 int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
diff --git a/src/common/dpp.c b/src/common/dpp.c
index 847e77c81..56c442d6d 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -3665,7 +3665,8 @@  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)
+	       os_time_t *expiry,
+	       char *peer_key_hash, size_t peer_key_hash_len)
 {
 	struct json_token *root = NULL, *netkey, *token;
 	struct json_token *own_root = NULL;
@@ -3770,6 +3771,9 @@  dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
 		goto fail;
 	}
 
+	if (peer_key_hash)
+		dpp_get_pubkey_hash(peer_key, peer_key_hash, peer_key_hash_len);
+
 	ret = DPP_STATUS_OK;
 fail:
 	if (ret != DPP_STATUS_OK)
@@ -4393,8 +4397,13 @@  void dpp_global_deinit(struct dpp_global *dpp)
 
 void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
 {
-	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d",
-		initiator);
+	char hex[SHA256_MAC_LEN*2 + 1];
+
+	os_memset(hex, 0, sizeof(hex));
+	dpp_get_pubkey_hash(auth->peer_protocol_key, hex, sizeof(hex));
+
+	wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s",
+		initiator, hex);
 }
 
 
diff --git a/src/common/dpp.h b/src/common/dpp.h
index ba2ef53de..fffb7a37f 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -594,7 +594,8 @@  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);
+	       os_time_t *expiry,
+	       char *peer_key_hash, size_t peer_key_hash_len);
 struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
 				const u8 *own_mac,
 				const char *identifier,
@@ -732,6 +733,7 @@  struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
 					     size_t pp_key_len);
 int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
 void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
+int dpp_get_pubkey_hash(EVP_PKEY *key, char *hexstr, size_t len);
 
 #endif /* CONFIG_DPP */
 #endif /* DPP_H */
diff --git a/src/common/dpp_crypto.c b/src/common/dpp_crypto.c
index c75fc7871..c1e6c43ee 100644
--- a/src/common/dpp_crypto.c
+++ b/src/common/dpp_crypto.c
@@ -520,6 +520,43 @@  EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, const u8 *buf, size_t len)
 }
 
 
+int dpp_get_pubkey_hash(EVP_PKEY *key, char *hexstr, size_t len)
+{
+	unsigned char *der = NULL;
+	const u8 *args[1];
+	size_t lens[1];
+	u8 buf[SHA256_MAC_LEN];
+	EC_KEY *eckey;
+	int der_len;
+	int res = 0;
+
+	os_memset(buf, 0, sizeof(buf));
+	os_memset(hexstr, 0, len);
+
+	if (!key)
+		return -1;
+
+	eckey = EVP_PKEY_get1_EC_KEY(key);
+	if (!eckey)
+		return -1;
+
+	der_len = i2d_EC_PUBKEY(eckey, &der);
+	if (der_len > 0) {
+		args[0] = der;
+		lens[0] = der_len;
+
+		if (sha256_vector(1, args, lens, buf) < 0)
+			res = -1;
+
+	}
+	OPENSSL_free(der);
+	EC_KEY_free(eckey);
+
+	wpa_snprintf_hex(hexstr, len, buf, sizeof(buf));
+	return res;
+}
+
+
 EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve)
 {
 	EVP_PKEY_CTX *kctx = NULL;
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index 289c60bc8..b0a11bc4d 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -2437,7 +2437,7 @@  static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
 			     ssid->dpp_netaccesskey_len,
 			     ssid->dpp_csign,
 			     ssid->dpp_csign_len,
-			     connector, connector_len, &expiry);
+			     connector, connector_len, &expiry, NULL, 0);
 	if (res != DPP_STATUS_OK) {
 		wpa_printf(MSG_INFO,
 			   "DPP: Network Introduction protocol resulted in failure");