From 0e3c16546b419fc95cd6c0e7131a9114c075f34b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 27 Jun 2012 22:15:55 +0300 Subject: [PATCH] WPS: Use separate list of NFC Password Tokens in the Registrar This adds a cleaner mechanism for handling NFC Password Tokens in the WPS Registrar. There could be more than one active NFC Password Token in use and as such, a list of tokens needs to be maintained. The old WPS_OOB interface is still using the old mechanism that supports only a single active NFC Password Token. Signed-hostap: Jouni Malinen --- src/wps/wps.c | 7 ++ src/wps/wps.h | 3 + src/wps/wps_i.h | 8 ++- src/wps/wps_registrar.c | 141 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 150 insertions(+), 9 deletions(-) diff --git a/src/wps/wps.c b/src/wps/wps.c index 64b80d808..26542a067 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -118,6 +118,12 @@ struct wps_data * wps_init(const struct wps_config *cfg) */ void wps_deinit(struct wps_data *data) { +#ifdef CONFIG_WPS_NFC + if (data->registrar && data->nfc_pw_token) + wps_registrar_remove_nfc_pw_token(data->wps->registrar, + data->nfc_pw_token); +#endif /* CONFIG_WPS_NFC */ + if (data->wps_pin_revealed) { wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and " "negotiation failed"); @@ -136,6 +142,7 @@ void wps_deinit(struct wps_data *data) wps_device_data_free(&data->peer_dev); os_free(data->new_ap_settings); dh5_free(data->dh_ctx); + os_free(data->nfc_pw_token); os_free(data); } diff --git a/src/wps/wps.h b/src/wps/wps.h index 66fccd754..927102f8c 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -797,6 +797,9 @@ int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr, char *buf, size_t buflen); int wps_registrar_config_ap(struct wps_registrar *reg, struct wps_credential *cred); +int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg, + const u8 *pubkey_hash, u16 pw_id, + const u8 *dev_pw, size_t dev_pw_len); int wps_registrar_add_nfc_password_token(struct wps_registrar *reg, const u8 *oob_dev_pw, size_t oob_dev_pw_len); diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index a50db3f1c..86ad248d3 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - internal definitions - * Copyright (c) 2008-2009, Jouni Malinen + * Copyright (c) 2008-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,8 @@ #include "wps.h" #include "wps_attr_parse.h" +struct wps_nfc_pw_token; + /** * struct wps_data - WPS registration protocol data * @@ -115,6 +117,8 @@ struct wps_data { u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or * 00:00:00:00:00:00 if not a P2p client */ int pbc_in_m1; + + struct wps_nfc_pw_token *nfc_pw_token; }; @@ -198,5 +202,7 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg); const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count); int wps_registrar_pbc_overlap(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e); +void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg, + struct wps_nfc_pw_token *token); #endif /* WPS_I_H */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 1bef660f6..154c2b4c3 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -26,6 +26,53 @@ #define WPS_WORKAROUNDS #endif /* CONFIG_WPS_STRICT */ +#ifdef CONFIG_WPS_NFC + +struct wps_nfc_pw_token { + struct dl_list list; + u8 pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN]; + u16 pw_id; + u8 dev_pw[WPS_OOB_DEVICE_PASSWORD_LEN]; + size_t dev_pw_len; +}; + + +static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token) +{ + dl_list_del(&token->list); + os_free(token); +} + + +static void wps_free_nfc_pw_tokens(struct dl_list *tokens, u16 pw_id) +{ + struct wps_nfc_pw_token *token, *prev; + dl_list_for_each_safe(token, prev, tokens, struct wps_nfc_pw_token, + list) { + if (pw_id == 0 || pw_id == token->pw_id) + wps_remove_nfc_pw_token(token); + } +} + + +static struct wps_nfc_pw_token * wps_get_nfc_pw_token(struct dl_list *tokens, + u16 pw_id) +{ + struct wps_nfc_pw_token *token; + dl_list_for_each(token, tokens, struct wps_nfc_pw_token, list) { + if (pw_id == token->pw_id) + return token; + } + return NULL; +} + +#else /* CONFIG_WPS_NFC */ + +#define wps_free_nfc_pw_tokens(t, p) do { } while (0) + +#endif /* CONFIG_WPS_NFC */ + + struct wps_uuid_pin { struct dl_list list; u8 uuid[WPS_UUID_LEN]; @@ -113,6 +160,7 @@ struct wps_registrar { void *cb_ctx; struct dl_list pins; + struct dl_list nfc_pw_tokens; struct wps_pbc_session *pbc_sessions; int skip_cred_build; @@ -591,6 +639,7 @@ wps_registrar_init(struct wps_context *wps, return NULL; dl_list_init(®->pins); + dl_list_init(®->nfc_pw_tokens); reg->wps = wps; reg->new_psk_cb = cfg->new_psk_cb; reg->set_ie_cb = cfg->set_ie_cb; @@ -634,6 +683,7 @@ void wps_registrar_deinit(struct wps_registrar *reg) eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); wps_free_pins(®->pins); + wps_free_nfc_pw_tokens(®->nfc_pw_tokens, 0); wps_free_pbc_sessions(reg->pbc_sessions); wpabuf_free(reg->extra_cred); wps_free_devices(reg->devices); @@ -1255,6 +1305,13 @@ static int wps_get_dev_password(struct wps_data *wps) wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC"); pin = (const u8 *) "00000000"; pin_len = 8; +#ifdef CONFIG_WPS_NFC + } else if (wps->nfc_pw_token) { + wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC " + "Password Token"); + pin = wps->nfc_pw_token->dev_pw; + pin_len = wps->nfc_pw_token->dev_pw_len; +#endif /* CONFIG_WPS_NFC */ } else { pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e, &pin_len); @@ -2441,8 +2498,34 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps, return WPS_CONTINUE; } +#ifdef CONFIG_WPS_NFC + if (wps->dev_pw_id >= 0x10) { + struct wps_nfc_pw_token *token; + const u8 *addr[1]; + u8 hash[WPS_HASH_LEN]; + + token = wps_get_nfc_pw_token( + &wps->wps->registrar->nfc_pw_tokens, wps->dev_pw_id); + if (token) { + wpa_printf(MSG_DEBUG, "WPS: Found matching NFC " + "Password Token"); + dl_list_del(&token->list); + wps->nfc_pw_token = token; + + addr[0] = attr->public_key; + sha256_vector(1, addr, &attr->public_key_len, hash); + if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN) != 0) { + wpa_printf(MSG_ERROR, "WPS: Public Key hash " + "mismatch"); + return WPS_FAILURE; + } + } + } +#endif /* CONFIG_WPS_NFC */ + #ifdef CONFIG_WPS_OOB - if (wps->dev_pw_id >= 0x10 && + if (wps->dev_pw_id >= 0x10 && wps->nfc_pw_token == NULL && wps->dev_pw_id != wps->wps->oob_dev_pw_id) { wpa_printf(MSG_DEBUG, "WPS: OOB Device Password ID " "%d mismatch", wps->dev_pw_id); @@ -3369,6 +3452,43 @@ int wps_registrar_config_ap(struct wps_registrar *reg, #ifdef CONFIG_WPS_NFC + +int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg, + const u8 *pubkey_hash, u16 pw_id, + const u8 *dev_pw, size_t dev_pw_len) +{ + struct wps_nfc_pw_token *token; + + if (dev_pw_len > WPS_OOB_DEVICE_PASSWORD_LEN) + return -1; + + wps_free_nfc_pw_tokens(®->nfc_pw_tokens, pw_id); + + token = os_zalloc(sizeof(*token)); + if (token == NULL) + return -1; + + os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); + token->pw_id = pw_id; + os_memcpy(token->dev_pw, dev_pw, dev_pw_len); + token->dev_pw_len = dev_pw_len; + + dl_list_add(®->nfc_pw_tokens, &token->list); + + reg->selected_registrar = 1; + reg->pbc = 0; + wps_registrar_add_authorized_mac(reg, + (u8 *) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); + eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL); + eloop_register_timeout(WPS_PBC_WALK_TIME, 0, + wps_registrar_set_selected_timeout, + reg, NULL); + + return 0; +} + + int wps_registrar_add_nfc_password_token(struct wps_registrar *reg, const u8 *oob_dev_pw, size_t oob_dev_pw_len) @@ -3396,12 +3516,17 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg, hash, WPS_OOB_PUBKEY_HASH_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len); - reg->wps->oob_dev_pw_id = id; - wpabuf_free(reg->wps->oob_conf.pubkey_hash); - reg->wps->oob_conf.pubkey_hash = wpabuf_alloc_copy( - hash, WPS_OOB_PUBKEY_HASH_LEN); - if (reg->wps->oob_conf.pubkey_hash == NULL) - return -1; - return wps_registrar_add_pin(reg, NULL, NULL, dev_pw, dev_pw_len, 300); + return wps_registrar_add_nfc_pw_token(reg, hash, id, dev_pw, + dev_pw_len); } + + +void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg, + struct wps_nfc_pw_token *token) +{ + wps_registrar_remove_authorized_mac(reg, + (u8 *) "\xff\xff\xff\xff\xff\xff"); + wps_registrar_selected_registrar_changed(reg); +} + #endif /* CONFIG_WPS_NFC */