From 835a546b2020a0587aff550fc2fe117dd2427644 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 Mar 2013 13:47:22 +0200 Subject: [PATCH] tests: Add test cases for PMF Signed-hostap: Jouni Malinen --- tests/hwsim/hostapd.py | 2 +- tests/hwsim/test_ap_pmf.py | 93 ++++++++++++++++++++++++++++++++++ tests/hwsim/test_ap_tdls.py | 48 ++++++++---------- tests/hwsim/wlantest.py | 98 ++++++++++++++++++++++++++++++++++++ tests/hwsim/wpasupplicant.py | 4 +- 5 files changed, 215 insertions(+), 30 deletions(-) create mode 100644 tests/hwsim/test_ap_pmf.py create mode 100644 tests/hwsim/wlantest.py diff --git a/tests/hwsim/hostapd.py b/tests/hwsim/hostapd.py index 15a98f39a..77d286a6c 100644 --- a/tests/hwsim/hostapd.py +++ b/tests/hwsim/hostapd.py @@ -103,7 +103,7 @@ def add_ap(ifname, params): raise Exception("Could not ping hostapd") hapd.set_defaults() fields = [ "ssid", "wpa_passphrase", "wpa", "wpa_key_mgmt", - "wpa_pairwise", "rsn_pairwise", "wep_key0" ] + "wpa_pairwise", "rsn_pairwise", "ieee80211w", "wep_key0" ] for field in fields: if field in params: hapd.set(field, params[field]) diff --git a/tests/hwsim/test_ap_pmf.py b/tests/hwsim/test_ap_pmf.py new file mode 100644 index 000000000..9a6f7af82 --- /dev/null +++ b/tests/hwsim/test_ap_pmf.py @@ -0,0 +1,93 @@ +#!/usr/bin/python +# +# Protected management frames tests +# Copyright (c) 2013, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import time +import subprocess +import logging +logger = logging.getLogger(__name__) + +import hwsim_utils +import hostapd +from wlantest import Wlantest + +ap_ifname = 'wlan2' +bssid = "02:00:00:00:02:00" + +def test_ap_pmf_required(dev): + """WPA2-PSK AP with PMF required""" + ssid = "test-pmf-required" + wt = Wlantest() + wt.flush() + wt.add_passphrase("12345678") + params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678") + params["wpa_key_mgmt"] = "WPA-PSK-SHA256"; + params["ieee80211w"] = "2"; + hostapd.add_ap(ap_ifname, params) + dev[0].connect(ssid, psk="12345678", ieee80211w="1", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[0].ifname, ap_ifname) + dev[1].connect(ssid, psk="12345678", ieee80211w="2", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[1].ifname, ap_ifname) + wt.require_ap_pmf_mandatory(bssid) + wt.require_sta_pmf(bssid, dev[0].p2p_interface_addr()) + wt.require_sta_pmf_mandatory(bssid, dev[1].p2p_interface_addr()) + +def test_ap_pmf_optional(dev): + """WPA2-PSK AP with PMF optional""" + ssid = "test-pmf-optional" + wt = Wlantest() + wt.flush() + wt.add_passphrase("12345678") + params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678") + params["wpa_key_mgmt"] = "WPA-PSK"; + params["ieee80211w"] = "1"; + hostapd.add_ap(ap_ifname, params) + dev[0].connect(ssid, psk="12345678", ieee80211w="1", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[0].ifname, ap_ifname) + dev[1].connect(ssid, psk="12345678", ieee80211w="2", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[1].ifname, ap_ifname) + wt.require_ap_pmf_optional(bssid) + wt.require_sta_pmf(bssid, dev[0].p2p_interface_addr()) + wt.require_sta_pmf_mandatory(bssid, dev[1].p2p_interface_addr()) + +def test_ap_pmf_optional_2akm(dev): + """WPA2-PSK AP with PMF optional (2 AKMs)""" + ssid = "test-pmf-optional-2akm" + wt = Wlantest() + wt.flush() + wt.add_passphrase("12345678") + params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678") + params["wpa_key_mgmt"] = "WPA-PSK WPA-PSK-SHA256"; + params["ieee80211w"] = "1"; + hostapd.add_ap(ap_ifname, params) + dev[0].connect(ssid, psk="12345678", ieee80211w="1", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[0].ifname, ap_ifname) + dev[1].connect(ssid, psk="12345678", ieee80211w="2", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[1].ifname, ap_ifname) + wt.require_ap_pmf_optional(bssid) + wt.require_sta_pmf(bssid, dev[0].p2p_interface_addr()) + wt.require_sta_key_mgmt(bssid, dev[0].p2p_interface_addr(), "PSK-SHA256") + wt.require_sta_pmf_mandatory(bssid, dev[1].p2p_interface_addr()) + wt.require_sta_key_mgmt(bssid, dev[1].p2p_interface_addr(), "PSK-SHA256") + +def test_ap_pmf_negative(dev): + """WPA2-PSK AP without PMF (negative test)""" + ssid = "test-pmf-negative" + wt = Wlantest() + wt.flush() + wt.add_passphrase("12345678") + params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678") + hostapd.add_ap(ap_ifname, params) + dev[0].connect(ssid, psk="12345678", ieee80211w="1", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[0].ifname, ap_ifname) + try: + dev[1].connect(ssid, psk="12345678", ieee80211w="2", key_mgmt="WPA-PSK WPA-PSK-SHA256", proto="WPA2") + hwsim_utils.test_connectivity(dev[1].ifname, ap_ifname) + raise Exception("PMF required STA connected to no PMF AP") + except Exception, e: + logger.debug("Ignore expected exception: " + str(e)) + wt.require_ap_no_pmf(bssid) diff --git a/tests/hwsim/test_ap_tdls.py b/tests/hwsim/test_ap_tdls.py index 74e9377c4..db2e903fd 100644 --- a/tests/hwsim/test_ap_tdls.py +++ b/tests/hwsim/test_ap_tdls.py @@ -7,7 +7,6 @@ # See README for more details. import time -import subprocess import logging logger = logging.getLogger(__name__) @@ -15,6 +14,7 @@ import hwsim_utils from hostapd import HostapdGlobal from hostapd import Hostapd import hostapd +from wlantest import Wlantest ap_ifname = 'wlan2' @@ -53,34 +53,23 @@ def connect_2sta_open(dev): dev[1].connect("test-open", key_mgmt="NONE") connectivity(dev, ap_ifname) -def wlantest_tdls(field, bssid, addr1, addr2): - res = subprocess.check_output(["../../wlantest/wlantest_cli", - "get_tdls_counter", field, bssid, addr1, - addr2]); - if "FAIL" in res: - raise Exception("wlantest_cli command failed") - return int(res) - -def wlantest_tdls_clear(bssid, addr1, addr2): - subprocess.call(["../../wlantest/wlantest_cli", - "clear_tdls_counters", bssid, addr1, addr2]); - def wlantest_setup(): - subprocess.call(["../../wlantest/wlantest_cli", "flush"]); - subprocess.call(["../../wlantest/wlantest_cli", "add_passphrase", - "12345678"]); - subprocess.call(["../../wlantest/wlantest_cli", "add_wepkey", - "68656c6c6f"]); + wt = Wlantest() + wt.flush() + wt.add_passphrase("12345678") + wt.add_wepkey("68656c6c6f") def wlantest_tdls_packet_counters(bssid, addr0, addr1): - dl = wlantest_tdls("valid_direct_link", bssid, addr0, addr1); - inv_dl = wlantest_tdls("invalid_direct_link", bssid, addr0, addr1); - ap = wlantest_tdls("valid_ap_path", bssid, addr0, addr1); - inv_ap = wlantest_tdls("invalid_ap_path", bssid, addr0, addr1); + wt = Wlantest() + dl = wt.get_tdls_counter("valid_direct_link", bssid, addr0, addr1) + inv_dl = wt.get_tdls_counter("invalid_direct_link", bssid, addr0, addr1) + ap = wt.get_tdls_counter("valid_ap_path", bssid, addr0, addr1) + inv_ap = wt.get_tdls_counter("invalid_ap_path", bssid, addr0, addr1) return [dl,inv_dl,ap,inv_ap] def tdls_check_dl(sta0, sta1, bssid, addr0, addr1): - wlantest_tdls_clear(bssid, addr0, addr1); + wt = Wlantest() + wt.tdls_clear(bssid, addr0, addr1) hwsim_utils.test_connectivity_sta(sta0, sta1) [dl,inv_dl,ap,inv_ap] = wlantest_tdls_packet_counters(bssid, addr0, addr1) if dl == 0: @@ -93,7 +82,8 @@ def tdls_check_dl(sta0, sta1, bssid, addr0, addr1): raise Exception("Invalid frames through AP path") def tdls_check_ap(sta0, sta1, bssid, addr0, addr1): - wlantest_tdls_clear(bssid, addr0, addr1); + wt = Wlantest() + wt.tdls_clear(bssid, addr0, addr1); hwsim_utils.test_connectivity_sta(sta0, sta1) [dl,inv_dl,ap,inv_ap] = wlantest_tdls_packet_counters(bssid, addr0, addr1) if dl > 0: @@ -109,8 +99,9 @@ def setup_tdls(sta0, sta1, bssid, reverse=False, expect_fail=False): logger.info("Setup TDLS") addr0 = sta0.p2p_interface_addr() addr1 = sta1.p2p_interface_addr() - wlantest_tdls_clear(bssid, addr0, addr1); - wlantest_tdls_clear(bssid, addr1, addr0); + wt = Wlantest() + wt.tdls_clear(bssid, addr0, addr1); + wt.tdls_clear(bssid, addr1, addr0); sta0.tdls_setup(addr1) time.sleep(1) if expect_fail: @@ -119,7 +110,7 @@ def setup_tdls(sta0, sta1, bssid, reverse=False, expect_fail=False): if reverse: addr1 = sta0.p2p_interface_addr() addr0 = sta1.p2p_interface_addr() - conf = wlantest_tdls("setup_conf_ok", bssid, addr0, addr1); + conf = wt.get_tdls_counter("setup_conf_ok", bssid, addr0, addr1); if conf == 0: raise Exception("No TDLS Setup Confirm (success) seen") tdls_check_dl(sta0, sta1, bssid, addr0, addr1) @@ -130,7 +121,8 @@ def teardown_tdls(sta0, sta1, bssid): addr1 = sta1.p2p_interface_addr() sta0.tdls_teardown(addr1) time.sleep(1) - teardown = wlantest_tdls("teardown", bssid, addr0, addr1); + wt = Wlantest() + teardown = wt.get_tdls_counter("teardown", bssid, addr0, addr1); if teardown == 0: raise Exception("No TDLS Setup Teardown seen") tdls_check_ap(sta0, sta1, bssid, addr0, addr1) diff --git a/tests/hwsim/wlantest.py b/tests/hwsim/wlantest.py new file mode 100644 index 000000000..84723b1f2 --- /dev/null +++ b/tests/hwsim/wlantest.py @@ -0,0 +1,98 @@ +#!/usr/bin/python +# +# Python class for controlling wlantest +# Copyright (c) 2013, Jouni Malinen +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import time +import subprocess +import logging +import wpaspy + +logger = logging.getLogger(__name__) +wlantest_cli = '../../wlantest/wlantest_cli' + +class Wlantest: + def flush(self): + res = subprocess.check_output([wlantest_cli, "flush"]) + if "FAIL" in res: + raise Exception("wlantest_cli flush failed") + + def add_passphrase(self, passphrase): + res = subprocess.check_output([wlantest_cli, "add_passphrase", + passphrase]) + if "FAIL" in res: + raise Exception("wlantest_cli add_passphrase failed") + + def add_wepkey(self, key): + res = subprocess.check_output([wlantest_cli, "add_wepkey", key]) + if "FAIL" in res: + raise Exception("wlantest_cli add_key failed") + + def info_bss(self, field, bssid): + res = subprocess.check_output([wlantest_cli, "info_bss", field, bssid]) + if "FAIL" in res: + raise Exception("Could not get BSS info from wlantest for " + bssid) + return res + + def info_sta(self, field, bssid, addr): + res = subprocess.check_output([wlantest_cli, "info_sta", field, bssid, + addr]) + if "FAIL" in res: + raise Exception("Could not get STA info from wlantest for " + addr) + return res + + def tdls_clear(self, bssid, addr1, addr2): + subprocess.call([wlantest_cli, "clear_tdls_counters", bssid, addr1, + addr2]); + + def get_tdls_counter(self, field, bssid, addr1, addr2): + res = subprocess.check_output([wlantest_cli, "get_tdls_counter", field, + bssid, addr1, addr2]); + if "FAIL" in res: + raise Exception("wlantest_cli command failed") + return int(res) + + def require_ap_pmf_mandatory(self, bssid): + res = self.info_bss("rsn_capab", bssid) + if "MFPR" not in res: + raise Exception("AP did not require PMF") + if "MFPC" not in res: + raise Exception("AP did not enable PMF") + res = self.info_bss("key_mgmt", bssid) + if "PSK-SHA256" not in res: + raise Exception("AP did not enable SHA256-based AKM for PMF") + + def require_ap_pmf_optional(self, bssid): + res = self.info_bss("rsn_capab", bssid) + if "MFPR" in res: + raise Exception("AP required PMF") + if "MFPC" not in res: + raise Exception("AP did not enable PMF") + + def require_ap_no_pmf(self, bssid): + res = self.info_bss("rsn_capab", bssid) + if "MFPR" in res: + raise Exception("AP required PMF") + if "MFPC" in res: + raise Exception("AP enabled PMF") + + def require_sta_pmf_mandatory(self, bssid, addr): + res = self.info_sta("rsn_capab", bssid, addr) + if "MFPR" not in res: + raise Exception("STA did not require PMF") + if "MFPC" not in res: + raise Exception("STA did not enable PMF") + + def require_sta_pmf(self, bssid, addr): + res = self.info_sta("rsn_capab", bssid, addr) + if "MFPC" not in res: + raise Exception("STA did not enable PMF") + + def require_sta_key_mgmt(self, bssid, addr, key_mgmt): + res = self.info_sta("key_mgmt", bssid, addr) + if key_mgmt not in res: + raise Exception("Unexpected STA key_mgmt") diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py index 10adb3ef6..68dbaec0e 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -302,7 +302,7 @@ class WpaSupplicant: raise Exception("Failed to request TDLS teardown") return None - def connect(self, ssid, psk=None, proto=None, key_mgmt=None, wep_key0=None): + def connect(self, ssid, psk=None, proto=None, key_mgmt=None, wep_key0=None, ieee80211w=None): logger.info("Connect STA " + self.ifname + " to AP") id = self.add_network() self.set_network_quoted(id, "ssid", ssid) @@ -312,6 +312,8 @@ class WpaSupplicant: self.set_network(id, "proto", proto) if key_mgmt: self.set_network(id, "key_mgmt", key_mgmt) + if ieee80211w: + self.set_network(id, "ieee80211w", ieee80211w) if wep_key0: self.set_network(id, "wep_key0", wep_key0) self.connect_network(id)