test_radius.py 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  1. # RADIUS tests
  2. # Copyright (c) 2013-2015, 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. import hashlib
  7. import hmac
  8. import logging
  9. logger = logging.getLogger()
  10. import os
  11. import select
  12. import struct
  13. import subprocess
  14. import threading
  15. import time
  16. import hostapd
  17. from utils import HwsimSkip
  18. def connect(dev, ssid, wait_connect=True):
  19. dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412",
  20. eap="PSK", identity="psk.user@example.com",
  21. password_hex="0123456789abcdef0123456789abcdef",
  22. wait_connect=wait_connect)
  23. def test_radius_auth_unreachable(dev, apdev):
  24. """RADIUS Authentication server unreachable"""
  25. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  26. params['auth_server_port'] = "18139"
  27. hostapd.add_ap(apdev[0]['ifname'], params)
  28. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  29. connect(dev[0], "radius-auth", wait_connect=False)
  30. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  31. if ev is None:
  32. raise Exception("Timeout on EAP start")
  33. logger.info("Checking for RADIUS retries")
  34. time.sleep(4)
  35. mib = hapd.get_mib()
  36. if "radiusAuthClientAccessRequests" not in mib:
  37. raise Exception("Missing MIB fields")
  38. if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
  39. raise Exception("Missing RADIUS Authentication retransmission")
  40. if int(mib["radiusAuthClientPendingRequests"]) < 1:
  41. raise Exception("Missing pending RADIUS Authentication request")
  42. def test_radius_auth_unreachable2(dev, apdev):
  43. """RADIUS Authentication server unreachable (2)"""
  44. subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
  45. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  46. params['auth_server_addr'] = "192.168.213.17"
  47. params['auth_server_port'] = "18139"
  48. hostapd.add_ap(apdev[0]['ifname'], params)
  49. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  50. subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
  51. connect(dev[0], "radius-auth", wait_connect=False)
  52. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  53. if ev is None:
  54. raise Exception("Timeout on EAP start")
  55. logger.info("Checking for RADIUS retries")
  56. time.sleep(4)
  57. mib = hapd.get_mib()
  58. if "radiusAuthClientAccessRequests" not in mib:
  59. raise Exception("Missing MIB fields")
  60. if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
  61. raise Exception("Missing RADIUS Authentication retransmission")
  62. def test_radius_auth_unreachable3(dev, apdev):
  63. """RADIUS Authentication server initially unreachable, but then available"""
  64. subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
  65. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  66. params['auth_server_addr'] = "192.168.213.18"
  67. hostapd.add_ap(apdev[0]['ifname'], params)
  68. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  69. connect(dev[0], "radius-auth", wait_connect=False)
  70. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  71. if ev is None:
  72. raise Exception("Timeout on EAP start")
  73. subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
  74. time.sleep(0.1)
  75. dev[0].request("DISCONNECT")
  76. hapd.set('auth_server_addr_replace', '127.0.0.1')
  77. dev[0].request("RECONNECT")
  78. dev[0].wait_connected()
  79. def test_radius_acct_unreachable(dev, apdev):
  80. """RADIUS Accounting server unreachable"""
  81. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  82. params['acct_server_addr'] = "127.0.0.1"
  83. params['acct_server_port'] = "18139"
  84. params['acct_server_shared_secret'] = "radius"
  85. hostapd.add_ap(apdev[0]['ifname'], params)
  86. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  87. connect(dev[0], "radius-acct")
  88. logger.info("Checking for RADIUS retries")
  89. time.sleep(4)
  90. mib = hapd.get_mib()
  91. if "radiusAccClientRetransmissions" not in mib:
  92. raise Exception("Missing MIB fields")
  93. if int(mib["radiusAccClientRetransmissions"]) < 2:
  94. raise Exception("Missing RADIUS Accounting retransmissions")
  95. if int(mib["radiusAccClientPendingRequests"]) < 2:
  96. raise Exception("Missing pending RADIUS Accounting requests")
  97. def test_radius_acct_unreachable2(dev, apdev):
  98. """RADIUS Accounting server unreachable(2)"""
  99. subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
  100. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  101. params['acct_server_addr'] = "192.168.213.17"
  102. params['acct_server_port'] = "18139"
  103. params['acct_server_shared_secret'] = "radius"
  104. hostapd.add_ap(apdev[0]['ifname'], params)
  105. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  106. subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
  107. connect(dev[0], "radius-acct")
  108. logger.info("Checking for RADIUS retries")
  109. time.sleep(4)
  110. mib = hapd.get_mib()
  111. if "radiusAccClientRetransmissions" not in mib:
  112. raise Exception("Missing MIB fields")
  113. if int(mib["radiusAccClientRetransmissions"]) < 1 and int(mib["radiusAccClientPendingRequests"]) < 1:
  114. raise Exception("Missing pending or retransmitted RADIUS Accounting requests")
  115. def test_radius_acct_unreachable3(dev, apdev):
  116. """RADIUS Accounting server initially unreachable, but then available"""
  117. subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
  118. as_hapd = hostapd.Hostapd("as")
  119. as_mib_start = as_hapd.get_mib(param="radius_server")
  120. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  121. params['acct_server_addr'] = "192.168.213.18"
  122. params['acct_server_port'] = "1813"
  123. params['acct_server_shared_secret'] = "radius"
  124. hostapd.add_ap(apdev[0]['ifname'], params)
  125. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  126. connect(dev[0], "radius-acct")
  127. subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
  128. time.sleep(0.1)
  129. dev[0].request("DISCONNECT")
  130. hapd.set('acct_server_addr_replace', '127.0.0.1')
  131. dev[0].request("RECONNECT")
  132. dev[0].wait_connected()
  133. time.sleep(1)
  134. as_mib_end = as_hapd.get_mib(param="radius_server")
  135. req_s = int(as_mib_start['radiusAccServTotalResponses'])
  136. req_e = int(as_mib_end['radiusAccServTotalResponses'])
  137. if req_e <= req_s:
  138. raise Exception("Unexpected RADIUS server acct MIB value")
  139. def test_radius_acct_unreachable4(dev, apdev):
  140. """RADIUS Accounting server unreachable and multiple STAs"""
  141. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  142. params['acct_server_addr'] = "127.0.0.1"
  143. params['acct_server_port'] = "18139"
  144. params['acct_server_shared_secret'] = "radius"
  145. hostapd.add_ap(apdev[0]['ifname'], params)
  146. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  147. for i in range(20):
  148. connect(dev[0], "radius-acct")
  149. dev[0].request("REMOVE_NETWORK all")
  150. dev[0].wait_disconnected()
  151. def test_radius_acct(dev, apdev):
  152. """RADIUS Accounting"""
  153. as_hapd = hostapd.Hostapd("as")
  154. as_mib_start = as_hapd.get_mib(param="radius_server")
  155. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  156. params['acct_server_addr'] = "127.0.0.1"
  157. params['acct_server_port'] = "1813"
  158. params['acct_server_shared_secret'] = "radius"
  159. params['radius_auth_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
  160. params['radius_acct_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
  161. hostapd.add_ap(apdev[0]['ifname'], params)
  162. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  163. connect(dev[0], "radius-acct")
  164. dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
  165. eap="PAX", identity="test-class",
  166. password_hex="0123456789abcdef0123456789abcdef")
  167. dev[2].connect("radius-acct", key_mgmt="WPA-EAP",
  168. eap="GPSK", identity="gpsk-cui",
  169. password="abcdefghijklmnop0123456789abcdef",
  170. scan_freq="2412")
  171. logger.info("Checking for RADIUS counters")
  172. count = 0
  173. while True:
  174. mib = hapd.get_mib()
  175. if int(mib['radiusAccClientResponses']) >= 3:
  176. break
  177. time.sleep(0.1)
  178. count += 1
  179. if count > 10:
  180. raise Exception("Did not receive Accounting-Response packets")
  181. if int(mib['radiusAccClientRetransmissions']) > 0:
  182. raise Exception("Unexpected Accounting-Request retransmission")
  183. as_mib_end = as_hapd.get_mib(param="radius_server")
  184. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  185. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  186. if req_e < req_s + 2:
  187. raise Exception("Unexpected RADIUS server acct MIB value")
  188. acc_s = int(as_mib_start['radiusAuthServAccessAccepts'])
  189. acc_e = int(as_mib_end['radiusAuthServAccessAccepts'])
  190. if acc_e < acc_s + 1:
  191. raise Exception("Unexpected RADIUS server auth MIB value")
  192. def test_radius_acct_pmksa_caching(dev, apdev):
  193. """RADIUS Accounting with PMKSA caching"""
  194. as_hapd = hostapd.Hostapd("as")
  195. as_mib_start = as_hapd.get_mib(param="radius_server")
  196. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  197. params['acct_server_addr'] = "127.0.0.1"
  198. params['acct_server_port'] = "1813"
  199. params['acct_server_shared_secret'] = "radius"
  200. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  201. connect(dev[0], "radius-acct")
  202. dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
  203. eap="PAX", identity="test-class",
  204. password_hex="0123456789abcdef0123456789abcdef")
  205. for d in [ dev[0], dev[1] ]:
  206. d.request("REASSOCIATE")
  207. d.wait_connected(timeout=15, error="Reassociation timed out")
  208. count = 0
  209. while True:
  210. mib = hapd.get_mib()
  211. if int(mib['radiusAccClientResponses']) >= 4:
  212. break
  213. time.sleep(0.1)
  214. count += 1
  215. if count > 10:
  216. raise Exception("Did not receive Accounting-Response packets")
  217. if int(mib['radiusAccClientRetransmissions']) > 0:
  218. raise Exception("Unexpected Accounting-Request retransmission")
  219. as_mib_end = as_hapd.get_mib(param="radius_server")
  220. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  221. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  222. if req_e < req_s + 2:
  223. raise Exception("Unexpected RADIUS server acct MIB value")
  224. acc_s = int(as_mib_start['radiusAuthServAccessAccepts'])
  225. acc_e = int(as_mib_end['radiusAuthServAccessAccepts'])
  226. if acc_e < acc_s + 1:
  227. raise Exception("Unexpected RADIUS server auth MIB value")
  228. def test_radius_acct_interim(dev, apdev):
  229. """RADIUS Accounting interim update"""
  230. as_hapd = hostapd.Hostapd("as")
  231. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  232. params['acct_server_addr'] = "127.0.0.1"
  233. params['acct_server_port'] = "1813"
  234. params['acct_server_shared_secret'] = "radius"
  235. params['radius_acct_interim_interval'] = "1"
  236. hostapd.add_ap(apdev[0]['ifname'], params)
  237. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  238. connect(dev[0], "radius-acct")
  239. logger.info("Checking for RADIUS counters")
  240. as_mib_start = as_hapd.get_mib(param="radius_server")
  241. time.sleep(3.1)
  242. as_mib_end = as_hapd.get_mib(param="radius_server")
  243. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  244. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  245. if req_e < req_s + 3:
  246. raise Exception("Unexpected RADIUS server acct MIB value")
  247. def test_radius_acct_interim_unreachable(dev, apdev):
  248. """RADIUS Accounting interim update with unreachable server"""
  249. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  250. params['acct_server_addr'] = "127.0.0.1"
  251. params['acct_server_port'] = "18139"
  252. params['acct_server_shared_secret'] = "radius"
  253. params['radius_acct_interim_interval'] = "1"
  254. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  255. start = hapd.get_mib()
  256. connect(dev[0], "radius-acct")
  257. logger.info("Waiting for interium accounting updates")
  258. time.sleep(3.1)
  259. end = hapd.get_mib()
  260. req_s = int(start['radiusAccClientTimeouts'])
  261. req_e = int(end['radiusAccClientTimeouts'])
  262. if req_e < req_s + 2:
  263. raise Exception("Unexpected RADIUS server acct MIB value")
  264. def send_and_check_reply(srv, req, code, error_cause=0):
  265. reply = srv.SendPacket(req)
  266. logger.debug("RADIUS response from hostapd")
  267. for i in reply.keys():
  268. logger.debug("%s: %s" % (i, reply[i]))
  269. if reply.code != code:
  270. raise Exception("Unexpected response code")
  271. if error_cause:
  272. if 'Error-Cause' not in reply:
  273. raise Exception("Missing Error-Cause")
  274. if reply['Error-Cause'][0] != error_cause:
  275. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  276. def test_radius_das_disconnect(dev, apdev):
  277. """RADIUS Dynamic Authorization Extensions - Disconnect"""
  278. try:
  279. import pyrad.client
  280. import pyrad.packet
  281. import pyrad.dictionary
  282. import radius_das
  283. except ImportError:
  284. raise HwsimSkip("No pyrad modules available")
  285. params = hostapd.wpa2_eap_params(ssid="radius-das")
  286. params['radius_das_port'] = "3799"
  287. params['radius_das_client'] = "127.0.0.1 secret"
  288. params['radius_das_require_event_timestamp'] = "1"
  289. params['own_ip_addr'] = "127.0.0.1"
  290. params['nas_identifier'] = "nas.example.com"
  291. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  292. connect(dev[0], "radius-das")
  293. addr = dev[0].p2p_interface_addr()
  294. sta = hapd.get_sta(addr)
  295. id = sta['dot1xAuthSessionId']
  296. dict = pyrad.dictionary.Dictionary("dictionary.radius")
  297. srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
  298. secret="secret", dict=dict)
  299. srv.retries = 1
  300. srv.timeout = 1
  301. logger.info("Disconnect-Request with incorrect secret")
  302. req = radius_das.DisconnectPacket(dict=dict, secret="incorrect",
  303. User_Name="foo",
  304. NAS_Identifier="localhost",
  305. Event_Timestamp=int(time.time()))
  306. logger.debug(req)
  307. try:
  308. reply = srv.SendPacket(req)
  309. raise Exception("Unexpected response to Disconnect-Request")
  310. except pyrad.client.Timeout:
  311. logger.info("Disconnect-Request with incorrect secret properly ignored")
  312. logger.info("Disconnect-Request without Event-Timestamp")
  313. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  314. User_Name="psk.user@example.com")
  315. logger.debug(req)
  316. try:
  317. reply = srv.SendPacket(req)
  318. raise Exception("Unexpected response to Disconnect-Request")
  319. except pyrad.client.Timeout:
  320. logger.info("Disconnect-Request without Event-Timestamp properly ignored")
  321. logger.info("Disconnect-Request with non-matching Event-Timestamp")
  322. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  323. User_Name="psk.user@example.com",
  324. Event_Timestamp=123456789)
  325. logger.debug(req)
  326. try:
  327. reply = srv.SendPacket(req)
  328. raise Exception("Unexpected response to Disconnect-Request")
  329. except pyrad.client.Timeout:
  330. logger.info("Disconnect-Request with non-matching Event-Timestamp properly ignored")
  331. logger.info("Disconnect-Request with unsupported attribute")
  332. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  333. User_Name="foo",
  334. User_Password="foo",
  335. Event_Timestamp=int(time.time()))
  336. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 401)
  337. logger.info("Disconnect-Request with invalid Calling-Station-Id")
  338. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  339. User_Name="foo",
  340. Calling_Station_Id="foo",
  341. Event_Timestamp=int(time.time()))
  342. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 407)
  343. logger.info("Disconnect-Request with mismatching User-Name")
  344. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  345. User_Name="foo",
  346. Event_Timestamp=int(time.time()))
  347. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  348. logger.info("Disconnect-Request with mismatching Calling-Station-Id")
  349. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  350. Calling_Station_Id="12:34:56:78:90:aa",
  351. Event_Timestamp=int(time.time()))
  352. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  353. logger.info("Disconnect-Request with mismatching Acct-Session-Id")
  354. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  355. Acct_Session_Id="12345678-87654321",
  356. Event_Timestamp=int(time.time()))
  357. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  358. logger.info("Disconnect-Request with mismatching Acct-Session-Id (len)")
  359. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  360. Acct_Session_Id="12345678",
  361. Event_Timestamp=int(time.time()))
  362. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  363. logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id")
  364. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  365. Acct_Multi_Session_Id="12345678+87654321",
  366. Event_Timestamp=int(time.time()))
  367. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  368. logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id (len)")
  369. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  370. Acct_Multi_Session_Id="12345678",
  371. Event_Timestamp=int(time.time()))
  372. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  373. logger.info("Disconnect-Request with no session identification attributes")
  374. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  375. Event_Timestamp=int(time.time()))
  376. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
  377. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  378. if ev is not None:
  379. raise Exception("Unexpected disconnection")
  380. logger.info("Disconnect-Request with mismatching NAS-IP-Address")
  381. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  382. NAS_IP_Address="192.168.3.4",
  383. Acct_Session_Id=id,
  384. Event_Timestamp=int(time.time()))
  385. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
  386. logger.info("Disconnect-Request with mismatching NAS-Identifier")
  387. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  388. NAS_Identifier="unknown.example.com",
  389. Acct_Session_Id=id,
  390. Event_Timestamp=int(time.time()))
  391. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
  392. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  393. if ev is not None:
  394. raise Exception("Unexpected disconnection")
  395. logger.info("Disconnect-Request with matching Acct-Session-Id")
  396. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  397. NAS_IP_Address="127.0.0.1",
  398. NAS_Identifier="nas.example.com",
  399. Acct_Session_Id=id,
  400. Event_Timestamp=int(time.time()))
  401. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  402. dev[0].wait_disconnected(timeout=10)
  403. dev[0].wait_connected(timeout=10, error="Re-connection timed out")
  404. logger.info("Disconnect-Request with matching Acct-Multi-Session-Id")
  405. sta = hapd.get_sta(addr)
  406. multi_sess_id = sta['authMultiSessionId']
  407. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  408. NAS_IP_Address="127.0.0.1",
  409. NAS_Identifier="nas.example.com",
  410. Acct_Multi_Session_Id=multi_sess_id,
  411. Event_Timestamp=int(time.time()))
  412. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  413. dev[0].wait_disconnected(timeout=10)
  414. dev[0].wait_connected(timeout=10, error="Re-connection timed out")
  415. logger.info("Disconnect-Request with matching User-Name")
  416. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  417. NAS_Identifier="nas.example.com",
  418. User_Name="psk.user@example.com",
  419. Event_Timestamp=int(time.time()))
  420. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  421. dev[0].wait_disconnected(timeout=10)
  422. dev[0].wait_connected(timeout=10, error="Re-connection timed out")
  423. logger.info("Disconnect-Request with matching Calling-Station-Id")
  424. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  425. NAS_IP_Address="127.0.0.1",
  426. Calling_Station_Id=addr,
  427. Event_Timestamp=int(time.time()))
  428. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  429. dev[0].wait_disconnected(timeout=10)
  430. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", "CTRL-EVENT-CONNECTED"])
  431. if ev is None:
  432. raise Exception("Timeout while waiting for re-connection")
  433. if "CTRL-EVENT-EAP-STARTED" not in ev:
  434. raise Exception("Unexpected skipping of EAP authentication in reconnection")
  435. dev[0].wait_connected(timeout=10, error="Re-connection timed out")
  436. logger.info("Disconnect-Request with matching Calling-Station-Id and non-matching CUI")
  437. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  438. Calling_Station_Id=addr,
  439. Chargeable_User_Identity="foo@example.com",
  440. Event_Timestamp=int(time.time()))
  441. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
  442. logger.info("Disconnect-Request with matching CUI")
  443. dev[1].connect("radius-das", key_mgmt="WPA-EAP",
  444. eap="GPSK", identity="gpsk-cui",
  445. password="abcdefghijklmnop0123456789abcdef",
  446. scan_freq="2412")
  447. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  448. Chargeable_User_Identity="gpsk-chargeable-user-identity",
  449. Event_Timestamp=int(time.time()))
  450. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  451. dev[1].wait_disconnected(timeout=10)
  452. dev[1].wait_connected(timeout=10, error="Re-connection timed out")
  453. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  454. if ev is not None:
  455. raise Exception("Unexpected disconnection")
  456. connect(dev[2], "radius-das")
  457. logger.info("Disconnect-Request with matching User-Name - multiple sessions matching")
  458. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  459. NAS_Identifier="nas.example.com",
  460. User_Name="psk.user@example.com",
  461. Event_Timestamp=int(time.time()))
  462. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=508)
  463. logger.info("Disconnect-Request with User-Name matching multiple sessions, Calling-Station-Id only one")
  464. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  465. NAS_Identifier="nas.example.com",
  466. Calling_Station_Id=addr,
  467. User_Name="psk.user@example.com",
  468. Event_Timestamp=int(time.time()))
  469. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  470. dev[0].wait_disconnected(timeout=10)
  471. dev[0].wait_connected(timeout=10, error="Re-connection timed out")
  472. ev = dev[2].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  473. if ev is not None:
  474. raise Exception("Unexpected disconnection")
  475. logger.info("Disconnect-Request with matching Acct-Multi-Session-Id after disassociation")
  476. sta = hapd.get_sta(addr)
  477. multi_sess_id = sta['authMultiSessionId']
  478. dev[0].request("DISCONNECT")
  479. dev[0].wait_disconnected(timeout=10)
  480. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  481. NAS_IP_Address="127.0.0.1",
  482. NAS_Identifier="nas.example.com",
  483. Acct_Multi_Session_Id=multi_sess_id,
  484. Event_Timestamp=int(time.time()))
  485. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  486. dev[0].request("RECONNECT")
  487. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
  488. if ev is None:
  489. raise Exception("Timeout on EAP start")
  490. dev[0].wait_connected(timeout=15)
  491. logger.info("Disconnect-Request with matching User-Name after disassociation")
  492. dev[0].request("DISCONNECT")
  493. dev[0].wait_disconnected(timeout=10)
  494. dev[2].request("DISCONNECT")
  495. dev[2].wait_disconnected(timeout=10)
  496. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  497. NAS_IP_Address="127.0.0.1",
  498. NAS_Identifier="nas.example.com",
  499. User_Name="psk.user@example.com",
  500. Event_Timestamp=int(time.time()))
  501. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  502. logger.info("Disconnect-Request with matching CUI after disassociation")
  503. dev[1].request("DISCONNECT")
  504. dev[1].wait_disconnected(timeout=10)
  505. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  506. NAS_IP_Address="127.0.0.1",
  507. NAS_Identifier="nas.example.com",
  508. Chargeable_User_Identity="gpsk-chargeable-user-identity",
  509. Event_Timestamp=int(time.time()))
  510. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  511. logger.info("Disconnect-Request with matching Calling-Station-Id after disassociation")
  512. dev[0].request("RECONNECT")
  513. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
  514. if ev is None:
  515. raise Exception("Timeout on EAP start")
  516. dev[0].wait_connected(timeout=15)
  517. dev[0].request("DISCONNECT")
  518. dev[0].wait_disconnected(timeout=10)
  519. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  520. NAS_IP_Address="127.0.0.1",
  521. NAS_Identifier="nas.example.com",
  522. Calling_Station_Id=addr,
  523. Event_Timestamp=int(time.time()))
  524. send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
  525. logger.info("Disconnect-Request with mismatching Calling-Station-Id after disassociation")
  526. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  527. NAS_IP_Address="127.0.0.1",
  528. NAS_Identifier="nas.example.com",
  529. Calling_Station_Id=addr,
  530. Event_Timestamp=int(time.time()))
  531. send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
  532. def test_radius_das_coa(dev, apdev):
  533. """RADIUS Dynamic Authorization Extensions - CoA"""
  534. try:
  535. import pyrad.client
  536. import pyrad.packet
  537. import pyrad.dictionary
  538. import radius_das
  539. except ImportError:
  540. raise HwsimSkip("No pyrad modules available")
  541. params = hostapd.wpa2_eap_params(ssid="radius-das")
  542. params['radius_das_port'] = "3799"
  543. params['radius_das_client'] = "127.0.0.1 secret"
  544. params['radius_das_require_event_timestamp'] = "1"
  545. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  546. connect(dev[0], "radius-das")
  547. addr = dev[0].p2p_interface_addr()
  548. sta = hapd.get_sta(addr)
  549. id = sta['dot1xAuthSessionId']
  550. dict = pyrad.dictionary.Dictionary("dictionary.radius")
  551. srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
  552. secret="secret", dict=dict)
  553. srv.retries = 1
  554. srv.timeout = 1
  555. # hostapd does not currently support CoA-Request, so NAK is expected
  556. logger.info("CoA-Request with matching Acct-Session-Id")
  557. req = radius_das.CoAPacket(dict=dict, secret="secret",
  558. Acct_Session_Id=id,
  559. Event_Timestamp=int(time.time()))
  560. send_and_check_reply(srv, req, pyrad.packet.CoANAK, error_cause=405)
  561. def test_radius_ipv6(dev, apdev):
  562. """RADIUS connection over IPv6"""
  563. params = {}
  564. params['ssid'] = 'as'
  565. params['beacon_int'] = '2000'
  566. params['radius_server_clients'] = 'auth_serv/radius_clients_ipv6.conf'
  567. params['radius_server_ipv6'] = '1'
  568. params['radius_server_auth_port'] = '18129'
  569. params['radius_server_acct_port'] = '18139'
  570. params['eap_server'] = '1'
  571. params['eap_user_file'] = 'auth_serv/eap_user.conf'
  572. params['ca_cert'] = 'auth_serv/ca.pem'
  573. params['server_cert'] = 'auth_serv/server.pem'
  574. params['private_key'] = 'auth_serv/server.key'
  575. hostapd.add_ap(apdev[1]['ifname'], params)
  576. params = hostapd.wpa2_eap_params(ssid="radius-ipv6")
  577. params['auth_server_addr'] = "::0"
  578. params['auth_server_port'] = "18129"
  579. params['acct_server_addr'] = "::0"
  580. params['acct_server_port'] = "18139"
  581. params['acct_server_shared_secret'] = "radius"
  582. params['own_ip_addr'] = "::0"
  583. hostapd.add_ap(apdev[0]['ifname'], params)
  584. connect(dev[0], "radius-ipv6")
  585. def test_radius_macacl(dev, apdev):
  586. """RADIUS MAC ACL"""
  587. params = hostapd.radius_params()
  588. params["ssid"] = "radius"
  589. params["macaddr_acl"] = "2"
  590. hostapd.add_ap(apdev[0]['ifname'], params)
  591. dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
  592. def test_radius_macacl_acct(dev, apdev):
  593. """RADIUS MAC ACL and accounting enabled"""
  594. params = hostapd.radius_params()
  595. params["ssid"] = "radius"
  596. params["macaddr_acl"] = "2"
  597. params['acct_server_addr'] = "127.0.0.1"
  598. params['acct_server_port'] = "1813"
  599. params['acct_server_shared_secret'] = "radius"
  600. hostapd.add_ap(apdev[0]['ifname'], params)
  601. dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
  602. dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412")
  603. dev[1].request("DISCONNECT")
  604. dev[1].wait_disconnected()
  605. dev[1].request("RECONNECT")
  606. def test_radius_failover(dev, apdev):
  607. """RADIUS Authentication and Accounting server failover"""
  608. subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
  609. as_hapd = hostapd.Hostapd("as")
  610. as_mib_start = as_hapd.get_mib(param="radius_server")
  611. params = hostapd.wpa2_eap_params(ssid="radius-failover")
  612. params["auth_server_addr"] = "192.168.213.17"
  613. params["auth_server_port"] = "1812"
  614. params["auth_server_shared_secret"] = "testing"
  615. params['acct_server_addr'] = "192.168.213.17"
  616. params['acct_server_port'] = "1813"
  617. params['acct_server_shared_secret'] = "testing"
  618. params['radius_retry_primary_interval'] = "20"
  619. hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
  620. hapd.set("auth_server_addr", "127.0.0.1")
  621. hapd.set("auth_server_port", "1812")
  622. hapd.set("auth_server_shared_secret", "radius")
  623. hapd.set('acct_server_addr', "127.0.0.1")
  624. hapd.set('acct_server_port', "1813")
  625. hapd.set('acct_server_shared_secret', "radius")
  626. hapd.enable()
  627. ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=30)
  628. if ev is None:
  629. raise Exception("AP startup timed out")
  630. if "AP-ENABLED" not in ev:
  631. raise Exception("AP startup failed")
  632. start = os.times()[4]
  633. try:
  634. subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
  635. dev[0].request("SET EAPOL::authPeriod 5")
  636. connect(dev[0], "radius-failover", wait_connect=False)
  637. dev[0].wait_connected(timeout=20)
  638. finally:
  639. dev[0].request("SET EAPOL::authPeriod 30")
  640. subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
  641. as_mib_end = as_hapd.get_mib(param="radius_server")
  642. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  643. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  644. if req_e <= req_s:
  645. raise Exception("Unexpected RADIUS server acct MIB value")
  646. end = os.times()[4]
  647. try:
  648. subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
  649. dev[1].request("SET EAPOL::authPeriod 5")
  650. if end - start < 21:
  651. time.sleep(21 - (end - start))
  652. connect(dev[1], "radius-failover", wait_connect=False)
  653. dev[1].wait_connected(timeout=20)
  654. finally:
  655. dev[1].request("SET EAPOL::authPeriod 30")
  656. subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
  657. def run_pyrad_server(srv, t_events):
  658. srv.RunWithStop(t_events)
  659. def test_radius_protocol(dev, apdev):
  660. """RADIUS Authentication protocol tests with a fake server"""
  661. try:
  662. import pyrad.server
  663. import pyrad.packet
  664. import pyrad.dictionary
  665. except ImportError:
  666. raise HwsimSkip("No pyrad modules available")
  667. class TestServer(pyrad.server.Server):
  668. def _HandleAuthPacket(self, pkt):
  669. pyrad.server.Server._HandleAuthPacket(self, pkt)
  670. logger.info("Received authentication request")
  671. reply = self.CreateReplyPacket(pkt)
  672. reply.code = pyrad.packet.AccessAccept
  673. if self.t_events['msg_auth'].is_set():
  674. logger.info("Add Message-Authenticator")
  675. if self.t_events['wrong_secret'].is_set():
  676. logger.info("Use incorrect RADIUS shared secret")
  677. pw = "incorrect"
  678. else:
  679. pw = reply.secret
  680. hmac_obj = hmac.new(pw)
  681. hmac_obj.update(struct.pack("B", reply.code))
  682. hmac_obj.update(struct.pack("B", reply.id))
  683. # reply attributes
  684. reply.AddAttribute("Message-Authenticator",
  685. "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
  686. attrs = reply._PktEncodeAttributes()
  687. # Length
  688. flen = 4 + 16 + len(attrs)
  689. hmac_obj.update(struct.pack(">H", flen))
  690. hmac_obj.update(pkt.authenticator)
  691. hmac_obj.update(attrs)
  692. if self.t_events['double_msg_auth'].is_set():
  693. logger.info("Include two Message-Authenticator attributes")
  694. else:
  695. del reply[80]
  696. reply.AddAttribute("Message-Authenticator", hmac_obj.digest())
  697. self.SendReplyPacket(pkt.fd, reply)
  698. def RunWithStop(self, t_events):
  699. self._poll = select.poll()
  700. self._fdmap = {}
  701. self._PrepareSockets()
  702. self.t_events = t_events
  703. while not t_events['stop'].is_set():
  704. for (fd, event) in self._poll.poll(1000):
  705. if event == select.POLLIN:
  706. try:
  707. fdo = self._fdmap[fd]
  708. self._ProcessInput(fdo)
  709. except ServerPacketError as err:
  710. logger.info("pyrad server dropping packet: " + str(err))
  711. except pyrad.packet.PacketError as err:
  712. logger.info("pyrad server received invalid packet: " + str(err))
  713. else:
  714. logger.error("Unexpected event in pyrad server main loop")
  715. srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
  716. authport=18138, acctport=18139)
  717. srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
  718. "radius",
  719. "localhost")
  720. srv.BindToAddress("")
  721. t_events = {}
  722. t_events['stop'] = threading.Event()
  723. t_events['msg_auth'] = threading.Event()
  724. t_events['wrong_secret'] = threading.Event()
  725. t_events['double_msg_auth'] = threading.Event()
  726. t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
  727. t.start()
  728. try:
  729. params = hostapd.wpa2_eap_params(ssid="radius-test")
  730. params['auth_server_port'] = "18138"
  731. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  732. connect(dev[0], "radius-test", wait_connect=False)
  733. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
  734. if ev is None:
  735. raise Exception("Timeout on EAP start")
  736. time.sleep(1)
  737. dev[0].request("REMOVE_NETWORK all")
  738. time.sleep(0.1)
  739. dev[0].dump_monitor()
  740. t_events['msg_auth'].set()
  741. t_events['wrong_secret'].set()
  742. connect(dev[0], "radius-test", wait_connect=False)
  743. time.sleep(1)
  744. dev[0].request("REMOVE_NETWORK all")
  745. time.sleep(0.1)
  746. dev[0].dump_monitor()
  747. t_events['wrong_secret'].clear()
  748. connect(dev[0], "radius-test", wait_connect=False)
  749. time.sleep(1)
  750. dev[0].request("REMOVE_NETWORK all")
  751. time.sleep(0.1)
  752. dev[0].dump_monitor()
  753. t_events['double_msg_auth'].set()
  754. connect(dev[0], "radius-test", wait_connect=False)
  755. time.sleep(1)
  756. finally:
  757. t_events['stop'].set()
  758. t.join()
  759. def test_radius_psk(dev, apdev):
  760. """WPA2 with PSK from RADIUS"""
  761. try:
  762. import pyrad.server
  763. import pyrad.packet
  764. import pyrad.dictionary
  765. except ImportError:
  766. raise HwsimSkip("No pyrad modules available")
  767. class TestServer(pyrad.server.Server):
  768. def _HandleAuthPacket(self, pkt):
  769. pyrad.server.Server._HandleAuthPacket(self, pkt)
  770. logger.info("Received authentication request")
  771. reply = self.CreateReplyPacket(pkt)
  772. reply.code = pyrad.packet.AccessAccept
  773. a = "\xab\xcd"
  774. secret = reply.secret
  775. if self.t_events['long'].is_set():
  776. p = b'\x10' + "0123456789abcdef" + 15 * b'\x00'
  777. b = hashlib.md5(secret + pkt.authenticator + a).digest()
  778. pp = bytearray(p[0:16])
  779. bb = bytearray(b)
  780. cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
  781. b = hashlib.md5(reply.secret + bytes(cc)).digest()
  782. pp = bytearray(p[16:32])
  783. bb = bytearray(b)
  784. cc += bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
  785. data = '\x00' + a + bytes(cc)
  786. else:
  787. p = b'\x08' + "12345678" + 7 * b'\x00'
  788. b = hashlib.md5(secret + pkt.authenticator + a).digest()
  789. pp = bytearray(p)
  790. bb = bytearray(b)
  791. cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
  792. data = '\x00' + a + bytes(cc)
  793. reply.AddAttribute("Tunnel-Password", data)
  794. self.SendReplyPacket(pkt.fd, reply)
  795. def RunWithStop(self, t_events):
  796. self._poll = select.poll()
  797. self._fdmap = {}
  798. self._PrepareSockets()
  799. self.t_events = t_events
  800. while not t_events['stop'].is_set():
  801. for (fd, event) in self._poll.poll(1000):
  802. if event == select.POLLIN:
  803. try:
  804. fdo = self._fdmap[fd]
  805. self._ProcessInput(fdo)
  806. except ServerPacketError as err:
  807. logger.info("pyrad server dropping packet: " + str(err))
  808. except pyrad.packet.PacketError as err:
  809. logger.info("pyrad server received invalid packet: " + str(err))
  810. else:
  811. logger.error("Unexpected event in pyrad server main loop")
  812. srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
  813. authport=18138, acctport=18139)
  814. srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
  815. "radius",
  816. "localhost")
  817. srv.BindToAddress("")
  818. t_events = {}
  819. t_events['stop'] = threading.Event()
  820. t_events['long'] = threading.Event()
  821. t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
  822. t.start()
  823. try:
  824. ssid = "test-wpa2-psk"
  825. params = hostapd.radius_params()
  826. params['ssid'] = ssid
  827. params["wpa"] = "2"
  828. params["wpa_key_mgmt"] = "WPA-PSK"
  829. params["rsn_pairwise"] = "CCMP"
  830. params['macaddr_acl'] = '2'
  831. params['wpa_psk_radius'] = '2'
  832. params['auth_server_port'] = "18138"
  833. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  834. dev[0].connect(ssid, psk="12345678", scan_freq="2412")
  835. t_events['long'].set()
  836. dev[1].connect(ssid, psk="0123456789abcdef", scan_freq="2412")
  837. finally:
  838. t_events['stop'].set()
  839. t.join()
  840. def test_radius_auth_force_client_addr(dev, apdev):
  841. """RADIUS client address specified"""
  842. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  843. params['radius_client_addr'] = "127.0.0.1"
  844. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  845. connect(dev[0], "radius-auth")
  846. def test_radius_auth_force_invalid_client_addr(dev, apdev):
  847. """RADIUS client address specified and invalid address"""
  848. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  849. #params['radius_client_addr'] = "10.11.12.14"
  850. params['radius_client_addr'] = "1::2"
  851. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  852. connect(dev[0], "radius-auth", wait_connect=False)
  853. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  854. if ev is None:
  855. raise Exception("Timeout on EAP start")
  856. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
  857. if ev is not None:
  858. raise Exception("Unexpected connection")
  859. def add_message_auth(req):
  860. req.authenticator = req.CreateAuthenticator()
  861. hmac_obj = hmac.new(req.secret)
  862. hmac_obj.update(struct.pack("B", req.code))
  863. hmac_obj.update(struct.pack("B", req.id))
  864. # request attributes
  865. req.AddAttribute("Message-Authenticator",
  866. "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
  867. attrs = req._PktEncodeAttributes()
  868. # Length
  869. flen = 4 + 16 + len(attrs)
  870. hmac_obj.update(struct.pack(">H", flen))
  871. hmac_obj.update(req.authenticator)
  872. hmac_obj.update(attrs)
  873. del req[80]
  874. req.AddAttribute("Message-Authenticator", hmac_obj.digest())
  875. def test_radius_server_failures(dev, apdev):
  876. """RADIUS server failure cases"""
  877. try:
  878. import pyrad.client
  879. import pyrad.packet
  880. import pyrad.dictionary
  881. except ImportError:
  882. raise HwsimSkip("No pyrad modules available")
  883. dict = pyrad.dictionary.Dictionary("dictionary.radius")
  884. client = pyrad.client.Client(server="127.0.0.1", authport=1812,
  885. secret="radius", dict=dict)
  886. client.retries = 1
  887. client.timeout = 1
  888. # unexpected State
  889. req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
  890. User_Name="foo")
  891. req['State'] = 'foo-state'
  892. add_message_auth(req)
  893. reply = client.SendPacket(req)
  894. if reply.code != pyrad.packet.AccessReject:
  895. raise Exception("Unexpected RADIUS response code " + str(reply.code))
  896. # no EAP-Message
  897. req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
  898. User_Name="foo")
  899. add_message_auth(req)
  900. try:
  901. reply = client.SendPacket(req)
  902. raise Exception("Unexpected response")
  903. except pyrad.client.Timeout:
  904. pass