aboutsummaryrefslogtreecommitdiffstats
path: root/wpa_supplicant
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-03-05 19:39:39 (GMT)
committerJouni Malinen <j@w1.fi>2009-03-11 19:20:11 (GMT)
commit0415598fa2acdb89ec025caa1112f43853207cd2 (patch)
tree8b9e6fa05ecc7e2a10fed2af8561399c0643f617 /wpa_supplicant
parent5c9d23f4bc5e3874049c077ce48a020c155152f8 (diff)
downloadhostap-06-0415598fa2acdb89ec025caa1112f43853207cd2.zip
hostap-06-0415598fa2acdb89ec025caa1112f43853207cd2.tar.gz
hostap-06-0415598fa2acdb89ec025caa1112f43853207cd2.tar.bz2
WPS: Add a workaround for TKIP/CCMP mixed mode credentials
Many deployed APs do not handle negotiation of security parameters well when both TKIP and CCMP (or both WPA and WPA2) are enabled. The most common end result seems to be ending up with the least secure option.. As a workaround, check whether the AP advertises WPA2/CCMP in Beacon frames and add those options for the credential if needed. This allows the client to select the most secure configuration regardless of how broken the AP's WPS implementation is as far as auth/encr type negotiation is concerned. (cherry picked from commit 7cc1b6c900d79e6051116f4aed55b84d404c49f1)
Diffstat (limited to 'wpa_supplicant')
-rw-r--r--wpa_supplicant/wps_supplicant.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index c2c1dd0..8b14a9a 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -26,6 +26,7 @@
#include "ctrl_iface_dbus.h"
#include "eap_common/eap_wsc_common.h"
#include "blacklist.h"
+#include "wpa.h"
#include "wps_supplicant.h"
#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
@@ -83,6 +84,102 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
}
+static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct wps_credential *cred)
+{
+ struct wpa_driver_capa capa;
+ size_t i;
+ struct wpa_scan_res *bss;
+ const u8 *ie;
+ struct wpa_ie_data adv;
+ int wpa2 = 0, ccmp = 0;
+
+ /*
+ * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
+ * case they are configured for mixed mode operation (WPA+WPA2 and
+ * TKIP+CCMP). Try to use scan results to figure out whether the AP
+ * actually supports stronger security and select that if the client
+ * has support for it, too.
+ */
+
+ if (wpa_drv_get_capa(wpa_s, &capa))
+ return; /* Unknown what driver supports */
+
+ if (wpa_supplicant_get_scan_results(wpa_s) || wpa_s->scan_res == NULL)
+ return; /* Could not get scan results for checking advertised
+ * parameters */
+
+ for (i = 0; i < wpa_s->scan_res->num; i++) {
+ bss = wpa_s->scan_res->res[i];
+ if (os_memcmp(bss->bssid, cred->mac_addr, ETH_ALEN) != 0)
+ continue;
+ ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+ if (ie == NULL)
+ continue;
+ if (ie[1] != ssid->ssid_len || ssid->ssid == NULL ||
+ os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "WPS: AP found from scan results");
+ break;
+ }
+
+ if (i == wpa_s->scan_res->num) {
+ wpa_printf(MSG_DEBUG, "WPS: The AP was not found from scan "
+ "results - use credential as-is");
+ return;
+ }
+
+ ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
+ wpa2 = 1;
+ if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
+ ccmp = 1;
+ } else {
+ ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
+ adv.pairwise_cipher & WPA_CIPHER_CCMP)
+ ccmp = 1;
+ }
+
+ if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
+ (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
+ /*
+ * TODO: This could be the initial AP configuration and the
+ * Beacon contents could change shortly. Should request a new
+ * scan and delay addition of the network until the updated
+ * scan results are available.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
+ "support - use credential as-is");
+ return;
+ }
+
+ if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
+ (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
+ "based on scan results");
+ if (wpa_s->conf->ap_scan == 1)
+ ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
+ else
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ }
+
+ if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
+ (ssid->proto & WPA_PROTO_WPA) &&
+ (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
+ wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
+ "based on scan results");
+ if (wpa_s->conf->ap_scan == 1)
+ ssid->proto |= WPA_PROTO_RSN;
+ else
+ ssid->proto = WPA_PROTO_RSN;
+ }
+}
+
+
static int wpa_supplicant_wps_cred(void *ctx,
const struct wps_credential *cred)
{
@@ -249,6 +346,8 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
}
+ wpas_wps_security_workaround(wpa_s, ssid, cred);
+
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {