DPP: Expose enrollee pubkey hash for identification

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>
This commit is contained in:
Michal Kazior 2021-05-11 10:56:17 +00:00 committed by Jouni Malinen
parent 2d8974e314
commit 043dedee83
12 changed files with 129 additions and 16 deletions

View file

@ -218,6 +218,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
{ {
int len, res, ret, i; int len, res, ret, i;
const char *keyid; const char *keyid;
const u8 *dpp_pkhash;
if (!sta) if (!sta)
return 0; return 0;
@ -386,6 +387,18 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
len += ret; len += ret;
} }
dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
if (dpp_pkhash) {
ret = os_snprintf(buf + len, buflen - len, "dpp_pkhash=");
if (!os_snprintf_error(buflen - len, ret))
len += ret;
len += wpa_snprintf_hex(buf + len, buflen - len, dpp_pkhash,
SHA256_MAC_LEN);
ret = os_snprintf(buf + len, buflen - len, "\n");
if (!os_snprintf_error(buflen - len, ret))
len += ret;
}
return len; return len;
} }

View file

@ -2051,6 +2051,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
os_time_t expire; os_time_t expire;
int expiration; int expiration;
enum dpp_status_error res; enum dpp_status_error res;
u8 pkhash[SHA256_MAC_LEN];
os_memset(&intro, 0, sizeof(intro)); os_memset(&intro, 0, sizeof(intro));
@ -2087,7 +2088,7 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
wpabuf_len(hapd->conf->dpp_netaccesskey), wpabuf_len(hapd->conf->dpp_netaccesskey),
wpabuf_head(hapd->conf->dpp_csign), wpabuf_head(hapd->conf->dpp_csign),
wpabuf_len(hapd->conf->dpp_csign), wpabuf_len(hapd->conf->dpp_csign),
connector, connector_len, &expire); connector, connector_len, &expire, pkhash);
if (res == 255) { if (res == 255) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in internal failure (peer " "DPP: Network Introduction protocol resulted in internal failure (peer "
@ -2132,9 +2133,9 @@ static void hostapd_dpp_rx_peer_disc_req(struct hostapd_data *hapd,
else else
expiration = 0; 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, 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"); wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
goto done; goto done;
} }
@ -2792,6 +2793,7 @@ hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src,
os_time_t expire; os_time_t expire;
int expiration; int expiration;
enum dpp_status_error res; enum dpp_status_error res;
u8 pkhash[SHA256_MAC_LEN];
os_memset(&intro, 0, sizeof(intro)); os_memset(&intro, 0, sizeof(intro));
@ -2869,7 +2871,7 @@ hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src,
wpabuf_len(hapd->conf->dpp_netaccesskey), wpabuf_len(hapd->conf->dpp_netaccesskey),
wpabuf_head(hapd->conf->dpp_csign), wpabuf_head(hapd->conf->dpp_csign),
wpabuf_len(hapd->conf->dpp_csign), wpabuf_len(hapd->conf->dpp_csign),
connector, connector_len, &expire); connector, connector_len, &expire, pkhash);
if (res == 255) { if (res == 255) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in internal failure (peer " "DPP: Network Introduction protocol resulted in internal failure (peer "
@ -2903,9 +2905,9 @@ hostapd_dpp_rx_priv_peer_intro_update(struct hostapd_data *hapd, const u8 *src,
else else
expiration = 0; 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, 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"); wpa_printf(MSG_ERROR, "DPP: Failed to add PMKSA cache entry");
goto done; goto done;
} }

View file

@ -40,6 +40,7 @@ static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{ {
os_free(entry->vlan_desc); os_free(entry->vlan_desc);
os_free(entry->identity); os_free(entry->identity);
os_free(entry->dpp_pkhash);
wpabuf_free(entry->cui); wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS #ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class); radius_free_class(&entry->radius_class);

View file

@ -23,6 +23,8 @@ struct rsn_pmksa_cache_entry {
int akmp; /* WPA_KEY_MGMT_* */ int akmp; /* WPA_KEY_MGMT_* */
u8 spa[ETH_ALEN]; u8 spa[ETH_ALEN];
u8 *dpp_pkhash; /* SHA256_MAC_LEN octet hash value of DPP Connector
* public key */
u8 *identity; u8 *identity;
size_t identity_len; size_t identity_len;
struct wpabuf *cui; struct wpabuf *cui;

View file

@ -1260,6 +1260,13 @@ const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
} }
const u8 * 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, void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized) int authorized)
{ {
@ -1298,10 +1305,13 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
sta->addr, authorized, dev_addr); sta->addr, authorized, dev_addr);
if (authorized) { if (authorized) {
const u8 *dpp_pkhash;
const char *keyid; const char *keyid;
char dpp_pkhash_buf[100];
char keyid_buf[100]; char keyid_buf[100];
char ip_addr[100]; char ip_addr[100];
dpp_pkhash_buf[0] = '\0';
keyid_buf[0] = '\0'; keyid_buf[0] = '\0';
ip_addr[0] = '\0'; ip_addr[0] = '\0';
#ifdef CONFIG_P2P #ifdef CONFIG_P2P
@ -1319,14 +1329,27 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
" keyid=%s", keyid); " keyid=%s", keyid);
} }
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s", dpp_pkhash = ap_sta_wpa_get_dpp_pkhash(hapd, sta);
buf, ip_addr, keyid_buf); if (dpp_pkhash) {
const char *prefix = " dpp_pkhash=";
size_t plen = os_strlen(prefix);
os_strlcpy(dpp_pkhash_buf, prefix,
sizeof(dpp_pkhash_buf));
wpa_snprintf_hex(&dpp_pkhash_buf[plen],
sizeof(dpp_pkhash_buf) - plen,
dpp_pkhash, SHA256_MAC_LEN);
}
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 && if (hapd->msg_ctx_parent &&
hapd->msg_ctx_parent != hapd->msg_ctx) hapd->msg_ctx_parent != hapd->msg_ctx)
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_CONNECTED "%s%s%s", AP_STA_CONNECTED "%s%s%s%s",
buf, ip_addr, keyid_buf); buf, ip_addr, keyid_buf,
dpp_pkhash_buf);
} else { } else {
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);

View file

@ -354,6 +354,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); 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, const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd,
struct sta_info *sta); struct sta_info *sta);
const u8 * 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, void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason); const u8 *addr, u16 reason);

View file

@ -4856,6 +4856,14 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len)
} }
const u8 * wpa_auth_get_dpp_pkhash(struct wpa_state_machine *sm)
{
if (!sm || !sm->pmksa)
return NULL;
return sm->pmksa->dpp_pkhash;
}
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
{ {
if (!sm) if (!sm)
@ -5018,6 +5026,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 u8 *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 (3)", 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)
entry->dpp_pkhash = os_memdup(dpp_pkhash, SHA256_MAC_LEN);
return 0;
}
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr) const u8 *sta_addr)
{ {

View file

@ -410,6 +410,7 @@ void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm); int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(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 u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len);
const u8 * 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_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(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); int wpa_auth_sta_ft_tk_already_set(struct wpa_state_machine *sm);
@ -435,6 +436,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, int wpa_auth_pmksa_add2(struct wpa_authenticator *wpa_auth, const u8 *addr,
const u8 *pmk, size_t pmk_len, const u8 *pmkid, const u8 *pmk, size_t pmk_len, const u8 *pmkid,
int session_timeout, int akmp); 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 u8 *dpp_pkhash);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr); const u8 *sta_addr);
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf, int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,

View file

@ -4141,7 +4141,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
const u8 *net_access_key, size_t net_access_key_len, const u8 *net_access_key, size_t net_access_key_len,
const u8 *csign_key, size_t csign_key_len, const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len, const u8 *peer_connector, size_t peer_connector_len,
os_time_t *expiry) os_time_t *expiry, u8 *peer_key_hash)
{ {
struct json_token *root = NULL, *netkey, *token; struct json_token *root = NULL, *netkey, *token;
struct json_token *own_root = NULL; struct json_token *own_root = NULL;
@ -4264,6 +4264,9 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
} }
#endif /* CONFIG_DPP3 */ #endif /* CONFIG_DPP3 */
if (peer_key_hash)
dpp_get_pubkey_hash(intro->peer_key, peer_key_hash);
ret = DPP_STATUS_OK; ret = DPP_STATUS_OK;
fail: fail:
if (ret != DPP_STATUS_OK) if (ret != DPP_STATUS_OK)
@ -5036,8 +5039,18 @@ void dpp_global_deinit(struct dpp_global *dpp)
void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator) void dpp_notify_auth_success(struct dpp_authentication *auth, int initiator)
{ {
wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_AUTH_SUCCESS "init=%d", u8 hash[SHA256_MAC_LEN];
initiator); char hex[SHA256_MAC_LEN * 2 + 1];
if (auth->peer_protocol_key) {
dpp_get_pubkey_hash(auth->peer_protocol_key, hash);
wpa_snprintf_hex(hex, sizeof(hex), hash, sizeof(hash));
} else {
hex[0] = '\0';
}
wpa_msg(auth->msg_ctx, MSG_INFO,
DPP_EVENT_AUTH_SUCCESS "init=%d pkhash=%s",
initiator, hex);
} }

View file

@ -669,7 +669,7 @@ dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
const u8 *net_access_key, size_t net_access_key_len, const u8 *net_access_key, size_t net_access_key_len,
const u8 *csign_key, size_t csign_key_len, const u8 *csign_key, size_t csign_key_len,
const u8 *peer_connector, size_t peer_connector_len, const u8 *peer_connector, size_t peer_connector_len,
os_time_t *expiry); os_time_t *expiry, u8 *peer_key_hash);
void dpp_peer_intro_deinit(struct dpp_introduction *intro); void dpp_peer_intro_deinit(struct dpp_introduction *intro);
int dpp_get_connector_version(const char *connector); int dpp_get_connector_version(const char *connector);
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi, struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
@ -853,6 +853,7 @@ struct dpp_reconfig_id * dpp_gen_reconfig_id(const u8 *csign_key,
size_t pp_key_len); size_t pp_key_len);
int dpp_update_reconfig_id(struct dpp_reconfig_id *id); int dpp_update_reconfig_id(struct dpp_reconfig_id *id);
void dpp_free_reconfig_id(struct dpp_reconfig_id *id); void dpp_free_reconfig_id(struct dpp_reconfig_id *id);
int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash);
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
#endif /* DPP_H */ #endif /* DPP_H */

View file

@ -246,6 +246,27 @@ struct crypto_ec_key * dpp_set_pubkey_point(struct crypto_ec_key *group_key,
} }
int dpp_get_pubkey_hash(struct crypto_ec_key *key, u8 *hash)
{
struct wpabuf *uncomp;
const u8 *addr[1];
size_t len[1];
int res;
if (!key)
return -1;
uncomp = crypto_ec_key_get_pubkey_point(key, 1);
if (!uncomp)
return -1;
addr[0] = wpabuf_head(uncomp);
len[0] = wpabuf_len(uncomp);
res = sha256_vector(1, addr, len, hash);
wpabuf_free(uncomp);
return res;
}
struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve) struct crypto_ec_key * dpp_gen_keypair(const struct dpp_curve_params *curve)
{ {
struct crypto_ec_key *key; struct crypto_ec_key *key;

View file

@ -2677,7 +2677,7 @@ static void wpas_dpp_rx_peer_disc_resp(struct wpa_supplicant *wpa_s,
ssid->dpp_netaccesskey_len, ssid->dpp_netaccesskey_len,
ssid->dpp_csign, ssid->dpp_csign,
ssid->dpp_csign_len, ssid->dpp_csign_len,
connector, connector_len, &expiry); connector, connector_len, &expiry, NULL);
if (res != DPP_STATUS_OK) { if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in failure"); "DPP: Network Introduction protocol resulted in failure");
@ -3830,7 +3830,7 @@ wpas_dpp_rx_priv_peer_intro_notify(struct wpa_supplicant *wpa_s,
ssid->dpp_netaccesskey_len, ssid->dpp_netaccesskey_len,
ssid->dpp_csign, ssid->dpp_csign,
ssid->dpp_csign_len, ssid->dpp_csign_len,
connector, connector_len, &expiry); connector, connector_len, &expiry, NULL);
if (res != DPP_STATUS_OK) { if (res != DPP_STATUS_OK) {
wpa_printf(MSG_INFO, wpa_printf(MSG_INFO,
"DPP: Network Introduction protocol resulted in failure"); "DPP: Network Introduction protocol resulted in failure");