test_sae.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. # Test cases for SAE
  2. # Copyright (c) 2013-2016, Jouni Malinen <j@w1.fi>
  3. #
  4. # This software may be distributed under the terms of the BSD license.
  5. # See README for more details.
  6. from remotehost import remote_compatible
  7. import binascii
  8. import os
  9. import time
  10. import logging
  11. logger = logging.getLogger()
  12. import hwsim_utils
  13. import hostapd
  14. from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
  15. from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
  16. @remote_compatible
  17. def test_sae(dev, apdev):
  18. """SAE with default group"""
  19. if "SAE" not in dev[0].get_capability("auth_alg"):
  20. raise HwsimSkip("SAE not supported")
  21. params = hostapd.wpa2_params(ssid="test-sae",
  22. passphrase="12345678")
  23. params['wpa_key_mgmt'] = 'SAE'
  24. hapd = hostapd.add_ap(apdev[0], params)
  25. key_mgmt = hapd.get_config()['key_mgmt']
  26. if key_mgmt.split(' ')[0] != "SAE":
  27. raise Exception("Unexpected GET_CONFIG(key_mgmt): " + key_mgmt)
  28. dev[0].request("SET sae_groups ")
  29. id = dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  30. scan_freq="2412")
  31. if dev[0].get_status_field('sae_group') != '19':
  32. raise Exception("Expected default SAE group not used")
  33. bss = dev[0].get_bss(apdev[0]['bssid'])
  34. if 'flags' not in bss:
  35. raise Exception("Could not get BSS flags from BSS table")
  36. if "[WPA2-SAE-CCMP]" not in bss['flags']:
  37. raise Exception("Unexpected BSS flags: " + bss['flags'])
  38. @remote_compatible
  39. def test_sae_password_ecc(dev, apdev):
  40. """SAE with number of different passwords (ECC)"""
  41. if "SAE" not in dev[0].get_capability("auth_alg"):
  42. raise HwsimSkip("SAE not supported")
  43. params = hostapd.wpa2_params(ssid="test-sae",
  44. passphrase="12345678")
  45. params['wpa_key_mgmt'] = 'SAE'
  46. hapd = hostapd.add_ap(apdev[0], params)
  47. dev[0].request("SET sae_groups 19")
  48. for i in range(10):
  49. password = "12345678-" + str(i)
  50. hapd.set("wpa_passphrase", password)
  51. dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
  52. scan_freq="2412")
  53. dev[0].request("REMOVE_NETWORK all")
  54. dev[0].wait_disconnected()
  55. @remote_compatible
  56. def test_sae_password_ffc(dev, apdev):
  57. """SAE with number of different passwords (FFC)"""
  58. if "SAE" not in dev[0].get_capability("auth_alg"):
  59. raise HwsimSkip("SAE not supported")
  60. params = hostapd.wpa2_params(ssid="test-sae",
  61. passphrase="12345678")
  62. params['wpa_key_mgmt'] = 'SAE'
  63. params['sae_groups'] = '22'
  64. hapd = hostapd.add_ap(apdev[0], params)
  65. dev[0].request("SET sae_groups 22")
  66. for i in range(10):
  67. password = "12345678-" + str(i)
  68. hapd.set("wpa_passphrase", password)
  69. dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
  70. scan_freq="2412")
  71. dev[0].request("REMOVE_NETWORK all")
  72. dev[0].wait_disconnected()
  73. @remote_compatible
  74. def test_sae_pmksa_caching(dev, apdev):
  75. """SAE and PMKSA caching"""
  76. if "SAE" not in dev[0].get_capability("auth_alg"):
  77. raise HwsimSkip("SAE not supported")
  78. params = hostapd.wpa2_params(ssid="test-sae",
  79. passphrase="12345678")
  80. params['wpa_key_mgmt'] = 'SAE'
  81. hapd = hostapd.add_ap(apdev[0], params)
  82. dev[0].request("SET sae_groups ")
  83. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  84. scan_freq="2412")
  85. ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
  86. if ev is None:
  87. raise Exception("No connection event received from hostapd")
  88. dev[0].request("DISCONNECT")
  89. dev[0].wait_disconnected()
  90. dev[0].request("RECONNECT")
  91. dev[0].wait_connected(timeout=15, error="Reconnect timed out")
  92. if dev[0].get_status_field('sae_group') is not None:
  93. raise Exception("SAE group claimed to have been used")
  94. @remote_compatible
  95. def test_sae_pmksa_caching_disabled(dev, apdev):
  96. """SAE and PMKSA caching disabled"""
  97. if "SAE" not in dev[0].get_capability("auth_alg"):
  98. raise HwsimSkip("SAE not supported")
  99. params = hostapd.wpa2_params(ssid="test-sae",
  100. passphrase="12345678")
  101. params['wpa_key_mgmt'] = 'SAE'
  102. params['disable_pmksa_caching'] = '1'
  103. hapd = hostapd.add_ap(apdev[0], params)
  104. dev[0].request("SET sae_groups ")
  105. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  106. scan_freq="2412")
  107. ev = hapd.wait_event([ "AP-STA-CONNECTED" ], timeout=5)
  108. if ev is None:
  109. raise Exception("No connection event received from hostapd")
  110. dev[0].request("DISCONNECT")
  111. dev[0].wait_disconnected()
  112. dev[0].request("RECONNECT")
  113. dev[0].wait_connected(timeout=15, error="Reconnect timed out")
  114. if dev[0].get_status_field('sae_group') != '19':
  115. raise Exception("Expected default SAE group not used")
  116. def test_sae_groups(dev, apdev):
  117. """SAE with all supported groups"""
  118. if "SAE" not in dev[0].get_capability("auth_alg"):
  119. raise HwsimSkip("SAE not supported")
  120. # This is the full list of supported groups, but groups 14-16 (2048-4096 bit
  121. # MODP) and group 21 (521-bit random ECP group) are a bit too slow on some
  122. # VMs and can result in hitting the mac80211 authentication timeout, so
  123. # allow them to fail and just report such failures in the debug log.
  124. sae_groups = [ 19, 25, 26, 20, 21, 2, 5, 14, 15, 16, 22, 23, 24 ]
  125. tls = dev[0].request("GET tls_library")
  126. if tls.startswith("OpenSSL") and "build=OpenSSL 1.0.2" in tls and "run=OpenSSL 1.0.2" in tls:
  127. logger.info("Add Brainpool EC groups since OpenSSL is new enough")
  128. sae_groups += [ 27, 28, 29, 30 ]
  129. heavy_groups = [ 14, 15, 16 ]
  130. groups = [str(g) for g in sae_groups]
  131. params = hostapd.wpa2_params(ssid="test-sae-groups",
  132. passphrase="12345678")
  133. params['wpa_key_mgmt'] = 'SAE'
  134. params['sae_groups'] = ' '.join(groups)
  135. hostapd.add_ap(apdev[0], params)
  136. for g in groups:
  137. logger.info("Testing SAE group " + g)
  138. dev[0].request("SET sae_groups " + g)
  139. id = dev[0].connect("test-sae-groups", psk="12345678", key_mgmt="SAE",
  140. scan_freq="2412", wait_connect=False)
  141. if int(g) in heavy_groups:
  142. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
  143. if ev is None:
  144. logger.info("No connection with heavy SAE group %s did not connect - likely hitting timeout in mac80211" % g)
  145. dev[0].remove_network(id)
  146. time.sleep(0.1)
  147. dev[0].dump_monitor()
  148. continue
  149. logger.info("Connection with heavy SAE group " + g)
  150. else:
  151. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=10)
  152. if ev is None:
  153. if "BoringSSL" in tls and int(g) in [ 25 ]:
  154. logger.info("Ignore connection failure with group " + g + " with BoringSSL")
  155. dev[0].remove_network(id)
  156. dev[0].dump_monitor()
  157. continue
  158. raise Exception("Connection timed out with group " + g)
  159. if dev[0].get_status_field('sae_group') != g:
  160. raise Exception("Expected SAE group not used")
  161. dev[0].remove_network(id)
  162. dev[0].wait_disconnected()
  163. dev[0].dump_monitor()
  164. @remote_compatible
  165. def test_sae_group_nego(dev, apdev):
  166. """SAE group negotiation"""
  167. if "SAE" not in dev[0].get_capability("auth_alg"):
  168. raise HwsimSkip("SAE not supported")
  169. params = hostapd.wpa2_params(ssid="test-sae-group-nego",
  170. passphrase="12345678")
  171. params['wpa_key_mgmt'] = 'SAE'
  172. params['sae_groups'] = '19'
  173. hostapd.add_ap(apdev[0], params)
  174. dev[0].request("SET sae_groups 25 26 20 19")
  175. dev[0].connect("test-sae-group-nego", psk="12345678", key_mgmt="SAE",
  176. scan_freq="2412")
  177. if dev[0].get_status_field('sae_group') != '19':
  178. raise Exception("Expected SAE group not used")
  179. @remote_compatible
  180. def test_sae_anti_clogging(dev, apdev):
  181. """SAE anti clogging"""
  182. if "SAE" not in dev[0].get_capability("auth_alg"):
  183. raise HwsimSkip("SAE not supported")
  184. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  185. params['wpa_key_mgmt'] = 'SAE'
  186. params['sae_anti_clogging_threshold'] = '1'
  187. hostapd.add_ap(apdev[0], params)
  188. dev[0].request("SET sae_groups ")
  189. dev[1].request("SET sae_groups ")
  190. id = {}
  191. for i in range(0, 2):
  192. dev[i].scan(freq="2412")
  193. id[i] = dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
  194. scan_freq="2412", only_add_network=True)
  195. for i in range(0, 2):
  196. dev[i].select_network(id[i])
  197. for i in range(0, 2):
  198. dev[i].wait_connected(timeout=10)
  199. def test_sae_forced_anti_clogging(dev, apdev):
  200. """SAE anti clogging (forced)"""
  201. if "SAE" not in dev[0].get_capability("auth_alg"):
  202. raise HwsimSkip("SAE not supported")
  203. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  204. params['wpa_key_mgmt'] = 'SAE WPA-PSK'
  205. params['sae_anti_clogging_threshold'] = '0'
  206. hostapd.add_ap(apdev[0], params)
  207. dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
  208. for i in range(0, 2):
  209. dev[i].request("SET sae_groups ")
  210. dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
  211. scan_freq="2412")
  212. def test_sae_mixed(dev, apdev):
  213. """Mixed SAE and non-SAE network"""
  214. if "SAE" not in dev[0].get_capability("auth_alg"):
  215. raise HwsimSkip("SAE not supported")
  216. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  217. params['wpa_key_mgmt'] = 'SAE WPA-PSK'
  218. params['sae_anti_clogging_threshold'] = '0'
  219. hostapd.add_ap(apdev[0], params)
  220. dev[2].connect("test-sae", psk="12345678", scan_freq="2412")
  221. for i in range(0, 2):
  222. dev[i].request("SET sae_groups ")
  223. dev[i].connect("test-sae", psk="12345678", key_mgmt="SAE",
  224. scan_freq="2412")
  225. @remote_compatible
  226. def test_sae_missing_password(dev, apdev):
  227. """SAE and missing password"""
  228. if "SAE" not in dev[0].get_capability("auth_alg"):
  229. raise HwsimSkip("SAE not supported")
  230. params = hostapd.wpa2_params(ssid="test-sae",
  231. passphrase="12345678")
  232. params['wpa_key_mgmt'] = 'SAE'
  233. hapd = hostapd.add_ap(apdev[0], params)
  234. dev[0].request("SET sae_groups ")
  235. id = dev[0].connect("test-sae",
  236. raw_psk="46b4a73b8a951ad53ebd2e0afdb9c5483257edd4c21d12b7710759da70945858",
  237. key_mgmt="SAE", scan_freq="2412", wait_connect=False)
  238. ev = dev[0].wait_event(['CTRL-EVENT-SSID-TEMP-DISABLED'], timeout=10)
  239. if ev is None:
  240. raise Exception("Invalid network not temporarily disabled")
  241. def test_sae_key_lifetime_in_memory(dev, apdev, params):
  242. """SAE and key lifetime in memory"""
  243. if "SAE" not in dev[0].get_capability("auth_alg"):
  244. raise HwsimSkip("SAE not supported")
  245. password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
  246. p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
  247. p['wpa_key_mgmt'] = 'SAE'
  248. hapd = hostapd.add_ap(apdev[0], p)
  249. pid = find_wpas_process(dev[0])
  250. dev[0].request("SET sae_groups ")
  251. id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
  252. scan_freq="2412")
  253. # The decrypted copy of GTK is freed only after the CTRL-EVENT-CONNECTED
  254. # event has been delivered, so verify that wpa_supplicant has returned to
  255. # eloop before reading process memory.
  256. time.sleep(1)
  257. dev[0].ping()
  258. buf = read_process_memory(pid, password)
  259. dev[0].request("DISCONNECT")
  260. dev[0].wait_disconnected()
  261. dev[0].relog()
  262. sae_k = None
  263. sae_keyseed = None
  264. sae_kck = None
  265. pmk = None
  266. ptk = None
  267. gtk = None
  268. with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
  269. for l in f.readlines():
  270. if "SAE: k - hexdump" in l:
  271. val = l.strip().split(':')[3].replace(' ', '')
  272. sae_k = binascii.unhexlify(val)
  273. if "SAE: keyseed - hexdump" in l:
  274. val = l.strip().split(':')[3].replace(' ', '')
  275. sae_keyseed = binascii.unhexlify(val)
  276. if "SAE: KCK - hexdump" in l:
  277. val = l.strip().split(':')[3].replace(' ', '')
  278. sae_kck = binascii.unhexlify(val)
  279. if "SAE: PMK - hexdump" in l:
  280. val = l.strip().split(':')[3].replace(' ', '')
  281. pmk = binascii.unhexlify(val)
  282. if "WPA: PTK - hexdump" in l:
  283. val = l.strip().split(':')[3].replace(' ', '')
  284. ptk = binascii.unhexlify(val)
  285. if "WPA: Group Key - hexdump" in l:
  286. val = l.strip().split(':')[3].replace(' ', '')
  287. gtk = binascii.unhexlify(val)
  288. if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
  289. raise Exception("Could not find keys from debug log")
  290. if len(gtk) != 16:
  291. raise Exception("Unexpected GTK length")
  292. kck = ptk[0:16]
  293. kek = ptk[16:32]
  294. tk = ptk[32:48]
  295. fname = os.path.join(params['logdir'],
  296. 'sae_key_lifetime_in_memory.memctx-')
  297. logger.info("Checking keys in memory while associated")
  298. get_key_locations(buf, password, "Password")
  299. get_key_locations(buf, pmk, "PMK")
  300. if password not in buf:
  301. raise HwsimSkip("Password not found while associated")
  302. if pmk not in buf:
  303. raise HwsimSkip("PMK not found while associated")
  304. if kck not in buf:
  305. raise Exception("KCK not found while associated")
  306. if kek not in buf:
  307. raise Exception("KEK not found while associated")
  308. if tk in buf:
  309. raise Exception("TK found from memory")
  310. if gtk in buf:
  311. get_key_locations(buf, gtk, "GTK")
  312. raise Exception("GTK found from memory")
  313. verify_not_present(buf, sae_k, fname, "SAE(k)")
  314. verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
  315. verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
  316. logger.info("Checking keys in memory after disassociation")
  317. buf = read_process_memory(pid, password)
  318. # Note: Password is still present in network configuration
  319. # Note: PMK is in PMKSA cache
  320. get_key_locations(buf, password, "Password")
  321. get_key_locations(buf, pmk, "PMK")
  322. verify_not_present(buf, kck, fname, "KCK")
  323. verify_not_present(buf, kek, fname, "KEK")
  324. verify_not_present(buf, tk, fname, "TK")
  325. verify_not_present(buf, gtk, fname, "GTK")
  326. verify_not_present(buf, sae_k, fname, "SAE(k)")
  327. verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
  328. verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
  329. dev[0].request("PMKSA_FLUSH")
  330. logger.info("Checking keys in memory after PMKSA cache flush")
  331. buf = read_process_memory(pid, password)
  332. get_key_locations(buf, password, "Password")
  333. get_key_locations(buf, pmk, "PMK")
  334. verify_not_present(buf, pmk, fname, "PMK")
  335. dev[0].request("REMOVE_NETWORK all")
  336. logger.info("Checking keys in memory after network profile removal")
  337. buf = read_process_memory(pid, password)
  338. get_key_locations(buf, password, "Password")
  339. get_key_locations(buf, pmk, "PMK")
  340. verify_not_present(buf, password, fname, "password")
  341. verify_not_present(buf, pmk, fname, "PMK")
  342. verify_not_present(buf, kck, fname, "KCK")
  343. verify_not_present(buf, kek, fname, "KEK")
  344. verify_not_present(buf, tk, fname, "TK")
  345. verify_not_present(buf, gtk, fname, "GTK")
  346. verify_not_present(buf, sae_k, fname, "SAE(k)")
  347. verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
  348. verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
  349. @remote_compatible
  350. def test_sae_oom_wpas(dev, apdev):
  351. """SAE and OOM in wpa_supplicant"""
  352. if "SAE" not in dev[0].get_capability("auth_alg"):
  353. raise HwsimSkip("SAE not supported")
  354. params = hostapd.wpa2_params(ssid="test-sae",
  355. passphrase="12345678")
  356. params['wpa_key_mgmt'] = 'SAE'
  357. hapd = hostapd.add_ap(apdev[0], params)
  358. dev[0].request("SET sae_groups 25")
  359. tls = dev[0].request("GET tls_library")
  360. if "BoringSSL" in tls:
  361. dev[0].request("SET sae_groups 26")
  362. with alloc_fail(dev[0], 1, "sae_set_group"):
  363. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  364. scan_freq="2412")
  365. dev[0].request("REMOVE_NETWORK all")
  366. dev[0].request("SET sae_groups ")
  367. with alloc_fail(dev[0], 2, "sae_set_group"):
  368. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  369. scan_freq="2412")
  370. dev[0].request("REMOVE_NETWORK all")
  371. @remote_compatible
  372. def test_sae_proto_ecc(dev, apdev):
  373. """SAE protocol testing (ECC)"""
  374. if "SAE" not in dev[0].get_capability("auth_alg"):
  375. raise HwsimSkip("SAE not supported")
  376. params = hostapd.wpa2_params(ssid="test-sae",
  377. passphrase="12345678")
  378. params['wpa_key_mgmt'] = 'SAE'
  379. hapd = hostapd.add_ap(apdev[0], params)
  380. bssid = apdev[0]['bssid']
  381. dev[0].request("SET sae_groups 19")
  382. tests = [ ("Confirm mismatch",
  383. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  384. "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc4240"),
  385. ("Commit without even full cyclic group field",
  386. "13",
  387. None),
  388. ("Too short commit",
  389. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02",
  390. None),
  391. ("Invalid commit scalar (0)",
  392. "1300" + "0000000000000000000000000000000000000000000000000000000000000000" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  393. None),
  394. ("Invalid commit scalar (1)",
  395. "1300" + "0000000000000000000000000000000000000000000000000000000000000001" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  396. None),
  397. ("Invalid commit scalar (> r)",
  398. "1300" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  399. None),
  400. ("Commit element not on curve",
  401. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728d0000000000000000000000000000000000000000000000000000000000000000",
  402. None),
  403. ("Invalid commit element (y coordinate > P)",
  404. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  405. None),
  406. ("Invalid commit element (x coordinate > P)",
  407. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  408. None),
  409. ("Different group in commit",
  410. "1400" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  411. None),
  412. ("Too short confirm",
  413. "1300" + "033d3635b39666ed427fd4a3e7d37acec2810afeaf1687f746a14163ff0e6d03" + "559cb8928db4ce4e3cbd6555e837591995e5ebe503ef36b503d9ca519d63728dd3c7c676b8e8081831b6bc3a64bdf136061a7de175e17d1965bfa41983ed02f8",
  414. "0000800edebc3f260dc1fe7e0b20888af2b8a3316252ec37388a8504e25b73dc42")]
  415. for (note, commit, confirm) in tests:
  416. logger.info(note)
  417. dev[0].scan_for_bss(bssid, freq=2412)
  418. hapd.set("ext_mgmt_frame_handling", "1")
  419. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  420. scan_freq="2412", wait_connect=False)
  421. logger.info("Commit")
  422. for i in range(0, 10):
  423. req = hapd.mgmt_rx()
  424. if req is None:
  425. raise Exception("MGMT RX wait timed out (commit)")
  426. if req['subtype'] == 11:
  427. break
  428. req = None
  429. if not req:
  430. raise Exception("Authentication frame (commit) not received")
  431. hapd.dump_monitor()
  432. resp = {}
  433. resp['fc'] = req['fc']
  434. resp['da'] = req['sa']
  435. resp['sa'] = req['da']
  436. resp['bssid'] = req['bssid']
  437. resp['payload'] = binascii.unhexlify("030001000000" + commit)
  438. hapd.mgmt_tx(resp)
  439. if confirm:
  440. logger.info("Confirm")
  441. for i in range(0, 10):
  442. req = hapd.mgmt_rx()
  443. if req is None:
  444. raise Exception("MGMT RX wait timed out (confirm)")
  445. if req['subtype'] == 11:
  446. break
  447. req = None
  448. if not req:
  449. raise Exception("Authentication frame (confirm) not received")
  450. hapd.dump_monitor()
  451. resp = {}
  452. resp['fc'] = req['fc']
  453. resp['da'] = req['sa']
  454. resp['sa'] = req['da']
  455. resp['bssid'] = req['bssid']
  456. resp['payload'] = binascii.unhexlify("030002000000" + confirm)
  457. hapd.mgmt_tx(resp)
  458. time.sleep(0.1)
  459. dev[0].request("REMOVE_NETWORK all")
  460. hapd.set("ext_mgmt_frame_handling", "0")
  461. hapd.dump_monitor()
  462. @remote_compatible
  463. def test_sae_proto_ffc(dev, apdev):
  464. """SAE protocol testing (FFC)"""
  465. if "SAE" not in dev[0].get_capability("auth_alg"):
  466. raise HwsimSkip("SAE not supported")
  467. params = hostapd.wpa2_params(ssid="test-sae",
  468. passphrase="12345678")
  469. params['wpa_key_mgmt'] = 'SAE'
  470. hapd = hostapd.add_ap(apdev[0], params)
  471. bssid = apdev[0]['bssid']
  472. dev[0].request("SET sae_groups 2")
  473. tests = [ ("Confirm mismatch",
  474. "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a17486",
  475. "0000f3116a9731f1259622e3eb55d4b3b50ba16f8c5f5565b28e609b180c51460251"),
  476. ("Too short commit",
  477. "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "a8c00117493cdffa5dd671e934bc9cb1a69f39e25e9dd9cd9afd3aea2441a0f5491211c7ba50a753563f9ce943b043557cb71193b28e86ed9544f4289c471bf91b70af5c018cf4663e004165b0fd0bc1d8f3f78adf42eee92bcbc55246fd3ee9f107ab965dc7d4986f23eb71d616ebfe6bfe0a6c1ac5dc1718acee17c9a174",
  478. None),
  479. ("Invalid element (0) in commit",
  480. "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  481. None),
  482. ("Invalid element (1) in commit",
  483. "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
  484. None),
  485. ("Invalid element (> P) in commit",
  486. "0200" + "0c70519d874e3e4930a917cc5e17ea7a26028211159f217bab28b8d6c56691805e49f03249b2c6e22c7c9f86b30e04ccad2deedd5e5108ae07b737c00001c59cd0eb08b1dfc7f1b06a1542e2b6601a963c066e0c65940983a03917ae57a101ce84b5cbbc76ff33ebb990aac2e54aa0f0ab6ec0a58113d927683502b2cb2347d2" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
  487. None) ]
  488. for (note, commit, confirm) in tests:
  489. logger.info(note)
  490. dev[0].scan_for_bss(bssid, freq=2412)
  491. hapd.set("ext_mgmt_frame_handling", "1")
  492. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  493. scan_freq="2412", wait_connect=False)
  494. logger.info("Commit")
  495. for i in range(0, 10):
  496. req = hapd.mgmt_rx()
  497. if req is None:
  498. raise Exception("MGMT RX wait timed out (commit)")
  499. if req['subtype'] == 11:
  500. break
  501. req = None
  502. if not req:
  503. raise Exception("Authentication frame (commit) not received")
  504. hapd.dump_monitor()
  505. resp = {}
  506. resp['fc'] = req['fc']
  507. resp['da'] = req['sa']
  508. resp['sa'] = req['da']
  509. resp['bssid'] = req['bssid']
  510. resp['payload'] = binascii.unhexlify("030001000000" + commit)
  511. hapd.mgmt_tx(resp)
  512. if confirm:
  513. logger.info("Confirm")
  514. for i in range(0, 10):
  515. req = hapd.mgmt_rx()
  516. if req is None:
  517. raise Exception("MGMT RX wait timed out (confirm)")
  518. if req['subtype'] == 11:
  519. break
  520. req = None
  521. if not req:
  522. raise Exception("Authentication frame (confirm) not received")
  523. hapd.dump_monitor()
  524. resp = {}
  525. resp['fc'] = req['fc']
  526. resp['da'] = req['sa']
  527. resp['sa'] = req['da']
  528. resp['bssid'] = req['bssid']
  529. resp['payload'] = binascii.unhexlify("030002000000" + confirm)
  530. hapd.mgmt_tx(resp)
  531. time.sleep(0.1)
  532. dev[0].request("REMOVE_NETWORK all")
  533. hapd.set("ext_mgmt_frame_handling", "0")
  534. hapd.dump_monitor()
  535. @remote_compatible
  536. def test_sae_no_ffc_by_default(dev, apdev):
  537. """SAE and default groups rejecting FFC"""
  538. if "SAE" not in dev[0].get_capability("auth_alg"):
  539. raise HwsimSkip("SAE not supported")
  540. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  541. params['wpa_key_mgmt'] = 'SAE'
  542. hapd = hostapd.add_ap(apdev[0], params)
  543. dev[0].request("SET sae_groups 5")
  544. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412",
  545. wait_connect=False)
  546. ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
  547. if ev is None:
  548. raise Exception("Did not try to authenticate")
  549. ev = dev[0].wait_event(["SME: Trying to authenticate"], timeout=3)
  550. if ev is None:
  551. raise Exception("Did not try to authenticate (2)")
  552. dev[0].request("REMOVE_NETWORK all")
  553. def sae_reflection_attack(apdev, dev, group):
  554. if "SAE" not in dev.get_capability("auth_alg"):
  555. raise HwsimSkip("SAE not supported")
  556. params = hostapd.wpa2_params(ssid="test-sae",
  557. passphrase="no-knowledge-of-passphrase")
  558. params['wpa_key_mgmt'] = 'SAE'
  559. hapd = hostapd.add_ap(apdev, params)
  560. bssid = apdev['bssid']
  561. dev.scan_for_bss(bssid, freq=2412)
  562. hapd.set("ext_mgmt_frame_handling", "1")
  563. dev.request("SET sae_groups %d" % group)
  564. dev.connect("test-sae", psk="reflection-attack", key_mgmt="SAE",
  565. scan_freq="2412", wait_connect=False)
  566. # Commit
  567. for i in range(0, 10):
  568. req = hapd.mgmt_rx()
  569. if req is None:
  570. raise Exception("MGMT RX wait timed out")
  571. if req['subtype'] == 11:
  572. break
  573. req = None
  574. if not req:
  575. raise Exception("Authentication frame not received")
  576. resp = {}
  577. resp['fc'] = req['fc']
  578. resp['da'] = req['sa']
  579. resp['sa'] = req['da']
  580. resp['bssid'] = req['bssid']
  581. resp['payload'] = req['payload']
  582. hapd.mgmt_tx(resp)
  583. # Confirm
  584. req = hapd.mgmt_rx(timeout=0.5)
  585. if req is not None:
  586. if req['subtype'] == 11:
  587. raise Exception("Unexpected Authentication frame seen")
  588. @remote_compatible
  589. def test_sae_reflection_attack_ecc(dev, apdev):
  590. """SAE reflection attack (ECC)"""
  591. sae_reflection_attack(apdev[0], dev[0], 19)
  592. @remote_compatible
  593. def test_sae_reflection_attack_ffc(dev, apdev):
  594. """SAE reflection attack (FFC)"""
  595. sae_reflection_attack(apdev[0], dev[0], 5)
  596. @remote_compatible
  597. def test_sae_anti_clogging_proto(dev, apdev):
  598. """SAE anti clogging protocol testing"""
  599. if "SAE" not in dev[0].get_capability("auth_alg"):
  600. raise HwsimSkip("SAE not supported")
  601. params = hostapd.wpa2_params(ssid="test-sae",
  602. passphrase="no-knowledge-of-passphrase")
  603. params['wpa_key_mgmt'] = 'SAE'
  604. hapd = hostapd.add_ap(apdev[0], params)
  605. bssid = apdev[0]['bssid']
  606. dev[0].scan_for_bss(bssid, freq=2412)
  607. hapd.set("ext_mgmt_frame_handling", "1")
  608. dev[0].request("SET sae_groups ")
  609. dev[0].connect("test-sae", psk="anti-cloggign", key_mgmt="SAE",
  610. scan_freq="2412", wait_connect=False)
  611. # Commit
  612. for i in range(0, 10):
  613. req = hapd.mgmt_rx()
  614. if req is None:
  615. raise Exception("MGMT RX wait timed out")
  616. if req['subtype'] == 11:
  617. break
  618. req = None
  619. if not req:
  620. raise Exception("Authentication frame not received")
  621. resp = {}
  622. resp['fc'] = req['fc']
  623. resp['da'] = req['sa']
  624. resp['sa'] = req['da']
  625. resp['bssid'] = req['bssid']
  626. resp['payload'] = binascii.unhexlify("030001004c00" + "ffff00")
  627. hapd.mgmt_tx(resp)
  628. # Confirm (not received due to DH group being rejected)
  629. req = hapd.mgmt_rx(timeout=0.5)
  630. if req is not None:
  631. if req['subtype'] == 11:
  632. raise Exception("Unexpected Authentication frame seen")
  633. @remote_compatible
  634. def test_sae_no_random(dev, apdev):
  635. """SAE and no random numbers available"""
  636. if "SAE" not in dev[0].get_capability("auth_alg"):
  637. raise HwsimSkip("SAE not supported")
  638. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  639. params['wpa_key_mgmt'] = 'SAE'
  640. hapd = hostapd.add_ap(apdev[0], params)
  641. dev[0].request("SET sae_groups ")
  642. tests = [ (1, "os_get_random;sae_get_rand"),
  643. (1, "os_get_random;get_rand_1_to_p_1"),
  644. (1, "os_get_random;get_random_qr_qnr"),
  645. (1, "os_get_random;sae_derive_pwe_ecc") ]
  646. for count, func in tests:
  647. with fail_test(dev[0], count, func):
  648. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  649. scan_freq="2412")
  650. dev[0].request("REMOVE_NETWORK all")
  651. dev[0].wait_disconnected()
  652. @remote_compatible
  653. def test_sae_pwe_failure(dev, apdev):
  654. """SAE and pwe failure"""
  655. if "SAE" not in dev[0].get_capability("auth_alg"):
  656. raise HwsimSkip("SAE not supported")
  657. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  658. params['wpa_key_mgmt'] = 'SAE'
  659. params['sae_groups'] = '19 5'
  660. hapd = hostapd.add_ap(apdev[0], params)
  661. dev[0].request("SET sae_groups 19")
  662. with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ecc"):
  663. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  664. scan_freq="2412")
  665. dev[0].request("REMOVE_NETWORK all")
  666. dev[0].wait_disconnected()
  667. with fail_test(dev[0], 1, "sae_test_pwd_seed_ecc"):
  668. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  669. scan_freq="2412")
  670. dev[0].request("REMOVE_NETWORK all")
  671. dev[0].wait_disconnected()
  672. dev[0].request("SET sae_groups 5")
  673. with fail_test(dev[0], 1, "hmac_sha256_vector;sae_derive_pwe_ffc"):
  674. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  675. scan_freq="2412")
  676. dev[0].request("REMOVE_NETWORK all")
  677. dev[0].wait_disconnected()
  678. dev[0].request("SET sae_groups 5")
  679. with fail_test(dev[0], 1, "sae_test_pwd_seed_ffc"):
  680. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  681. scan_freq="2412")
  682. dev[0].request("REMOVE_NETWORK all")
  683. dev[0].wait_disconnected()
  684. with fail_test(dev[0], 2, "sae_test_pwd_seed_ffc"):
  685. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  686. scan_freq="2412")
  687. dev[0].request("REMOVE_NETWORK all")
  688. dev[0].wait_disconnected()
  689. @remote_compatible
  690. def test_sae_bignum_failure(dev, apdev):
  691. """SAE and bignum failure"""
  692. if "SAE" not in dev[0].get_capability("auth_alg"):
  693. raise HwsimSkip("SAE not supported")
  694. params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
  695. params['wpa_key_mgmt'] = 'SAE'
  696. params['sae_groups'] = '19 5 22'
  697. hapd = hostapd.add_ap(apdev[0], params)
  698. dev[0].request("SET sae_groups 19")
  699. tests = [ (1, "crypto_bignum_init_set;get_rand_1_to_p_1"),
  700. (1, "crypto_bignum_init;is_quadratic_residue_blind"),
  701. (1, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
  702. (2, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
  703. (3, "crypto_bignum_mulmod;is_quadratic_residue_blind"),
  704. (1, "crypto_bignum_legendre;is_quadratic_residue_blind"),
  705. (1, "crypto_bignum_init_set;sae_test_pwd_seed_ecc"),
  706. (1, "crypto_ec_point_compute_y_sqr;sae_test_pwd_seed_ecc"),
  707. (1, "crypto_bignum_init_set;get_random_qr_qnr"),
  708. (1, "crypto_bignum_to_bin;sae_derive_pwe_ecc"),
  709. (1, "crypto_ec_point_init;sae_derive_pwe_ecc"),
  710. (1, "crypto_ec_point_solve_y_coord;sae_derive_pwe_ecc"),
  711. (1, "crypto_ec_point_init;sae_derive_commit_element_ecc"),
  712. (1, "crypto_ec_point_mul;sae_derive_commit_element_ecc"),
  713. (1, "crypto_ec_point_invert;sae_derive_commit_element_ecc"),
  714. (1, "crypto_bignum_init;=sae_derive_commit"),
  715. (1, "crypto_ec_point_init;sae_derive_k_ecc"),
  716. (1, "crypto_ec_point_mul;sae_derive_k_ecc"),
  717. (1, "crypto_ec_point_add;sae_derive_k_ecc"),
  718. (2, "crypto_ec_point_mul;sae_derive_k_ecc"),
  719. (1, "crypto_ec_point_to_bin;sae_derive_k_ecc"),
  720. (1, "crypto_bignum_legendre;get_random_qr_qnr"),
  721. (1, "sha256_prf;sae_derive_keys"),
  722. (1, "crypto_bignum_init;sae_derive_keys"),
  723. (1, "crypto_bignum_init_set;sae_parse_commit_scalar"),
  724. (1, "crypto_bignum_to_bin;sae_parse_commit_element_ecc"),
  725. (1, "crypto_ec_point_from_bin;sae_parse_commit_element_ecc") ]
  726. for count, func in tests:
  727. with fail_test(dev[0], count, func):
  728. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  729. scan_freq="2412", wait_connect=False)
  730. wait_fail_trigger(dev[0], "GET_FAIL")
  731. dev[0].request("REMOVE_NETWORK all")
  732. dev[0].request("SET sae_groups 5")
  733. tests = [ (1, "crypto_bignum_init_set;sae_set_group"),
  734. (2, "crypto_bignum_init_set;sae_set_group"),
  735. (1, "crypto_bignum_init_set;sae_get_rand"),
  736. (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
  737. (1, "crypto_bignum_exptmod;sae_test_pwd_seed_ffc"),
  738. (1, "crypto_bignum_init;sae_derive_pwe_ffc"),
  739. (1, "crypto_bignum_init;sae_derive_commit_element_ffc"),
  740. (1, "crypto_bignum_exptmod;sae_derive_commit_element_ffc"),
  741. (1, "crypto_bignum_inverse;sae_derive_commit_element_ffc"),
  742. (1, "crypto_bignum_init;sae_derive_k_ffc"),
  743. (1, "crypto_bignum_exptmod;sae_derive_k_ffc"),
  744. (1, "crypto_bignum_mulmod;sae_derive_k_ffc"),
  745. (2, "crypto_bignum_exptmod;sae_derive_k_ffc"),
  746. (1, "crypto_bignum_to_bin;sae_derive_k_ffc"),
  747. (1, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
  748. (1, "crypto_bignum_init;sae_parse_commit_element_ffc"),
  749. (2, "crypto_bignum_init_set;sae_parse_commit_element_ffc"),
  750. (1, "crypto_bignum_exptmod;sae_parse_commit_element_ffc") ]
  751. for count, func in tests:
  752. with fail_test(dev[0], count, func):
  753. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  754. scan_freq="2412", wait_connect=False)
  755. wait_fail_trigger(dev[0], "GET_FAIL")
  756. dev[0].request("REMOVE_NETWORK all")
  757. dev[0].request("SET sae_groups 22")
  758. tests = [ (1, "crypto_bignum_init_set;sae_test_pwd_seed_ffc"),
  759. (1, "crypto_bignum_sub;sae_test_pwd_seed_ffc"),
  760. (1, "crypto_bignum_div;sae_test_pwd_seed_ffc") ]
  761. for count, func in tests:
  762. with fail_test(dev[0], count, func):
  763. dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
  764. scan_freq="2412", wait_connect=False)
  765. wait_fail_trigger(dev[0], "GET_FAIL")
  766. dev[0].request("REMOVE_NETWORK all")