diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2012-07-19 12:16:46 -0700 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2012-07-19 16:03:19 -0700 |
commit | 04949598a23f501be6eec21697465fd46a28840a (patch) | |
tree | 6eb315b8d139b0690cb644dc914c53bacb42df42 /src/wps | |
parent | ce1e0634ed741293de60d5ba3476b26ccbd58ce2 (diff) | |
download | android_external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.tar.gz android_external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.tar.bz2 android_external_wpa_supplicant_8-04949598a23f501be6eec21697465fd46a28840a.zip |
wpa_supplicant: Update to 07-Jul-2012 TOT
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date: Sat Jul 7 13:01:45 2012 +0300
WPS SSDP: Fix socket leaks on error paths
Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/wps')
-rw-r--r-- | src/wps/ndef.c | 41 | ||||
-rw-r--r-- | src/wps/wps.c | 32 | ||||
-rw-r--r-- | src/wps/wps.h | 39 | ||||
-rw-r--r-- | src/wps/wps_attr_build.c | 43 | ||||
-rw-r--r-- | src/wps/wps_attr_parse.c | 9 | ||||
-rw-r--r-- | src/wps/wps_attr_parse.h | 107 | ||||
-rw-r--r-- | src/wps/wps_common.c | 132 | ||||
-rw-r--r-- | src/wps/wps_defs.h | 2 | ||||
-rw-r--r-- | src/wps/wps_dev_attr.c | 14 | ||||
-rw-r--r-- | src/wps/wps_dev_attr.h | 1 | ||||
-rw-r--r-- | src/wps/wps_enrollee.c | 3 | ||||
-rw-r--r-- | src/wps/wps_er.c | 40 | ||||
-rw-r--r-- | src/wps/wps_i.h | 110 | ||||
-rw-r--r-- | src/wps/wps_nfc.c | 12 | ||||
-rw-r--r-- | src/wps/wps_nfc_pn531.c | 12 | ||||
-rw-r--r-- | src/wps/wps_registrar.c | 213 | ||||
-rw-r--r-- | src/wps/wps_ufd.c | 16 | ||||
-rw-r--r-- | src/wps/wps_upnp.c | 66 | ||||
-rw-r--r-- | src/wps/wps_upnp_ssdp.c | 7 |
19 files changed, 661 insertions, 238 deletions
diff --git a/src/wps/ndef.c b/src/wps/ndef.c index 9baec7f4..7630ecbc 100644 --- a/src/wps/ndef.c +++ b/src/wps/ndef.c @@ -1,16 +1,10 @@ /* * NDEF(NFC Data Exchange Format) routines for Wi-Fi Protected Setup * Reference is "NFCForum-TS-NDEF_1.0 2006-07-24". - * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp> + * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -26,9 +20,9 @@ #define FLAG_TNF_RFC2046 (0x02) struct ndef_record { - u8 *type; - u8 *id; - u8 *payload; + const u8 *type; + const u8 *id; + const u8 *payload; u8 type_length; u8 id_length; u32 payload_length; @@ -37,9 +31,10 @@ struct ndef_record { static char wifi_handover_type[] = "application/vnd.wfa.wsc"; -static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record) +static int ndef_parse_record(const u8 *data, u32 size, + struct ndef_record *record) { - u8 *pos = data + 1; + const u8 *pos = data + 1; if (size < 2) return -1; @@ -78,12 +73,12 @@ static int ndef_parse_record(u8 *data, u32 size, struct ndef_record *record) } -static struct wpabuf * ndef_parse_records(struct wpabuf *buf, +static struct wpabuf * ndef_parse_records(const struct wpabuf *buf, int (*filter)(struct ndef_record *)) { struct ndef_record record; int len = wpabuf_len(buf); - u8 *data = wpabuf_mhead(buf); + const u8 *data = wpabuf_head(buf); while (len > 0) { if (ndef_parse_record(data, len, &record) < 0) { @@ -103,13 +98,14 @@ static struct wpabuf * ndef_parse_records(struct wpabuf *buf, static struct wpabuf * ndef_build_record(u8 flags, void *type, u8 type_length, void *id, - u8 id_length, void *payload, - u32 payload_length) + u8 id_length, + const struct wpabuf *payload) { struct wpabuf *record; size_t total_len; int short_record; u8 local_flag; + size_t payload_length = wpabuf_len(payload); short_record = payload_length < 256 ? 1 : 0; @@ -144,7 +140,7 @@ static struct wpabuf * ndef_build_record(u8 flags, void *type, wpabuf_put_u8(record, id_length); wpabuf_put_data(record, type, type_length); wpabuf_put_data(record, id, id_length); - wpabuf_put_data(record, payload, payload_length); + wpabuf_put_buf(record, payload); return record; } @@ -160,16 +156,15 @@ static int wifi_filter(struct ndef_record *record) } -struct wpabuf * ndef_parse_wifi(struct wpabuf *buf) +struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf) { return ndef_parse_records(buf, wifi_filter); } -struct wpabuf * ndef_build_wifi(struct wpabuf *buf) +struct wpabuf * ndef_build_wifi(const struct wpabuf *buf) { return ndef_build_record(FLAG_MESSAGE_BEGIN | FLAG_MESSAGE_END | FLAG_TNF_RFC2046, wifi_handover_type, - os_strlen(wifi_handover_type), NULL, 0, - wpabuf_mhead(buf), wpabuf_len(buf)); + os_strlen(wifi_handover_type), NULL, 0, buf); } diff --git a/src/wps/wps.c b/src/wps/wps.c index 9422c713..5453962a 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -56,6 +56,23 @@ struct wps_data * wps_init(const struct wps_config *cfg) data->dev_password_len = cfg->pin_len; } +#ifdef CONFIG_WPS_NFC + if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) { + data->dev_pw_id = cfg->wps->ap_nfc_dev_pw_id; + os_free(data->dev_password); + data->dev_password = + os_malloc(wpabuf_len(cfg->wps->ap_nfc_dev_pw)); + if (data->dev_password == NULL) { + os_free(data); + return NULL; + } + os_memcpy(data->dev_password, + wpabuf_head(cfg->wps->ap_nfc_dev_pw), + wpabuf_len(cfg->wps->ap_nfc_dev_pw)); + data->dev_password_len = wpabuf_len(cfg->wps->ap_nfc_dev_pw); + } +#endif /* CONFIG_WPS_NFC */ + data->pbc = cfg->pbc; if (cfg->pbc) { /* Use special PIN '00000000' for PBC */ @@ -118,6 +135,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 +159,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); } @@ -431,7 +455,8 @@ struct wpabuf * wps_build_assoc_resp_ie(void) /** * wps_build_probe_req_ie - Build WPS IE for Probe Request - * @pbc: Whether searching for PBC mode APs + * @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for + * most other use cases) * @dev: Device attributes * @uuid: Own UUID * @req_type: Value for Request Type attribute @@ -442,7 +467,7 @@ struct wpabuf * wps_build_assoc_resp_ie(void) * * The caller is responsible for freeing the buffer. */ -struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, +struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, const u8 *uuid, enum wps_request_type req_type, unsigned int num_req_dev_types, @@ -464,8 +489,7 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, wps_build_rf_bands(dev, ie) || wps_build_assoc_state(NULL, ie) || wps_build_config_error(ie, WPS_CFG_NO_ERROR) || - wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : - DEV_PW_DEFAULT) || + wps_build_dev_password_id(ie, pw_id) || #ifdef CONFIG_WPS2 wps_build_manufacturer(dev, ie) || wps_build_model_name(dev, ie) || diff --git a/src/wps/wps.h b/src/wps/wps.h index 22e029fb..c45b68cf 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -27,6 +27,7 @@ enum wsc_op_code { struct wps_registrar; struct upnp_wps_device_sm; struct wps_er; +struct wps_parse_attr; /** * struct wps_credential - WPS Credential @@ -94,6 +95,7 @@ struct wps_device_data { u32 os_version; u8 rf_bands; u16 config_methods; + struct wpabuf *vendor_ext_m1; struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; int p2p; @@ -238,7 +240,7 @@ int wps_is_20(const struct wpabuf *msg); struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type); struct wpabuf * wps_build_assoc_resp_ie(void); -struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, +struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev, const u8 *uuid, enum wps_request_type req_type, unsigned int num_req_dev_types, @@ -294,12 +296,15 @@ struct wps_registrar_config { * @ctx: Higher layer context data (cb_ctx) * @mac_addr: MAC address of the Enrollee * @uuid_e: UUID-E of the Enrollee + * @dev_pw: Device Password (PIN) used during registration + * @dev_pw_len: Length of dev_pw in octets * * This callback is called whenever an Enrollee completes registration * successfully. */ void (*reg_success_cb)(void *ctx, const u8 *mac_addr, - const u8 *uuid_e); + const u8 *uuid_e, const u8 *dev_pw, + size_t dev_pw_len); /** * set_sel_reg_cb - Callback for reporting selected registrar changes @@ -752,6 +757,11 @@ struct wps_context { /* Pending messages from UPnP PutWLANResponse */ struct upnp_pending_message *upnp_msgs; + + u16 ap_nfc_dev_pw_id; + struct wpabuf *ap_nfc_dh_pubkey; + struct wpabuf *ap_nfc_dh_privkey; + struct wpabuf *ap_nfc_dev_pw; }; struct oob_device_data { @@ -783,7 +793,8 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg); int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid); int wps_registrar_button_pushed(struct wps_registrar *reg, const u8 *p2p_dev_addr); -void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e); +void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, + const u8 *dev_pw, size_t dev_pw_len); void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, const struct wpabuf *wps_data, int p2p_wildcard); @@ -792,6 +803,12 @@ 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); int wps_build_credential_wrap(struct wpabuf *msg, const struct wps_credential *cred); @@ -799,6 +816,7 @@ int wps_build_credential_wrap(struct wpabuf *msg, unsigned int wps_pin_checksum(unsigned int pin); unsigned int wps_pin_valid(unsigned int pin); unsigned int wps_generate_pin(void); +int wps_pin_str_valid(const char *pin); void wps_free_pending_msgs(struct upnp_pending_message *msgs); struct oob_device_data * wps_get_oob_device(char *device_type); @@ -806,6 +824,8 @@ struct oob_nfc_device_data * wps_get_oob_nfc_device(char *device_name); int wps_get_oob_method(char *method); int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, int registrar); +struct wpabuf * wps_get_oob_cred(struct wps_context *wps); +int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr); int wps_attr_text(struct wpabuf *data, char *buf, char *end); struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname, @@ -821,12 +841,23 @@ int wps_er_set_config(struct wps_er *er, const u8 *uuid, const struct wps_credential *cred); int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, size_t pin_len, const struct wps_credential *cred); +struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid); int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]); char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf, size_t buf_len); void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid); u16 wps_config_methods_str2bin(const char *str); +struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, + const struct wpabuf *pubkey, + const struct wpabuf *dev_pw); +struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, + struct wpabuf **privkey, + struct wpabuf **dev_pw); + +/* ndef.c */ +struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf); +struct wpabuf * ndef_build_wifi(const struct wpabuf *buf); #ifdef CONFIG_WPS_STRICT int wps_validate_beacon(const struct wpabuf *wps_ie); diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index 753083d7..9be30b98 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -30,6 +30,14 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) wps->dh_ctx = wps->wps->dh_ctx; wps->wps->dh_ctx = NULL; pubkey = wpabuf_dup(wps->wps->dh_pubkey); +#ifdef CONFIG_WPS_NFC + } else if (wps->dev_pw_id >= 0x10 && wps->wps->ap && + wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) { + wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys"); + wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey); + pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey); + wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey); +#endif /* CONFIG_WPS_NFC */ } else { wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys"); wps->dh_privkey = NULL; @@ -340,19 +348,34 @@ int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, #ifdef CONFIG_WPS_OOB -int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) +int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, + const struct wpabuf *pubkey, const u8 *dev_pw, + size_t dev_pw_len) { size_t hash_len; const u8 *addr[1]; u8 pubkey_hash[WPS_HASH_LEN]; + + addr[0] = wpabuf_head(pubkey); + hash_len = wpabuf_len(pubkey); + sha256_vector(1, addr, &hash_len, pubkey_hash); + + wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); + wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len); + wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); + wpabuf_put_be16(msg, dev_pw_id); + wpabuf_put_data(msg, dev_pw, dev_pw_len); + + return 0; +} + + +int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) +{ u8 dev_password_bin[WPS_OOB_DEVICE_PASSWORD_LEN]; wpa_printf(MSG_DEBUG, "WPS: * OOB Device Password"); - addr[0] = wpabuf_head(wps->dh_pubkey); - hash_len = wpabuf_len(wps->dh_pubkey); - sha256_vector(1, addr, &hash_len, pubkey_hash); - if (os_get_random((u8 *) &wps->oob_dev_pw_id, sizeof(u16)) < 0) { wpa_printf(MSG_ERROR, "WPS: device password id " "generation error"); @@ -367,19 +390,15 @@ int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps) return -1; } - wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD); - wpabuf_put_be16(msg, WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); - wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN); - wpabuf_put_be16(msg, wps->oob_dev_pw_id); - wpabuf_put_data(msg, dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); - wpa_snprintf_hex_uppercase( wpabuf_put(wps->oob_conf.dev_password, wpabuf_size(wps->oob_conf.dev_password)), wpabuf_size(wps->oob_conf.dev_password), dev_password_bin, WPS_OOB_DEVICE_PASSWORD_LEN); - return 0; + return wps_build_oob_dev_pw(msg, wps->oob_dev_pw_id, wps->dh_pubkey, + dev_password_bin, + WPS_OOB_DEVICE_PASSWORD_LEN); } #endif /* CONFIG_WPS_OOB */ diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c index f5ad4037..5aa9b004 100644 --- a/src/wps/wps_attr_parse.c +++ b/src/wps/wps_attr_parse.c @@ -9,7 +9,8 @@ #include "includes.h" #include "common.h" -#include "wps_i.h" +#include "wps_defs.h" +#include "wps_attr_parse.h" #ifndef CONFIG_WPS_STRICT #define WPS_WORKAROUNDS @@ -262,12 +263,16 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type, attr->dev_password_id = pos; break; case ATTR_OOB_DEVICE_PASSWORD: - if (len != WPS_OOB_DEVICE_PASSWORD_ATTR_LEN) { + if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_MIN_LEN || + len > WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_LEN) { wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device " "Password length %u", len); return -1; } attr->oob_dev_password = pos; + attr->oob_dev_password_len = len; break; case ATTR_OS_VERSION: if (len != 4) { diff --git a/src/wps/wps_attr_parse.h b/src/wps/wps_attr_parse.h new file mode 100644 index 00000000..332e966a --- /dev/null +++ b/src/wps/wps_attr_parse.h @@ -0,0 +1,107 @@ +/* + * Wi-Fi Protected Setup - attribute parsing + * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef WPS_ATTR_PARSE_H +#define WPS_ATTR_PARSE_H + +#include "wps.h" + +struct wps_parse_attr { + /* fixed length fields */ + const u8 *version; /* 1 octet */ + const u8 *version2; /* 1 octet */ + const u8 *msg_type; /* 1 octet */ + const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */ + const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */ + const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */ + const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */ + const u8 *auth_type_flags; /* 2 octets */ + const u8 *encr_type_flags; /* 2 octets */ + const u8 *conn_type_flags; /* 1 octet */ + const u8 *config_methods; /* 2 octets */ + const u8 *sel_reg_config_methods; /* 2 octets */ + const u8 *primary_dev_type; /* 8 octets */ + const u8 *rf_bands; /* 1 octet */ + const u8 *assoc_state; /* 2 octets */ + const u8 *config_error; /* 2 octets */ + const u8 *dev_password_id; /* 2 octets */ + const u8 *os_version; /* 4 octets */ + const u8 *wps_state; /* 1 octet */ + const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */ + const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */ + const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */ + const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */ + const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */ + const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ + const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */ + const u8 *auth_type; /* 2 octets */ + const u8 *encr_type; /* 2 octets */ + const u8 *network_idx; /* 1 octet */ + const u8 *network_key_idx; /* 1 octet */ + const u8 *mac_addr; /* ETH_ALEN (6) octets */ + const u8 *key_prov_auto; /* 1 octet (Bool) */ + const u8 *dot1x_enabled; /* 1 octet (Bool) */ + const u8 *selected_registrar; /* 1 octet (Bool) */ + const u8 *request_type; /* 1 octet */ + const u8 *response_type; /* 1 octet */ + const u8 *ap_setup_locked; /* 1 octet */ + const u8 *settings_delay_time; /* 1 octet */ + const u8 *network_key_shareable; /* 1 octet (Bool) */ + const u8 *request_to_enroll; /* 1 octet (Bool) */ + + /* variable length fields */ + const u8 *manufacturer; + size_t manufacturer_len; + const u8 *model_name; + size_t model_name_len; + const u8 *model_number; + size_t model_number_len; + const u8 *serial_number; + size_t serial_number_len; + const u8 *dev_name; + size_t dev_name_len; + const u8 *public_key; + size_t public_key_len; + const u8 *encr_settings; + size_t encr_settings_len; + const u8 *ssid; /* <= 32 octets */ + size_t ssid_len; + const u8 *network_key; /* <= 64 octets */ + size_t network_key_len; + const u8 *eap_type; /* <= 8 octets */ + size_t eap_type_len; + const u8 *eap_identity; /* <= 64 octets */ + size_t eap_identity_len; + const u8 *authorized_macs; /* <= 30 octets */ + size_t authorized_macs_len; + const u8 *sec_dev_type_list; /* <= 128 octets */ + size_t sec_dev_type_list_len; + const u8 *oob_dev_password; /* 38..54 octets */ + size_t oob_dev_password_len; + + /* attributes that can occur multiple times */ +#define MAX_CRED_COUNT 10 + const u8 *cred[MAX_CRED_COUNT]; + size_t cred_len[MAX_CRED_COUNT]; + size_t num_cred; + +#define MAX_REQ_DEV_TYPE_COUNT 10 + const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT]; + size_t num_req_dev_type; + + const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT]; + size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT]; + size_t num_vendor_ext; +}; + +int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr); + +#endif /* WPS_ATTR_PARSE_H */ diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 2dff4b25..5a8817f2 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - common functionality - * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -249,6 +249,22 @@ unsigned int wps_generate_pin(void) } +int wps_pin_str_valid(const char *pin) +{ + const char *p; + size_t len; + + p = pin; + while (*p >= '0' && *p <= '9') + p++; + if (*p != '\0') + return 0; + + len = p - pin; + return len == 4 || len == 8; +} + + void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg, u16 config_error, u16 error_indication) { @@ -308,7 +324,7 @@ void wps_pbc_timeout_event(struct wps_context *wps) #ifdef CONFIG_WPS_OOB -static struct wpabuf * wps_get_oob_cred(struct wps_context *wps) +struct wpabuf * wps_get_oob_cred(struct wps_context *wps) { struct wps_data data; struct wpabuf *plain; @@ -335,11 +351,35 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps) } +struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id, + const struct wpabuf *pubkey, + const struct wpabuf *dev_pw) +{ + struct wpabuf *data; + + data = wpabuf_alloc(200); + if (data == NULL) + return NULL; + + if (wps_build_version(data) || + wps_build_oob_dev_pw(data, dev_pw_id, pubkey, + wpabuf_head(dev_pw), wpabuf_len(dev_pw)) || + wps_build_wfa_ext(data, 0, NULL, 0)) { + wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password " + "token"); + wpabuf_free(data); + return NULL; + } + + return data; +} + + static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps) { struct wpabuf *data; - data = wpabuf_alloc(9 + WPS_OOB_DEVICE_PASSWORD_ATTR_LEN); + data = wpabuf_alloc(200); if (data == NULL) { wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " "device password attribute"); @@ -375,6 +415,7 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps, struct oob_conf_data *oob_conf = &wps->oob_conf; struct wps_parse_attr attr; const u8 *pos; + size_t pw_len; if (wps_parse_msg(data, &attr) < 0 || attr.oob_dev_password == NULL) { @@ -384,6 +425,7 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps, pos = attr.oob_dev_password; + wpabuf_free(oob_conf->pubkey_hash); oob_conf->pubkey_hash = wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN); if (oob_conf->pubkey_hash == NULL) { @@ -396,39 +438,32 @@ static int wps_parse_oob_dev_pwd(struct wps_context *wps, wps->oob_dev_pw_id = WPA_GET_BE16(pos); pos += sizeof(wps->oob_dev_pw_id); - oob_conf->dev_password = - wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1); + pw_len = attr.oob_dev_password_len - WPS_OOB_PUBKEY_HASH_LEN - 2; + oob_conf->dev_password = wpabuf_alloc(pw_len * 2 + 1); if (oob_conf->dev_password == NULL) { wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB " "device password"); return -1; } wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password, - wpabuf_size(oob_conf->dev_password)), - wpabuf_size(oob_conf->dev_password), pos, - WPS_OOB_DEVICE_PASSWORD_LEN); + pw_len * 2 + 1), + pw_len * 2 + 1, pos, pw_len); return 0; } -static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) +int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr) { struct wpabuf msg; - struct wps_parse_attr attr; size_t i; - if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { - wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); - return -1; - } - - for (i = 0; i < attr.num_cred; i++) { + for (i = 0; i < attr->num_cred; i++) { struct wps_credential local_cred; struct wps_parse_attr cattr; os_memset(&local_cred, 0, sizeof(local_cred)); - wpabuf_set(&msg, attr.cred[i], attr.cred_len[i]); + wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]); if (wps_parse_msg(&msg, &cattr) < 0 || wps_process_cred(&cattr, &local_cred)) { wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB " @@ -442,6 +477,19 @@ static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) } +static int wps_parse_oob_cred(struct wps_context *wps, struct wpabuf *data) +{ + struct wps_parse_attr attr; + + if (wps_parse_msg(data, &attr) < 0 || attr.num_cred <= 0) { + wpa_printf(MSG_ERROR, "WPS: OOB credential not found"); + return -1; + } + + return wps_oob_use_cred(wps, &attr); +} + + int wps_process_oob(struct wps_context *wps, struct oob_device_data *oob_dev, int registrar) { @@ -695,3 +743,53 @@ struct wpabuf * wps_build_wsc_nack(struct wps_data *wps) return msg; } + + +#ifdef CONFIG_WPS_NFC +struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey, + struct wpabuf **privkey, + struct wpabuf **dev_pw) +{ + struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret; + void *dh_ctx; + u16 val; + + pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN); + if (pw == NULL) + return NULL; + + if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN), + WPS_OOB_DEVICE_PASSWORD_LEN) || + random_get_bytes((u8 *) &val, sizeof(val))) { + wpabuf_free(pw); + return NULL; + } + + dh_ctx = dh5_init(&priv, &pub); + if (dh_ctx == NULL) { + wpabuf_free(pw); + return NULL; + } + dh5_free(dh_ctx); + + *id = 0x10 + val % 0xfff0; + wpabuf_free(*pubkey); + *pubkey = pub; + wpabuf_free(*privkey); + *privkey = priv; + wpabuf_free(*dev_pw); + *dev_pw = pw; + + ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw); + if (ndef && ret) { + struct wpabuf *tmp; + tmp = ndef_build_wifi(ret); + wpabuf_free(ret); + if (tmp == NULL) + return NULL; + ret = tmp; + } + + return ret; +} +#endif /* CONFIG_WPS_NFC */ diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h index e128a195..2f42603a 100644 --- a/src/wps/wps_defs.h +++ b/src/wps/wps_defs.h @@ -41,7 +41,7 @@ extern int wps_testing_dummy_cred; #define WPS_MGMTAUTHKEY_LEN 32 #define WPS_MGMTENCKEY_LEN 16 #define WPS_MGMT_KEY_ID_LEN 16 -#define WPS_OOB_DEVICE_PASSWORD_ATTR_LEN 54 +#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16 #define WPS_OOB_DEVICE_PASSWORD_LEN 32 #define WPS_OOB_PUBKEY_HASH_LEN 20 diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index 559582dd..3c94a434 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -203,6 +203,20 @@ int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg) } +int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg) +{ + if (dev->vendor_ext_m1 != NULL) { + wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension M1", + wpabuf_head_u8(dev->vendor_ext_m1), + wpabuf_len(dev->vendor_ext_m1)); + wpabuf_put_be16(msg, ATTR_VENDOR_EXT); + wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1)); + wpabuf_put_buf(msg, dev->vendor_ext_m1); + } + return 0; +} + + int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg) { wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands); diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index 7ca81ad6..200c9c45 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -17,6 +17,7 @@ int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg); diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 85d2e958..da0c101b 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -163,7 +163,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_config_error(msg, WPS_CFG_NO_ERROR) || wps_build_os_version(&wps->wps->dev, msg) || - wps_build_wfa_ext(msg, 0, NULL, 0)) { + wps_build_wfa_ext(msg, 0, NULL, 0) || + wps_build_vendor_ext_m1(&wps->wps->dev, msg)) { wpabuf_free(msg); return NULL; } diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 0655a3a4..95a0dec0 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - External Registrar - * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -1996,3 +1996,41 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, return 0; } + + +#ifdef CONFIG_WPS_NFC +struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid) +{ + struct wps_er_ap *ap; + struct wpabuf *ret; + struct wps_data data; + + if (er == NULL) + return NULL; + + ap = wps_er_ap_get(er, NULL, uuid); + if (ap == NULL) + return NULL; + if (ap->ap_settings == NULL) { + wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the " + "selected AP"); + return NULL; + } + + ret = wpabuf_alloc(500); + if (ret == NULL) + return NULL; + + os_memset(&data, 0, sizeof(data)); + data.wps = er->wps; + data.use_cred = ap->ap_settings; + if (wps_build_version(ret) || + wps_build_cred(&data, ret) || + wps_build_wfa_ext(ret, 0, NULL, 0)) { + wpabuf_free(ret); + return NULL; + } + + return ret; +} +#endif /* CONFIG_WPS_NFC */ diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 1297f658..86ad248d 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 <j@w1.fi> + * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -10,6 +10,9 @@ #define WPS_I_H #include "wps.h" +#include "wps_attr_parse.h" + +struct wps_nfc_pw_token; /** * struct wps_data - WPS registration protocol data @@ -114,100 +117,11 @@ 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_parse_attr { - /* fixed length fields */ - const u8 *version; /* 1 octet */ - const u8 *version2; /* 1 octet */ - const u8 *msg_type; /* 1 octet */ - const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */ - const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */ - const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */ - const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */ - const u8 *auth_type_flags; /* 2 octets */ - const u8 *encr_type_flags; /* 2 octets */ - const u8 *conn_type_flags; /* 1 octet */ - const u8 *config_methods; /* 2 octets */ - const u8 *sel_reg_config_methods; /* 2 octets */ - const u8 *primary_dev_type; /* 8 octets */ - const u8 *rf_bands; /* 1 octet */ - const u8 *assoc_state; /* 2 octets */ - const u8 *config_error; /* 2 octets */ - const u8 *dev_password_id; /* 2 octets */ - const u8 *oob_dev_password; /* WPS_OOB_DEVICE_PASSWORD_ATTR_LEN (54) - * octets */ - const u8 *os_version; /* 4 octets */ - const u8 *wps_state; /* 1 octet */ - const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */ - const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */ - const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */ - const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */ - const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */ - const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ - const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ - const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */ - const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */ - const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */ - const u8 *auth_type; /* 2 octets */ - const u8 *encr_type; /* 2 octets */ - const u8 *network_idx; /* 1 octet */ - const u8 *network_key_idx; /* 1 octet */ - const u8 *mac_addr; /* ETH_ALEN (6) octets */ - const u8 *key_prov_auto; /* 1 octet (Bool) */ - const u8 *dot1x_enabled; /* 1 octet (Bool) */ - const u8 *selected_registrar; /* 1 octet (Bool) */ - const u8 *request_type; /* 1 octet */ - const u8 *response_type; /* 1 octet */ - const u8 *ap_setup_locked; /* 1 octet */ - const u8 *settings_delay_time; /* 1 octet */ - const u8 *network_key_shareable; /* 1 octet (Bool) */ - const u8 *request_to_enroll; /* 1 octet (Bool) */ - - /* variable length fields */ - const u8 *manufacturer; - size_t manufacturer_len; - const u8 *model_name; - size_t model_name_len; - const u8 *model_number; - size_t model_number_len; - const u8 *serial_number; - size_t serial_number_len; - const u8 *dev_name; - size_t dev_name_len; - const u8 *public_key; - size_t public_key_len; - const u8 *encr_settings; - size_t encr_settings_len; - const u8 *ssid; /* <= 32 octets */ - size_t ssid_len; - const u8 *network_key; /* <= 64 octets */ - size_t network_key_len; - const u8 *eap_type; /* <= 8 octets */ - size_t eap_type_len; - const u8 *eap_identity; /* <= 64 octets */ - size_t eap_identity_len; - const u8 *authorized_macs; /* <= 30 octets */ - size_t authorized_macs_len; - const u8 *sec_dev_type_list; /* <= 128 octets */ - size_t sec_dev_type_list_len; - - /* attributes that can occur multiple times */ -#define MAX_CRED_COUNT 10 - const u8 *cred[MAX_CRED_COUNT]; - size_t cred_len[MAX_CRED_COUNT]; - size_t num_cred; - -#define MAX_REQ_DEV_TYPE_COUNT 10 - const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT]; - size_t num_req_dev_type; - - const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT]; - size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT]; - size_t num_vendor_ext; + struct wps_nfc_pw_token *nfc_pw_token; }; + /* wps_common.c */ void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, const char *label, u8 *res, size_t res_len); @@ -230,9 +144,6 @@ extern struct oob_nfc_device_data oob_nfc_pn531_device_data; struct wpabuf * wps_build_wsc_ack(struct wps_data *wps); struct wpabuf * wps_build_wsc_nack(struct wps_data *wps); -/* wps_attr_parse.c */ -int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr); - /* wps_attr_build.c */ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg); int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type); @@ -255,6 +166,9 @@ int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg); int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg); int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg); int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg); +int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id, + const struct wpabuf *pubkey, const u8 *dev_pw, + size_t dev_pw_len); int wps_build_oob_dev_password(struct wpabuf *msg, struct wps_context *wps); struct wpabuf * wps_ie_encapsulate(struct wpabuf *data); @@ -288,9 +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); - -/* ndef.c */ -struct wpabuf * ndef_parse_wifi(struct wpabuf *buf); -struct wpabuf * ndef_build_wifi(struct wpabuf *buf); +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_nfc.c b/src/wps/wps_nfc.c index ff120002..68043503 100644 --- a/src/wps/wps_nfc.c +++ b/src/wps/wps_nfc.c @@ -1,15 +1,9 @@ /* * NFC routines for Wi-Fi Protected Setup - * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp> + * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" diff --git a/src/wps/wps_nfc_pn531.c b/src/wps/wps_nfc_pn531.c index 7e05e4dd..c2bf4570 100644 --- a/src/wps/wps_nfc_pn531.c +++ b/src/wps/wps_nfc_pn531.c @@ -1,15 +1,9 @@ /* * NFC PN531 routines for Wi-Fi Protected Setup - * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp> + * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 5ed7ea4a..44bb0063 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1,6 +1,6 @@ /* * Wi-Fi Protected Setup - Registrar - * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -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]; @@ -102,7 +149,8 @@ struct wps_registrar { void (*pin_needed_cb)(void *ctx, const u8 *uuid_e, const struct wps_device_data *dev); void (*reg_success_cb)(void *ctx, const u8 *mac_addr, - const u8 *uuid_e); + const u8 *uuid_e, const u8 *dev_pw, + size_t dev_pw_len); void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id, u16 sel_reg_config_methods); void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e, @@ -112,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; @@ -484,12 +533,16 @@ static void wps_set_pushbutton(u16 *methods, u16 conf_methods) { *methods |= WPS_CONFIG_PUSHBUTTON; #ifdef CONFIG_WPS2 - if (conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) + if ((conf_methods & WPS_CONFIG_VIRT_PUSHBUTTON) == + WPS_CONFIG_VIRT_PUSHBUTTON) *methods |= WPS_CONFIG_VIRT_PUSHBUTTON; - if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) + if ((conf_methods & WPS_CONFIG_PHY_PUSHBUTTON) == + WPS_CONFIG_PHY_PUSHBUTTON) *methods |= WPS_CONFIG_PHY_PUSHBUTTON; - if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON | - WPS_CONFIG_PHY_PUSHBUTTON))) { + if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) != + WPS_CONFIG_VIRT_PUSHBUTTON && + (*methods & WPS_CONFIG_PHY_PUSHBUTTON) != + WPS_CONFIG_PHY_PUSHBUTTON) { /* * Required to include virtual/physical flag, but we were not * configured with push button type, so have to default to one @@ -591,6 +644,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 +688,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); @@ -740,14 +795,22 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg) /** * wps_registrar_invalidate_wildcard_pin - Invalidate a wildcard PIN * @reg: Registrar data from wps_registrar_init() + * @dev_pw: PIN to search for or %NULL to match any + * @dev_pw_len: Length of dev_pw in octets * Returns: 0 on success, -1 if not wildcard PIN is enabled */ -static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg) +static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg, + const u8 *dev_pw, + size_t dev_pw_len) { struct wps_uuid_pin *pin, *prev; dl_list_for_each_safe(pin, prev, ®->pins, struct wps_uuid_pin, list) { + if (dev_pw && pin->pin && + (dev_pw_len != pin->pin_len || + os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0)) + continue; /* different PIN */ if (pin->wildcard_uuid) { wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", pin->uuid, WPS_UUID_LEN); @@ -945,7 +1008,8 @@ static void wps_registrar_pin_completed(struct wps_registrar *reg) } -void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e) +void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e, + const u8 *dev_pw, size_t dev_pw_len) { if (registrar->pbc) { wps_registrar_remove_pbc_session(registrar, @@ -954,6 +1018,13 @@ void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e) } else { wps_registrar_pin_completed(registrar); } + + if (dev_pw && + wps_registrar_invalidate_wildcard_pin(registrar, dev_pw, + dev_pw_len) == 0) { + wpa_hexdump_key(MSG_DEBUG, "WPS: Invalidated wildcard PIN", + dev_pw, dev_pw_len); + } } @@ -968,7 +1039,7 @@ int wps_registrar_wps_cancel(struct wps_registrar *reg) /* PIN Method */ wpa_printf(MSG_DEBUG, "WPS: PIN is set - cancelling it"); wps_registrar_pin_completed(reg); - wps_registrar_invalidate_wildcard_pin(reg); + wps_registrar_invalidate_wildcard_pin(reg, NULL, 0); return 1; } return 0; @@ -1071,12 +1142,13 @@ static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e, static void wps_cb_reg_success(struct wps_registrar *reg, const u8 *mac_addr, - const u8 *uuid_e) + const u8 *uuid_e, const u8 *dev_pw, + size_t dev_pw_len) { if (reg->reg_success_cb == NULL) return; - reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e); + reg->reg_success_cb(reg->cb_ctx, mac_addr, uuid_e, dev_pw, dev_pw_len); } @@ -1238,6 +1310,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); @@ -2424,8 +2503,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); @@ -3055,7 +3160,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, wps->new_psk = NULL; } - wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e); + wps_cb_reg_success(wps->wps->registrar, wps->mac_addr_e, wps->uuid_e, + wps->dev_password, wps->dev_password_len); if (wps->pbc) { wps_registrar_remove_pbc_session(wps->wps->registrar, @@ -3348,3 +3454,84 @@ int wps_registrar_config_ap(struct wps_registrar *reg, return -1; } + + +#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) +{ + const u8 *pos, *hash, *dev_pw; + u16 id; + size_t dev_pw_len; + + if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_MIN_LEN || + oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 + + WPS_OOB_DEVICE_PASSWORD_LEN) + return -1; + + hash = oob_dev_pw; + pos = oob_dev_pw + WPS_OOB_PUBKEY_HASH_LEN; + id = WPA_GET_BE16(pos); + dev_pw = pos + 2; + dev_pw_len = oob_dev_pw + oob_dev_pw_len - dev_pw; + + wpa_printf(MSG_DEBUG, "WPS: Add NFC Password Token for Password ID %u", + id); + + wpa_hexdump(MSG_DEBUG, "WPS: Public Key Hash", + hash, WPS_OOB_PUBKEY_HASH_LEN); + wpa_hexdump_key(MSG_DEBUG, "WPS: Device Password", dev_pw, dev_pw_len); + + 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 */ diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c index 61f65530..f83bdf47 100644 --- a/src/wps/wps_ufd.c +++ b/src/wps/wps_ufd.c @@ -1,15 +1,9 @@ /* * UFD routines for Wi-Fi Protected Setup - * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp> + * Copyright (c) 2009-2012, Masashi Honma <masashi.honma@gmail.com> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. + * This software may be distributed under the terms of the BSD license. + * See README for more details. */ #include "includes.h" @@ -165,8 +159,10 @@ static void * init_ufd(struct wps_context *wps, } data = os_zalloc(sizeof(*data)); - if (data == NULL) + if (data == NULL) { + close(ufd_fd); return NULL; + } data->ufd_fd = ufd_fd; return data; } diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index 766cac49..09a46a21 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -305,15 +305,15 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, int alloc_len; char *scratch_mem = NULL; char *mem; - char *domain_and_port; + char *host; char *delim; char *path; - char *domain; int port = 80; /* port to send to (default is port 80) */ struct addrinfo hints; struct addrinfo *result = NULL; struct addrinfo *rp; int rerr; + size_t host_len, path_len; /* url MUST begin with http: */ if (url_len < 7 || os_strncasecmp(url, "http://", 7)) @@ -321,30 +321,24 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, url += 7; url_len -= 7; - /* allocate memory for the extra stuff we need */ - alloc_len = 2 * (url_len + 1); - scratch_mem = os_zalloc(alloc_len); + /* Make a copy of the string to allow modification during parsing */ + scratch_mem = os_malloc(url_len + 1); if (scratch_mem == NULL) goto fail; - mem = scratch_mem; - os_strncpy(mem, url, url_len); - wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem); - domain_and_port = mem; - mem += 1 + os_strlen(mem); - delim = os_strchr(domain_and_port, '/'); + os_memcpy(scratch_mem, url, url_len); + scratch_mem[url_len] = '\0'; + wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem); + host = scratch_mem; + path = os_strchr(host, '/'); + if (path) + *path++ = '\0'; /* null terminate host */ + + /* Process and remove optional port component */ + delim = os_strchr(host, ':'); if (delim) { - *delim++ = 0; /* null terminate domain and port */ - path = delim; - } else { - path = domain_and_port + os_strlen(domain_and_port); - } - domain = mem; - strcpy(domain, domain_and_port); - delim = os_strchr(domain, ':'); - if (delim) { - *delim++ = 0; /* null terminate domain */ - if (isdigit(*delim)) - port = atol(delim); + *delim = '\0'; /* null terminate host name for now */ + if (isdigit(delim[1])) + port = atol(delim + 1); } /* @@ -367,13 +361,21 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, hints.ai_flags = 0; #endif hints.ai_protocol = 0; /* Any protocol? */ - rerr = getaddrinfo(domain, NULL /* fill in port ourselves */, + rerr = getaddrinfo(host, NULL /* fill in port ourselves */, &hints, &result); if (rerr) { wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s", - rerr, gai_strerror(rerr), domain); + rerr, gai_strerror(rerr), host); goto fail; } + + if (delim) + *delim = ':'; /* Restore port */ + + host_len = os_strlen(host); + path_len = path ? os_strlen(path) : 0; + alloc_len = host_len + 1 + 1 + path_len + 1; + for (rp = result; rp; rp = rp->ai_next) { struct subscr_addr *a; @@ -386,16 +388,16 @@ static void subscr_addr_add_url(struct subscription *s, const char *url, a = os_zalloc(sizeof(*a) + alloc_len); if (a == NULL) - continue; - mem = (void *) (a + 1); + break; + mem = (char *) (a + 1); a->domain_and_port = mem; - strcpy(mem, domain_and_port); - mem += 1 + strlen(mem); + os_memcpy(mem, host, host_len); + mem += host_len + 1; a->path = mem; - if (path[0] != '/') + if (path == NULL || path[0] != '/') *mem++ = '/'; - strcpy(mem, path); - mem += 1 + os_strlen(mem); + if (path) + os_memcpy(mem, path, path_len); os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr)); a->saddr.sin_port = htons(port); diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c index 4c4aebf6..17a82074 100644 --- a/src/wps/wps_upnp_ssdp.c +++ b/src/wps/wps_upnp_ssdp.c @@ -866,20 +866,24 @@ int ssdp_open_multicast_sock(u32 ip_addr) return -1; #if 0 /* maybe ok if we sometimes block on writes */ - if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) + if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) { + close(sd); return -1; + } #endif if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, &ip_addr, sizeof(ip_addr))) { wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: " "%d (%s)", ip_addr, errno, strerror(errno)); + close(sd); return -1; } if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl))) { wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): " "%d (%s)", errno, strerror(errno)); + close(sd); return -1; } @@ -898,6 +902,7 @@ int ssdp_open_multicast_sock(u32 ip_addr) "WPS UPnP: setsockopt " "IP_ADD_MEMBERSHIP errno %d (%s)", errno, strerror(errno)); + close(sd); return -1; } } |