From 1491ebe877c87b91a53762d08762ade6ff77eed0 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Wed, 31 Jan 2018 09:56:00 -0800 Subject: [PATCH] auto-t: add SA Query tests Two autotests: 1. Tests SA Query procedure when the AP goes down. In this case the AP goes down ungracefully, now allowing it to send out any deauth frames. When the AP comes back up, IWD still thinks its connected. The AP will then send unprotected disassociate frames so the client can re-connect. This kicks off the SA Query procedure, which the AP will not respond to. At this point we can deauth and reconnect to the AP. 2. Test SA Query procedure when a disassociate frame has been spoofed. In this case we receive an unprotected disassociate frame and start SA Query. The AP should then respond to the SA query within the timeout. We then know the frame was spoofed and can remain connected. --- .../testSAQuery-spoofing/connection_test.py | 96 +++++++++++++++++++ autotests/testSAQuery-spoofing/hw.conf | 5 + autotests/testSAQuery-spoofing/ssidCCMP.conf | 10 ++ autotests/testSAQuery/connection_test.py | 88 +++++++++++++++++ autotests/testSAQuery/hw.conf | 5 + autotests/testSAQuery/ssidCCMP.conf | 10 ++ 6 files changed, 214 insertions(+) create mode 100644 autotests/testSAQuery-spoofing/connection_test.py create mode 100644 autotests/testSAQuery-spoofing/hw.conf create mode 100644 autotests/testSAQuery-spoofing/ssidCCMP.conf create mode 100644 autotests/testSAQuery/connection_test.py create mode 100644 autotests/testSAQuery/hw.conf create mode 100644 autotests/testSAQuery/ssidCCMP.conf diff --git a/autotests/testSAQuery-spoofing/connection_test.py b/autotests/testSAQuery-spoofing/connection_test.py new file mode 100644 index 00000000..167bd9a5 --- /dev/null +++ b/autotests/testSAQuery-spoofing/connection_test.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 + +import unittest +import sys + +sys.path.append('../util') +import iwd +from iwd import IWD +from iwd import PSKAgent +from iwd import NetworkType +from hwsim import Hwsim +from hostapd import HostapdCLI +from wiphy import wiphy_map + +from time import sleep + +class Test(unittest.TestCase): + + def test_connection_success(self): + hwsim = Hwsim() + + hostapd = None + radio = None + + for wname in wiphy_map: + wiphy = wiphy_map[wname] + intf = list(wiphy.values())[0] + if intf.use == 'hostapd': + hostapd = HostapdCLI(intf) + for path in hwsim.radios: + if hwsim.radios[path].name == wname: + radio = hwsim.radios[path] + break + + wd = IWD() + + psk_agent = PSKAgent("secret123") + wd.register_psk_agent(psk_agent) + + devices = wd.list_devices(); + self.assertIsNotNone(devices) + device = devices[0] + + condition = 'not obj.scanning' + wd.wait_for_object_condition(device, condition) + + device.scan() + + condition = 'not obj.scanning' + wd.wait_for_object_condition(device, condition) + + ordered_networks = device.get_ordered_networks() + ordered_network = ordered_networks[0] + + self.assertEqual(ordered_network.name, "ssidCCMP") + self.assertEqual(ordered_network.type, NetworkType.psk) + + condition = 'not obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + ordered_network.network_object.connect() + + condition = 'obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + # TODO: for some reason hostapd does not respond to SA query if done + # too soon after connection. + sleep(1) + + # Spoof a disassociate frame. This will kick off SA Query procedure. + hwsim.spoof_disassociate(radio, hostapd.get_freq(), device.address) + + # sleep to ensure hostapd responds and SA Query does not timeout + sleep(4) + + # Since disassociate was spoofed we should still be connected + condition = 'obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + device.disconnect() + + condition = 'not obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + wd.unregister_psk_agent(psk_agent) + + @classmethod + def setUpClass(cls): + pass + + @classmethod + def tearDownClass(cls): + IWD.clear_storage() + +if __name__ == '__main__': + unittest.main(exit=True) diff --git a/autotests/testSAQuery-spoofing/hw.conf b/autotests/testSAQuery-spoofing/hw.conf new file mode 100644 index 00000000..fad15b88 --- /dev/null +++ b/autotests/testSAQuery-spoofing/hw.conf @@ -0,0 +1,5 @@ +[SETUP] +num_radios=2 + +[HOSTAPD] +rad0=ssidCCMP.conf diff --git a/autotests/testSAQuery-spoofing/ssidCCMP.conf b/autotests/testSAQuery-spoofing/ssidCCMP.conf new file mode 100644 index 00000000..c79f5e55 --- /dev/null +++ b/autotests/testSAQuery-spoofing/ssidCCMP.conf @@ -0,0 +1,10 @@ +hw_mode=g +channel=1 +ssid=ssidCCMP + +wpa=2 +wpa_pairwise=CCMP +wpa_passphrase=secret123 + +ieee80211w=2 +wpa_key_mgmt=WPA-PSK-SHA256 diff --git a/autotests/testSAQuery/connection_test.py b/autotests/testSAQuery/connection_test.py new file mode 100644 index 00000000..ae816b3c --- /dev/null +++ b/autotests/testSAQuery/connection_test.py @@ -0,0 +1,88 @@ +#!/usr/bin/python3 + +import unittest +import sys + +sys.path.append('../util') +import iwd +from iwd import IWD +from iwd import PSKAgent +from iwd import NetworkType +from hwsim import Hwsim +from hostapd import HostapdCLI +from wiphy import wiphy_map + +class Test(unittest.TestCase): + + def test_connection_success(self): + hostapd = None + + for wname in wiphy_map: + wiphy = wiphy_map[wname] + intf = list(wiphy.values())[0] + if intf.use == 'hostapd': + hostapd = HostapdCLI(intf) + break + + hwsim = Hwsim() + wd = IWD() + + psk_agent = PSKAgent("secret123") + wd.register_psk_agent(psk_agent) + + devices = wd.list_devices(); + self.assertIsNotNone(devices) + device = devices[0] + + condition = 'not obj.scanning' + wd.wait_for_object_condition(device, condition) + + device.scan() + + condition = 'not obj.scanning' + wd.wait_for_object_condition(device, condition) + + ordered_networks = device.get_ordered_networks() + ordered_network = ordered_networks[0] + + self.assertEqual(ordered_network.name, "ssidCCMP") + self.assertEqual(ordered_network.type, NetworkType.psk) + + condition = 'not obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + ordered_network.network_object.connect() + + condition = 'obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + # Make AP go down ungracefully, when hostapd comes back up it should + # send an unprotected disassociate frame so the client will re-auth. + # This will kick off the SA Query procedure + hostapd.ungraceful_restart() + + condition = 'not obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + # IWD should now try and re-connect to the AP + + condition = 'obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + device.disconnect() + + condition = 'not obj.connected' + wd.wait_for_object_condition(ordered_network.network_object, condition) + + wd.unregister_psk_agent(psk_agent) + + @classmethod + def setUpClass(cls): + pass + + @classmethod + def tearDownClass(cls): + IWD.clear_storage() + +if __name__ == '__main__': + unittest.main(exit=True) diff --git a/autotests/testSAQuery/hw.conf b/autotests/testSAQuery/hw.conf new file mode 100644 index 00000000..fad15b88 --- /dev/null +++ b/autotests/testSAQuery/hw.conf @@ -0,0 +1,5 @@ +[SETUP] +num_radios=2 + +[HOSTAPD] +rad0=ssidCCMP.conf diff --git a/autotests/testSAQuery/ssidCCMP.conf b/autotests/testSAQuery/ssidCCMP.conf new file mode 100644 index 00000000..c79f5e55 --- /dev/null +++ b/autotests/testSAQuery/ssidCCMP.conf @@ -0,0 +1,10 @@ +hw_mode=g +channel=1 +ssid=ssidCCMP + +wpa=2 +wpa_pairwise=CCMP +wpa_passphrase=secret123 + +ieee80211w=2 +wpa_key_mgmt=WPA-PSK-SHA256