1# RADIUS tests 2# Copyright (c) 2013-2024, 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 7from remotehost import remote_compatible 8import binascii 9import hashlib 10import hmac 11import logging 12logger = logging.getLogger() 13import os 14import select 15import signal 16import struct 17import subprocess 18import threading 19import time 20 21import hostapd 22from utils import * 23from test_ap_hs20 import build_dhcp_ack 24from test_ap_ft import ft_params1 25from test_eap_proto import add_message_authenticator_attr, build_message_auth 26 27def connect(dev, ssid, wait_connect=True): 28 dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412", 29 eap="PSK", identity="psk.user@example.com", 30 password_hex="0123456789abcdef0123456789abcdef", 31 wait_connect=wait_connect) 32 33@remote_compatible 34def test_radius_auth_unreachable(dev, apdev): 35 """RADIUS Authentication server unreachable""" 36 params = hostapd.wpa2_eap_params(ssid="radius-auth") 37 params['auth_server_port'] = "18139" 38 hapd = hostapd.add_ap(apdev[0], params) 39 connect(dev[0], "radius-auth", wait_connect=False) 40 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"]) 41 if ev is None: 42 raise Exception("Timeout on EAP start") 43 logger.info("Checking for RADIUS retries") 44 time.sleep(4) 45 mib = hapd.get_mib() 46 if "radiusAuthClientAccessRequests" not in mib: 47 raise Exception("Missing MIB fields") 48 if int(mib["radiusAuthClientAccessRetransmissions"]) < 1: 49 raise Exception("Missing RADIUS Authentication retransmission") 50 if int(mib["radiusAuthClientPendingRequests"]) < 1: 51 raise Exception("Missing pending RADIUS Authentication request") 52 53def test_radius_auth_unreachable2(dev, apdev): 54 """RADIUS Authentication server unreachable (2)""" 55 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo']) 56 params = hostapd.wpa2_eap_params(ssid="radius-auth") 57 params['auth_server_addr'] = "192.168.213.17" 58 params['auth_server_port'] = "18139" 59 hapd = hostapd.add_ap(apdev[0], params) 60 subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo']) 61 connect(dev[0], "radius-auth", wait_connect=False) 62 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"]) 63 if ev is None: 64 raise Exception("Timeout on EAP start") 65 logger.info("Checking for RADIUS retries") 66 time.sleep(4) 67 mib = hapd.get_mib() 68 if "radiusAuthClientAccessRequests" not in mib: 69 raise Exception("Missing MIB fields") 70 logger.info("radiusAuthClientAccessRetransmissions: " + mib["radiusAuthClientAccessRetransmissions"]) 71 72def test_radius_auth_unreachable3(dev, apdev): 73 """RADIUS Authentication server initially unreachable, but then available""" 74 subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18']) 75 params = hostapd.wpa2_eap_params(ssid="radius-auth") 76 params['auth_server_addr'] = "192.168.213.18" 77 hapd = hostapd.add_ap(apdev[0], params) 78 connect(dev[0], "radius-auth", wait_connect=False) 79 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"]) 80 if ev is None: 81 raise Exception("Timeout on EAP start") 82 subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18']) 83 time.sleep(0.1) 84 dev[0].request("DISCONNECT") 85 hapd.set('auth_server_addr_replace', '127.0.0.1') 86 dev[0].request("RECONNECT") 87 88 dev[0].wait_connected() 89 90def test_radius_acct_unreachable(dev, apdev): 91 """RADIUS Accounting server unreachable""" 92 params = hostapd.wpa2_eap_params(ssid="radius-acct") 93 params['acct_server_addr'] = "127.0.0.1" 94 params['acct_server_port'] = "18139" 95 params['acct_server_shared_secret'] = "radius" 96 hapd = hostapd.add_ap(apdev[0], params) 97 connect(dev[0], "radius-acct") 98 logger.info("Checking for RADIUS retries") 99 time.sleep(4) 100 mib = hapd.get_mib() 101 if "radiusAccClientRetransmissions" not in mib: 102 raise Exception("Missing MIB fields") 103 if int(mib["radiusAccClientRetransmissions"]) < 2: 104 raise Exception("Missing RADIUS Accounting retransmissions") 105 if int(mib["radiusAccClientPendingRequests"]) < 2: 106 raise Exception("Missing pending RADIUS Accounting requests") 107 108def test_radius_acct_unreachable2(dev, apdev): 109 """RADIUS Accounting server unreachable(2)""" 110 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo']) 111 params = hostapd.wpa2_eap_params(ssid="radius-acct") 112 params['acct_server_addr'] = "192.168.213.17" 113 params['acct_server_port'] = "18139" 114 params['acct_server_shared_secret'] = "radius" 115 hapd = hostapd.add_ap(apdev[0], params) 116 subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo']) 117 connect(dev[0], "radius-acct") 118 logger.info("Checking for RADIUS retries") 119 found = False 120 for i in range(4): 121 time.sleep(1) 122 mib = hapd.get_mib() 123 if "radiusAccClientRetransmissions" not in mib: 124 raise Exception("Missing MIB fields") 125 if int(mib["radiusAccClientRetransmissions"]) > 0 or \ 126 int(mib["radiusAccClientPendingRequests"]) > 0: 127 found = True 128 if not found: 129 raise Exception("Missing pending or retransmitted RADIUS Accounting requests") 130 131def test_radius_acct_unreachable3(dev, apdev): 132 """RADIUS Accounting server initially unreachable, but then available""" 133 require_under_vm() 134 subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18']) 135 as_hapd = hostapd.Hostapd("as") 136 as_mib_start = as_hapd.get_mib(param="radius_server") 137 params = hostapd.wpa2_eap_params(ssid="radius-acct") 138 params['acct_server_addr'] = "192.168.213.18" 139 params['acct_server_port'] = "1813" 140 params['acct_server_shared_secret'] = "radius" 141 hapd = hostapd.add_ap(apdev[0], params) 142 connect(dev[0], "radius-acct") 143 subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18']) 144 time.sleep(0.1) 145 dev[0].request("DISCONNECT") 146 hapd.set('acct_server_addr_replace', '127.0.0.1') 147 dev[0].request("RECONNECT") 148 dev[0].wait_connected() 149 time.sleep(1) 150 as_mib_end = as_hapd.get_mib(param="radius_server") 151 req_s = int(as_mib_start['radiusAccServTotalResponses']) 152 req_e = int(as_mib_end['radiusAccServTotalResponses']) 153 if req_e <= req_s: 154 raise Exception("Unexpected RADIUS server acct MIB value") 155 156def test_radius_acct_unreachable4(dev, apdev): 157 """RADIUS Accounting server unreachable and multiple STAs""" 158 params = hostapd.wpa2_eap_params(ssid="radius-acct") 159 params['acct_server_addr'] = "127.0.0.1" 160 params['acct_server_port'] = "18139" 161 params['acct_server_shared_secret'] = "radius" 162 hapd = hostapd.add_ap(apdev[0], params) 163 for i in range(20): 164 connect(dev[0], "radius-acct") 165 dev[0].request("REMOVE_NETWORK all") 166 dev[0].wait_disconnected() 167 168def test_radius_acct(dev, apdev): 169 """RADIUS Accounting""" 170 as_hapd = hostapd.Hostapd("as") 171 as_mib_start = as_hapd.get_mib(param="radius_server") 172 params = hostapd.wpa2_eap_params(ssid="radius-acct") 173 params['acct_server_addr'] = "127.0.0.1" 174 params['acct_server_port'] = "1813" 175 params['acct_server_shared_secret'] = "radius" 176 params['radius_auth_req_attr'] = ["126:s:Operator", "77:s:testing", 177 "62:d:1"] 178 params['radius_acct_req_attr'] = ["126:s:Operator", "62:d:1", 179 "77:s:testing"] 180 hapd = hostapd.add_ap(apdev[0], params) 181 connect(dev[0], "radius-acct") 182 dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412", 183 eap="PAX", identity="test-class", 184 password_hex="0123456789abcdef0123456789abcdef") 185 dev[2].connect("radius-acct", key_mgmt="WPA-EAP", 186 eap="GPSK", identity="gpsk-cui", 187 password="abcdefghijklmnop0123456789abcdef", 188 scan_freq="2412") 189 logger.info("Checking for RADIUS counters") 190 count = 0 191 while True: 192 mib = hapd.get_mib() 193 if int(mib['radiusAccClientResponses']) >= 3: 194 break 195 time.sleep(0.1) 196 count += 1 197 if count > 10: 198 raise Exception("Did not receive Accounting-Response packets") 199 200 if int(mib['radiusAccClientRetransmissions']) > 0: 201 raise Exception("Unexpected Accounting-Request retransmission") 202 203 as_mib_end = as_hapd.get_mib(param="radius_server") 204 205 req_s = int(as_mib_start['radiusAccServTotalRequests']) 206 req_e = int(as_mib_end['radiusAccServTotalRequests']) 207 if req_e < req_s + 2: 208 raise Exception("Unexpected RADIUS server acct MIB value") 209 210 acc_s = int(as_mib_start['radiusAuthServAccessAccepts']) 211 acc_e = int(as_mib_end['radiusAuthServAccessAccepts']) 212 if acc_e < acc_s + 1: 213 raise Exception("Unexpected RADIUS server auth MIB value") 214 215def test_radius_req_attr(dev, apdev, params): 216 """RADIUS request attributes""" 217 try: 218 import sqlite3 219 except ImportError: 220 raise HwsimSkip("No sqlite3 module available") 221 db = os.path.join(params['logdir'], "radius_req_attr.sqlite") 222 as_hapd = hostapd.Hostapd("as") 223 params = hostapd.wpa2_eap_params(ssid="radius-req-attr") 224 params['acct_server_addr'] = "127.0.0.1" 225 params['acct_server_port'] = "1813" 226 params['acct_server_shared_secret'] = "radius" 227 params['radius_auth_req_attr'] = ["126:s:Operator"] 228 params['radius_acct_req_attr'] = ["126:s:Operator"] 229 params['radius_req_attr_sqlite'] = db 230 hapd = hostapd.add_ap(apdev[0], params) 231 232 with sqlite3.connect(db) as conn: 233 sql = "INSERT INTO radius_attributes(sta,reqtype,attr) VALUES (?,?,?)" 234 for e in [(dev[0].own_addr(), "auth", "77:s:conn-info-0"), 235 (dev[1].own_addr(), "auth", "77:s:conn-info-1"), 236 (dev[1].own_addr(), "auth", "77:s:conn-info-1a"), 237 (dev[1].own_addr(), "acct", "77:s:conn-info-1b")]: 238 conn.execute(sql, e) 239 conn.commit() 240 241 connect(dev[0], "radius-req-attr") 242 connect(dev[1], "radius-req-attr") 243 connect(dev[2], "radius-req-attr") 244 245def test_radius_acct_non_ascii_ssid(dev, apdev): 246 """RADIUS Accounting and non-ASCII SSID""" 247 params = hostapd.wpa2_eap_params() 248 params['acct_server_addr'] = "127.0.0.1" 249 params['acct_server_port'] = "1813" 250 params['acct_server_shared_secret'] = "radius" 251 ssid2 = "740665007374" 252 params['ssid2'] = ssid2 253 hostapd.add_ap(apdev[0], params) 254 dev[0].connect(ssid2=ssid2, key_mgmt="WPA-EAP", scan_freq="2412", 255 eap="PSK", identity="psk.user@example.com", 256 password_hex="0123456789abcdef0123456789abcdef") 257 258def test_radius_acct_pmksa_caching(dev, apdev): 259 """RADIUS Accounting with PMKSA caching""" 260 as_hapd = hostapd.Hostapd("as") 261 as_mib_start = as_hapd.get_mib(param="radius_server") 262 params = hostapd.wpa2_eap_params(ssid="radius-acct") 263 params['acct_server_addr'] = "127.0.0.1" 264 params['acct_server_port'] = "1813" 265 params['acct_server_shared_secret'] = "radius" 266 hapd = hostapd.add_ap(apdev[0], params) 267 connect(dev[0], "radius-acct") 268 dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412", 269 eap="PAX", identity="test-class", 270 password_hex="0123456789abcdef0123456789abcdef") 271 for d in [dev[0], dev[1]]: 272 d.request("REASSOCIATE") 273 d.wait_connected(timeout=15, error="Reassociation timed out") 274 275 count = 0 276 while True: 277 mib = hapd.get_mib() 278 if int(mib['radiusAccClientResponses']) >= 4: 279 break 280 time.sleep(0.1) 281 count += 1 282 if count > 10: 283 raise Exception("Did not receive Accounting-Response packets") 284 285 if int(mib['radiusAccClientRetransmissions']) > 0: 286 raise Exception("Unexpected Accounting-Request retransmission") 287 288 as_mib_end = as_hapd.get_mib(param="radius_server") 289 290 req_s = int(as_mib_start['radiusAccServTotalRequests']) 291 req_e = int(as_mib_end['radiusAccServTotalRequests']) 292 if req_e < req_s + 2: 293 raise Exception("Unexpected RADIUS server acct MIB value") 294 295 acc_s = int(as_mib_start['radiusAuthServAccessAccepts']) 296 acc_e = int(as_mib_end['radiusAuthServAccessAccepts']) 297 if acc_e < acc_s + 1: 298 raise Exception("Unexpected RADIUS server auth MIB value") 299 300def test_radius_acct_interim(dev, apdev): 301 """RADIUS Accounting interim update""" 302 as_hapd = hostapd.Hostapd("as") 303 params = hostapd.wpa2_eap_params(ssid="radius-acct") 304 params['acct_server_addr'] = "127.0.0.1" 305 params['acct_server_port'] = "1813" 306 params['acct_server_shared_secret'] = "radius" 307 params['radius_acct_interim_interval'] = "1" 308 hapd = hostapd.add_ap(apdev[0], params) 309 connect(dev[0], "radius-acct") 310 logger.info("Checking for RADIUS counters") 311 as_mib_start = as_hapd.get_mib(param="radius_server") 312 time.sleep(4.1) 313 as_mib_end = as_hapd.get_mib(param="radius_server") 314 req_s = int(as_mib_start['radiusAccServTotalRequests']) 315 req_e = int(as_mib_end['radiusAccServTotalRequests']) 316 if req_e < req_s + 3: 317 raise Exception("Unexpected RADIUS server acct MIB value (req_e=%d req_s=%d)" % (req_e, req_s)) 318 # Disable Accounting server and wait for interim update retries to fail and 319 # expire. 320 as_hapd.disable() 321 time.sleep(15) 322 as_hapd.enable() 323 ok = False 324 for i in range(10): 325 time.sleep(1) 326 as_mib = as_hapd.get_mib(param="radius_server") 327 if int(as_mib['radiusAccServTotalRequests']) > 0: 328 ok = True 329 break 330 if not ok: 331 raise Exception("Accounting updates did not seen after server restart") 332 333def test_radius_acct_interim_unreachable(dev, apdev): 334 """RADIUS Accounting interim update with unreachable server""" 335 params = hostapd.wpa2_eap_params(ssid="radius-acct") 336 params['acct_server_addr'] = "127.0.0.1" 337 params['acct_server_port'] = "18139" 338 params['acct_server_shared_secret'] = "radius" 339 params['radius_acct_interim_interval'] = "1" 340 hapd = hostapd.add_ap(apdev[0], params) 341 start = hapd.get_mib() 342 connect(dev[0], "radius-acct") 343 logger.info("Waiting for interium accounting updates") 344 time.sleep(3.1) 345 end = hapd.get_mib() 346 req_s = int(start['radiusAccClientTimeouts']) 347 req_e = int(end['radiusAccClientTimeouts']) 348 if req_e < req_s + 2: 349 raise Exception("Unexpected RADIUS server acct MIB value") 350 351def test_radius_acct_interim_unreachable2(dev, apdev): 352 """RADIUS Accounting interim update with unreachable server (retry)""" 353 params = hostapd.wpa2_eap_params(ssid="radius-acct") 354 params['acct_server_addr'] = "127.0.0.1" 355 params['acct_server_port'] = "18139" 356 params['acct_server_shared_secret'] = "radius" 357 # Use long enough interim update interval to allow RADIUS retransmission 358 # case (3 seconds) to trigger first. 359 params['radius_acct_interim_interval'] = "4" 360 hapd = hostapd.add_ap(apdev[0], params) 361 start = hapd.get_mib() 362 connect(dev[0], "radius-acct") 363 logger.info("Waiting for interium accounting updates") 364 time.sleep(7.5) 365 end = hapd.get_mib() 366 req_s = int(start['radiusAccClientTimeouts']) 367 req_e = int(end['radiusAccClientTimeouts']) 368 if req_e < req_s + 2: 369 raise Exception("Unexpected RADIUS server acct MIB value") 370 371def test_radius_acct_ipaddr(dev, apdev): 372 """RADIUS Accounting and Framed-IP-Address""" 373 try: 374 _test_radius_acct_ipaddr(dev, apdev) 375 finally: 376 subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'], 377 stderr=open('/dev/null', 'w')) 378 subprocess.call(['brctl', 'delbr', 'ap-br0'], 379 stderr=open('/dev/null', 'w')) 380 381def _test_radius_acct_ipaddr(dev, apdev): 382 params = {"ssid": "radius-acct-open", 383 'acct_server_addr': "127.0.0.1", 384 'acct_server_port': "1813", 385 'acct_server_shared_secret': "radius", 386 'proxy_arp': '1', 387 'ap_isolate': '1', 388 'bridge': 'ap-br0'} 389 hapd = hostapd.add_ap(apdev[0], params, no_enable=True) 390 try: 391 hapd.enable() 392 except: 393 # For now, do not report failures due to missing kernel support 394 raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version") 395 bssid = apdev[0]['bssid'] 396 397 subprocess.call(['brctl', 'setfd', 'ap-br0', '0']) 398 subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up']) 399 400 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 401 addr0 = dev[0].own_addr() 402 403 pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid, 404 ip_src="192.168.1.1", ip_dst="255.255.255.255", 405 yiaddr="192.168.1.123", chaddr=addr0) 406 if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt).decode()): 407 raise Exception("DATA_TEST_FRAME failed") 408 409 dev[0].request("DISCONNECT") 410 dev[0].wait_disconnected() 411 hapd.disable() 412 413def send_and_check_reply(srv, req, code, error_cause=0): 414 reply = srv.SendPacket(req) 415 logger.debug("RADIUS response from hostapd") 416 for i in list(reply.keys()): 417 logger.debug("%s: %s" % (i, reply[i])) 418 if reply.code != code: 419 raise Exception("Unexpected response code") 420 if error_cause: 421 if 'Error-Cause' not in reply: 422 raise Exception("Missing Error-Cause") 423 if reply['Error-Cause'][0] != error_cause: 424 raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause'])) 425 426def test_radius_acct_psk(dev, apdev): 427 """RADIUS Accounting - PSK""" 428 as_hapd = hostapd.Hostapd("as") 429 params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678") 430 params['acct_server_addr'] = "127.0.0.1" 431 params['acct_server_port'] = "1813" 432 params['acct_server_shared_secret'] = "radius" 433 hapd = hostapd.add_ap(apdev[0], params) 434 dev[0].connect("radius-acct", psk="12345678", scan_freq="2412") 435 436def test_radius_acct_psk_sha256(dev, apdev): 437 """RADIUS Accounting - PSK SHA256""" 438 as_hapd = hostapd.Hostapd("as") 439 params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678") 440 params["wpa_key_mgmt"] = "WPA-PSK-SHA256" 441 params['acct_server_addr'] = "127.0.0.1" 442 params['acct_server_port'] = "1813" 443 params['acct_server_shared_secret'] = "radius" 444 hapd = hostapd.add_ap(apdev[0], params) 445 dev[0].connect("radius-acct", key_mgmt="WPA-PSK-SHA256", 446 psk="12345678", scan_freq="2412") 447 448def test_radius_acct_ft_psk(dev, apdev): 449 """RADIUS Accounting - FT-PSK""" 450 as_hapd = hostapd.Hostapd("as") 451 params = ft_params1(ssid="radius-acct", passphrase="12345678") 452 params['acct_server_addr'] = "127.0.0.1" 453 params['acct_server_port'] = "1813" 454 params['acct_server_shared_secret'] = "radius" 455 hapd = hostapd.add_ap(apdev[0], params) 456 dev[0].connect("radius-acct", key_mgmt="FT-PSK", 457 psk="12345678", scan_freq="2412") 458 459def test_radius_acct_ieee8021x(dev, apdev): 460 """RADIUS Accounting - IEEE 802.1X""" 461 check_wep_capa(dev[0]) 462 skip_with_fips(dev[0]) 463 as_hapd = hostapd.Hostapd("as") 464 params = hostapd.radius_params() 465 params["ssid"] = "radius-acct-1x" 466 params["ieee8021x"] = "1" 467 params["wep_key_len_broadcast"] = "13" 468 params["wep_key_len_unicast"] = "13" 469 params['acct_server_addr'] = "127.0.0.1" 470 params['acct_server_port'] = "1813" 471 params['acct_server_shared_secret'] = "radius" 472 hapd = hostapd.add_ap(apdev[0], params) 473 dev[0].connect("radius-acct-1x", key_mgmt="IEEE8021X", eap="PSK", 474 identity="psk.user@example.com", 475 password_hex="0123456789abcdef0123456789abcdef", 476 scan_freq="2412") 477 478def test_radius_das_disconnect(dev, apdev): 479 """RADIUS Dynamic Authorization Extensions - Disconnect""" 480 try: 481 import pyrad.client 482 import pyrad.packet 483 import pyrad.dictionary 484 import radius_das 485 except ImportError: 486 raise HwsimSkip("No pyrad modules available") 487 488 params = hostapd.wpa2_eap_params(ssid="radius-das") 489 params['radius_das_port'] = "3799" 490 params['radius_das_client'] = "127.0.0.1 secret" 491 params['radius_das_require_event_timestamp'] = "1" 492 params['own_ip_addr'] = "127.0.0.1" 493 params['nas_identifier'] = "nas.example.com" 494 hapd = hostapd.add_ap(apdev[0], params) 495 connect(dev[0], "radius-das") 496 hapd.wait_sta(addr=dev[0].own_addr()) 497 498 addr = dev[0].p2p_interface_addr() 499 sta = hapd.get_sta(addr) 500 id = sta['dot1xAuthSessionId'] 501 502 dict = pyrad.dictionary.Dictionary("dictionary.radius") 503 504 srv = pyrad.client.Client(server="127.0.0.1", acctport=3799, 505 secret=b"secret", dict=dict) 506 srv.retries = 1 507 srv.timeout = 1 508 509 logger.info("Disconnect-Request with incorrect secret") 510 req = radius_das.DisconnectPacket(dict=dict, secret=b"incorrect", 511 User_Name="foo", 512 NAS_Identifier="localhost", 513 Event_Timestamp=int(time.time())) 514 logger.debug(req) 515 try: 516 reply = srv.SendPacket(req) 517 raise Exception("Unexpected response to Disconnect-Request") 518 except pyrad.client.Timeout: 519 logger.info("Disconnect-Request with incorrect secret properly ignored") 520 521 logger.info("Disconnect-Request without Event-Timestamp") 522 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 523 User_Name="psk.user@example.com") 524 logger.debug(req) 525 try: 526 reply = srv.SendPacket(req) 527 raise Exception("Unexpected response to Disconnect-Request") 528 except pyrad.client.Timeout: 529 logger.info("Disconnect-Request without Event-Timestamp properly ignored") 530 531 logger.info("Disconnect-Request with non-matching Event-Timestamp") 532 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 533 User_Name="psk.user@example.com", 534 Event_Timestamp=123456789) 535 logger.debug(req) 536 try: 537 reply = srv.SendPacket(req) 538 raise Exception("Unexpected response to Disconnect-Request") 539 except pyrad.client.Timeout: 540 logger.info("Disconnect-Request with non-matching Event-Timestamp properly ignored") 541 542 logger.info("Disconnect-Request with unsupported attribute") 543 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 544 User_Name="foo", 545 User_Password="foo", 546 Event_Timestamp=int(time.time())) 547 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 401) 548 549 logger.info("Disconnect-Request with invalid Calling-Station-Id") 550 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 551 User_Name="foo", 552 Calling_Station_Id="foo", 553 Event_Timestamp=int(time.time())) 554 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 407) 555 556 logger.info("Disconnect-Request with mismatching User-Name") 557 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 558 User_Name="foo", 559 Event_Timestamp=int(time.time())) 560 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 561 562 logger.info("Disconnect-Request with mismatching Calling-Station-Id") 563 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 564 Calling_Station_Id="12:34:56:78:90:aa", 565 Event_Timestamp=int(time.time())) 566 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 567 568 logger.info("Disconnect-Request with mismatching Acct-Session-Id") 569 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 570 Acct_Session_Id="12345678-87654321", 571 Event_Timestamp=int(time.time())) 572 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 573 574 logger.info("Disconnect-Request with mismatching Acct-Session-Id (len)") 575 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 576 Acct_Session_Id="12345678", 577 Event_Timestamp=int(time.time())) 578 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 579 580 logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id") 581 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 582 Acct_Multi_Session_Id="12345678+87654321", 583 Event_Timestamp=int(time.time())) 584 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 585 586 logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id (len)") 587 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 588 Acct_Multi_Session_Id="12345678", 589 Event_Timestamp=int(time.time())) 590 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 591 592 logger.info("Disconnect-Request with no session identification attributes") 593 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 594 Event_Timestamp=int(time.time())) 595 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503) 596 597 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1) 598 if ev is not None: 599 raise Exception("Unexpected disconnection") 600 dev[0].dump_monitor() 601 602 logger.info("Disconnect-Request with mismatching NAS-IP-Address") 603 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 604 NAS_IP_Address="192.168.3.4", 605 Acct_Session_Id=id, 606 Event_Timestamp=int(time.time())) 607 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403) 608 609 logger.info("Disconnect-Request with mismatching NAS-Identifier") 610 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 611 NAS_Identifier="unknown.example.com", 612 Acct_Session_Id=id, 613 Event_Timestamp=int(time.time())) 614 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403) 615 616 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1) 617 if ev is not None: 618 raise Exception("Unexpected disconnection") 619 dev[0].dump_monitor() 620 621 logger.info("Disconnect-Request with matching Acct-Session-Id") 622 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 623 NAS_IP_Address="127.0.0.1", 624 NAS_Identifier="nas.example.com", 625 Acct_Session_Id=id, 626 Event_Timestamp=int(time.time())) 627 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 628 629 dev[0].wait_disconnected(timeout=10) 630 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 631 dev[0].wait_connected(timeout=10, error="Re-connection timed out") 632 hapd.wait_sta(addr=dev[0].own_addr()) 633 dev[0].dump_monitor() 634 635 logger.info("Disconnect-Request with matching Acct-Multi-Session-Id") 636 sta = hapd.get_sta(addr) 637 multi_sess_id = sta['authMultiSessionId'] 638 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 639 NAS_IP_Address="127.0.0.1", 640 NAS_Identifier="nas.example.com", 641 Acct_Multi_Session_Id=multi_sess_id, 642 Event_Timestamp=int(time.time())) 643 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 644 645 dev[0].wait_disconnected(timeout=10) 646 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 647 dev[0].wait_connected(timeout=10, error="Re-connection timed out") 648 hapd.wait_sta(addr=dev[0].own_addr()) 649 dev[0].dump_monitor() 650 651 logger.info("Disconnect-Request with matching User-Name") 652 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 653 NAS_Identifier="nas.example.com", 654 User_Name="psk.user@example.com", 655 Event_Timestamp=int(time.time())) 656 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 657 658 dev[0].wait_disconnected(timeout=10) 659 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 660 dev[0].wait_connected(timeout=10, error="Re-connection timed out") 661 hapd.wait_sta(addr=dev[0].own_addr()) 662 dev[0].dump_monitor() 663 664 logger.info("Disconnect-Request with matching Calling-Station-Id") 665 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 666 NAS_IP_Address="127.0.0.1", 667 Calling_Station_Id=addr, 668 Event_Timestamp=int(time.time())) 669 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 670 671 dev[0].wait_disconnected(timeout=10) 672 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 673 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", "CTRL-EVENT-CONNECTED"]) 674 if ev is None: 675 raise Exception("Timeout while waiting for re-connection") 676 if "CTRL-EVENT-EAP-STARTED" not in ev: 677 raise Exception("Unexpected skipping of EAP authentication in reconnection") 678 dev[0].wait_connected(timeout=10, error="Re-connection timed out") 679 hapd.wait_sta(addr=dev[0].own_addr()) 680 dev[0].dump_monitor() 681 682 logger.info("Disconnect-Request with matching Calling-Station-Id and non-matching CUI") 683 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 684 Calling_Station_Id=addr, 685 Chargeable_User_Identity="foo@example.com", 686 Event_Timestamp=int(time.time())) 687 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503) 688 689 hapd.dump_monitor() 690 691 logger.info("Disconnect-Request with matching CUI") 692 dev[1].connect("radius-das", key_mgmt="WPA-EAP", 693 eap="GPSK", identity="gpsk-cui", 694 password="abcdefghijklmnop0123456789abcdef", 695 scan_freq="2412") 696 hapd.wait_sta(addr=dev[1].own_addr()) 697 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 698 Chargeable_User_Identity="gpsk-chargeable-user-identity", 699 Event_Timestamp=int(time.time())) 700 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 701 702 dev[1].wait_disconnected(timeout=10) 703 hapd.wait_sta_disconnect(addr=dev[1].own_addr()) 704 dev[1].wait_connected(timeout=10, error="Re-connection timed out") 705 hapd.wait_sta(addr=dev[1].own_addr()) 706 707 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1) 708 if ev is not None: 709 raise Exception("Unexpected disconnection") 710 711 connect(dev[2], "radius-das") 712 hapd.wait_sta(addr=dev[2].own_addr()) 713 dev[0].dump_monitor() 714 715 logger.info("Disconnect-Request with matching User-Name - multiple sessions matching") 716 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 717 NAS_Identifier="nas.example.com", 718 User_Name="psk.user@example.com", 719 Event_Timestamp=int(time.time())) 720 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=508) 721 722 logger.info("Disconnect-Request with User-Name matching multiple sessions, Calling-Station-Id only one") 723 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 724 NAS_Identifier="nas.example.com", 725 Calling_Station_Id=addr, 726 User_Name="psk.user@example.com", 727 Event_Timestamp=int(time.time())) 728 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 729 730 dev[0].wait_disconnected(timeout=10) 731 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 732 dev[0].wait_connected(timeout=10, error="Re-connection timed out") 733 hapd.wait_sta(addr=dev[0].own_addr()) 734 dev[0].dump_monitor() 735 736 ev = dev[2].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1) 737 if ev is not None: 738 raise Exception("Unexpected disconnection") 739 740 logger.info("Disconnect-Request with matching Acct-Multi-Session-Id after disassociation") 741 sta = hapd.get_sta(addr) 742 multi_sess_id = sta['authMultiSessionId'] 743 dev[0].request("DISCONNECT") 744 dev[0].wait_disconnected(timeout=10) 745 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 746 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 747 NAS_IP_Address="127.0.0.1", 748 NAS_Identifier="nas.example.com", 749 Acct_Multi_Session_Id=multi_sess_id, 750 Event_Timestamp=int(time.time())) 751 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 752 753 dev[0].request("RECONNECT") 754 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15) 755 if ev is None: 756 raise Exception("Timeout on EAP start") 757 dev[0].wait_connected(timeout=15) 758 hapd.wait_sta(addr=dev[0].own_addr()) 759 dev[0].dump_monitor() 760 761 logger.info("Disconnect-Request with matching User-Name after disassociation") 762 dev[0].request("DISCONNECT") 763 dev[0].wait_disconnected(timeout=10) 764 dev[0].dump_monitor() 765 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 766 dev[2].request("DISCONNECT") 767 dev[2].wait_disconnected(timeout=10) 768 hapd.wait_sta_disconnect(addr=dev[2].own_addr()) 769 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 770 NAS_IP_Address="127.0.0.1", 771 NAS_Identifier="nas.example.com", 772 User_Name="psk.user@example.com", 773 Event_Timestamp=int(time.time())) 774 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 775 776 logger.info("Disconnect-Request with matching CUI after disassociation") 777 dev[1].request("DISCONNECT") 778 dev[1].wait_disconnected(timeout=10) 779 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 780 NAS_IP_Address="127.0.0.1", 781 NAS_Identifier="nas.example.com", 782 Chargeable_User_Identity="gpsk-chargeable-user-identity", 783 Event_Timestamp=int(time.time())) 784 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 785 786 logger.info("Disconnect-Request with matching Calling-Station-Id after disassociation") 787 dev[0].request("RECONNECT") 788 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15) 789 if ev is None: 790 raise Exception("Timeout on EAP start") 791 dev[0].wait_connected(timeout=15) 792 hapd.wait_sta(addr=dev[0].own_addr()) 793 dev[0].dump_monitor() 794 dev[0].request("DISCONNECT") 795 dev[0].wait_disconnected(timeout=10) 796 hapd.wait_sta_disconnect(addr=dev[0].own_addr()) 797 dev[0].dump_monitor() 798 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 799 NAS_IP_Address="127.0.0.1", 800 NAS_Identifier="nas.example.com", 801 Calling_Station_Id=addr, 802 Event_Timestamp=int(time.time())) 803 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 804 805 logger.info("Disconnect-Request with mismatching Calling-Station-Id after disassociation") 806 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 807 NAS_IP_Address="127.0.0.1", 808 NAS_Identifier="nas.example.com", 809 Calling_Station_Id=addr, 810 Event_Timestamp=int(time.time())) 811 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503) 812 813def add_message_auth_req(req): 814 req.authenticator = req.CreateAuthenticator() 815 hmac_obj = hmac.new(req.secret, digestmod=hashlib.md5) 816 hmac_obj.update(struct.pack("B", req.code)) 817 hmac_obj.update(struct.pack("B", req.id)) 818 819 # request attributes 820 req.AddAttribute("Message-Authenticator", 16*b"\x00") 821 attrs = b'' 822 for code, datalst in sorted(req.items()): 823 for data in datalst: 824 attrs += req._PktEncodeAttribute(code, data) 825 826 # Length 827 flen = 4 + 16 + len(attrs) 828 hmac_obj.update(struct.pack(">H", flen)) 829 hmac_obj.update(16*b"\x00") # all zeros Authenticator in calculation 830 hmac_obj.update(attrs) 831 del req[80] 832 add_message_authenticator_attr(req, hmac_obj.digest()) 833 834def test_radius_das_disconnect_time_window(dev, apdev): 835 """RADIUS Dynamic Authorization Extensions - Disconnect - time window""" 836 try: 837 import pyrad.client 838 import pyrad.packet 839 import pyrad.dictionary 840 import radius_das 841 except ImportError: 842 raise HwsimSkip("No pyrad modules available") 843 844 params = hostapd.wpa2_eap_params(ssid="radius-das") 845 params['radius_das_port'] = "3799" 846 params['radius_das_client'] = "127.0.0.1 secret" 847 params['radius_das_require_event_timestamp'] = "1" 848 params['radius_das_require_message_authenticator'] = "1" 849 params['radius_das_time_window'] = "10" 850 params['own_ip_addr'] = "127.0.0.1" 851 params['nas_identifier'] = "nas.example.com" 852 hapd = hostapd.add_ap(apdev[0], params) 853 connect(dev[0], "radius-das") 854 addr = dev[0].own_addr() 855 sta = hapd.get_sta(addr) 856 id = sta['dot1xAuthSessionId'] 857 858 dict = pyrad.dictionary.Dictionary("dictionary.radius") 859 860 srv = pyrad.client.Client(server="127.0.0.1", acctport=3799, 861 secret=b"secret", dict=dict) 862 srv.retries = 1 863 srv.timeout = 1 864 865 logger.info("Disconnect-Request with unsupported attribute") 866 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 867 NAS_IP_Address="127.0.0.1", 868 NAS_Identifier="nas.example.com", 869 Calling_Station_Id=addr, 870 Event_Timestamp=int(time.time()) - 50) 871 add_message_auth_req(req) 872 logger.debug(req) 873 try: 874 reply = srv.SendPacket(req) 875 raise Exception("Unexpected response to Disconnect-Request") 876 except pyrad.client.Timeout: 877 logger.info("Disconnect-Request with non-matching Event-Timestamp properly ignored") 878 879 logger.info("Disconnect-Request with unsupported attribute") 880 req = radius_das.DisconnectPacket(dict=dict, secret=b"secret", 881 NAS_IP_Address="127.0.0.1", 882 NAS_Identifier="nas.example.com", 883 Calling_Station_Id=addr, 884 Event_Timestamp=int(time.time())) 885 add_message_auth_req(req) 886 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK) 887 888def test_radius_das_coa(dev, apdev): 889 """RADIUS Dynamic Authorization Extensions - CoA""" 890 try: 891 import pyrad.client 892 import pyrad.packet 893 import pyrad.dictionary 894 import radius_das 895 except ImportError: 896 raise HwsimSkip("No pyrad modules available") 897 898 params = hostapd.wpa2_eap_params(ssid="radius-das") 899 params['radius_das_port'] = "3799" 900 params['radius_das_client'] = "127.0.0.1 secret" 901 params['radius_das_require_event_timestamp'] = "1" 902 hapd = hostapd.add_ap(apdev[0], params) 903 connect(dev[0], "radius-das") 904 addr = dev[0].p2p_interface_addr() 905 sta = hapd.get_sta(addr) 906 id = sta['dot1xAuthSessionId'] 907 908 dict = pyrad.dictionary.Dictionary("dictionary.radius") 909 910 srv = pyrad.client.Client(server="127.0.0.1", acctport=3799, 911 secret=b"secret", dict=dict) 912 srv.retries = 1 913 srv.timeout = 1 914 915 # hostapd does not currently support CoA-Request, so NAK is expected 916 logger.info("CoA-Request with matching Acct-Session-Id") 917 req = radius_das.CoAPacket(dict=dict, secret=b"secret", 918 Acct_Session_Id=id, 919 Event_Timestamp=int(time.time())) 920 send_and_check_reply(srv, req, pyrad.packet.CoANAK, error_cause=405) 921 922def test_radius_ipv6(dev, apdev): 923 """RADIUS connection over IPv6""" 924 params = {} 925 params['ssid'] = 'as' 926 params['beacon_int'] = '2000' 927 params['radius_server_clients'] = 'auth_serv/radius_clients_ipv6.conf' 928 params['radius_server_ipv6'] = '1' 929 params['radius_server_auth_port'] = '18129' 930 params['radius_server_acct_port'] = '18139' 931 params['eap_server'] = '1' 932 params['eap_user_file'] = 'auth_serv/eap_user.conf' 933 params['ca_cert'] = 'auth_serv/ca.pem' 934 params['server_cert'] = 'auth_serv/server.pem' 935 params['private_key'] = 'auth_serv/server.key' 936 hostapd.add_ap(apdev[1], params) 937 938 params = hostapd.wpa2_eap_params(ssid="radius-ipv6") 939 params['auth_server_addr'] = "::0" 940 params['auth_server_port'] = "18129" 941 params['acct_server_addr'] = "::0" 942 params['acct_server_port'] = "18139" 943 params['acct_server_shared_secret'] = "radius" 944 params['own_ip_addr'] = "::0" 945 hostapd.add_ap(apdev[0], params) 946 connect(dev[0], "radius-ipv6") 947 948def test_radius_macacl(dev, apdev): 949 """RADIUS MAC ACL""" 950 params = hostapd.radius_params() 951 params["ssid"] = "radius" 952 params["macaddr_acl"] = "2" 953 hostapd.add_ap(apdev[0], params) 954 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412") 955 956 # Invalid VLAN ID from RADIUS server 957 dev[2].connect("radius", key_mgmt="NONE", scan_freq="2412") 958 dev[2].request("REMOVE_NETWORK all") 959 dev[2].wait_disconnected() 960 dev[2].connect("radius", key_mgmt="NONE", scan_freq="2412") 961 962def test_radius_macacl_acct(dev, apdev): 963 """RADIUS MAC ACL and accounting enabled""" 964 params = hostapd.radius_params() 965 params["ssid"] = "radius" 966 params["macaddr_acl"] = "2" 967 params['acct_server_addr'] = "127.0.0.1" 968 params['acct_server_port'] = "1813" 969 params['acct_server_shared_secret'] = "radius" 970 hostapd.add_ap(apdev[0], params) 971 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412") 972 dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412") 973 dev[1].request("DISCONNECT") 974 dev[1].wait_disconnected() 975 dev[1].request("RECONNECT") 976 977def test_radius_macacl_oom(dev, apdev): 978 """RADIUS MAC ACL and OOM""" 979 params = hostapd.radius_params() 980 params["ssid"] = "radius" 981 params["macaddr_acl"] = "2" 982 hapd = hostapd.add_ap(apdev[0], params) 983 bssid = hapd.own_addr() 984 985 dev[0].scan_for_bss(bssid, freq="2412") 986 with alloc_fail(hapd, 1, "hostapd_allowed_address"): 987 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412") 988 989 dev[1].scan_for_bss(bssid, freq="2412") 990 with alloc_fail(hapd, 2, "hostapd_allowed_address"): 991 dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412") 992 993 dev[2].scan_for_bss(bssid, freq="2412") 994 with alloc_fail(hapd, 2, "=hostapd_allowed_address"): 995 dev[2].connect("radius", key_mgmt="NONE", scan_freq="2412") 996 997def test_radius_macacl_unreachable(dev, apdev): 998 """RADIUS MAC ACL and server unreachable""" 999 params = hostapd.radius_params() 1000 params['auth_server_port'] = "18139" 1001 params["ssid"] = "radius" 1002 params["macaddr_acl"] = "2" 1003 hapd = hostapd.add_ap(apdev[0], params) 1004 bssid = hapd.own_addr() 1005 1006 dev[0].scan_for_bss(bssid, freq="2412") 1007 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412", 1008 wait_connect=False) 1009 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=3) 1010 if ev is not None: 1011 raise Exception("Unexpected connection") 1012 1013 logger.info("Fix authentication server port") 1014 hapd.set("auth_server_port", "1812") 1015 hapd.disable() 1016 hapd.enable() 1017 dev[0].wait_connected(timeout=20) 1018 dev[0].request("DISCONNECT") 1019 dev[0].wait_disconnected() 1020 1021def test_radius_failover(dev, apdev): 1022 """RADIUS Authentication and Accounting server failover""" 1023 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo']) 1024 as_hapd = hostapd.Hostapd("as") 1025 as_mib_start = as_hapd.get_mib(param="radius_server") 1026 params = hostapd.wpa2_eap_params(ssid="radius-failover") 1027 params["auth_server_addr"] = "192.168.213.17" 1028 params["auth_server_port"] = "1812" 1029 params["auth_server_shared_secret"] = "testing" 1030 params['acct_server_addr'] = "192.168.213.17" 1031 params['acct_server_port'] = "1813" 1032 params['acct_server_shared_secret'] = "testing" 1033 params['radius_retry_primary_interval'] = "20" 1034 hapd = hostapd.add_ap(apdev[0], params, no_enable=True) 1035 hapd.set("auth_server_addr", "127.0.0.1") 1036 hapd.set("auth_server_port", "1812") 1037 hapd.set("auth_server_shared_secret", "radius") 1038 hapd.set('acct_server_addr', "127.0.0.1") 1039 hapd.set('acct_server_port', "1813") 1040 hapd.set('acct_server_shared_secret', "radius") 1041 hapd.enable() 1042 ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=30) 1043 if ev is None: 1044 raise Exception("AP startup timed out") 1045 if "AP-ENABLED" not in ev: 1046 raise Exception("AP startup failed") 1047 start = os.times()[4] 1048 1049 try: 1050 subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17']) 1051 dev[0].request("SET EAPOL::authPeriod 5") 1052 connect(dev[0], "radius-failover", wait_connect=False) 1053 dev[0].wait_connected(timeout=20) 1054 finally: 1055 dev[0].request("SET EAPOL::authPeriod 30") 1056 subprocess.call(['ip', 'ro', 'del', '192.168.213.17']) 1057 1058 as_mib_end = as_hapd.get_mib(param="radius_server") 1059 req_s = int(as_mib_start['radiusAccServTotalRequests']) 1060 req_e = int(as_mib_end['radiusAccServTotalRequests']) 1061 if req_e <= req_s: 1062 raise Exception("Unexpected RADIUS server acct MIB value") 1063 1064 end = os.times()[4] 1065 try: 1066 subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17']) 1067 dev[1].request("SET EAPOL::authPeriod 5") 1068 if end - start < 21: 1069 time.sleep(21 - (end - start)) 1070 connect(dev[1], "radius-failover", wait_connect=False) 1071 dev[1].wait_connected(timeout=20) 1072 finally: 1073 dev[1].request("SET EAPOL::authPeriod 30") 1074 subprocess.call(['ip', 'ro', 'del', '192.168.213.17']) 1075 1076def run_pyrad_server(srv, t_events): 1077 srv.RunWithStop(t_events) 1078 1079def test_radius_protocol(dev, apdev): 1080 """RADIUS Authentication protocol tests with a fake server""" 1081 try: 1082 import pyrad.server 1083 import pyrad.packet 1084 import pyrad.dictionary 1085 except ImportError: 1086 raise HwsimSkip("No pyrad modules available") 1087 1088 class TestServer(pyrad.server.Server): 1089 def _HandleAuthPacket(self, pkt): 1090 pyrad.server.Server._HandleAuthPacket(self, pkt) 1091 logger.info("Received authentication request") 1092 reply = self.CreateReplyPacket(pkt) 1093 reply.code = pyrad.packet.AccessAccept 1094 if self.t_events['msg_auth'].is_set(): 1095 logger.info("Add Message-Authenticator") 1096 if self.t_events['wrong_secret'].is_set(): 1097 logger.info("Use incorrect RADIUS shared secret") 1098 pw = b"incorrect" 1099 else: 1100 pw = reply.secret 1101 hmac_obj = hmac.new(pw, digestmod=hashlib.md5) 1102 hmac_obj.update(struct.pack("B", reply.code)) 1103 hmac_obj.update(struct.pack("B", reply.id)) 1104 1105 # reply attributes 1106 reply.AddAttribute("Message-Authenticator", 16*b"\x00") 1107 attrs = reply._PktEncodeAttributes() 1108 1109 # Length 1110 flen = 4 + 16 + len(attrs) 1111 hmac_obj.update(struct.pack(">H", flen)) 1112 hmac_obj.update(pkt.authenticator) 1113 hmac_obj.update(attrs) 1114 if self.t_events['double_msg_auth'].is_set(): 1115 logger.info("Include two Message-Authenticator attributes") 1116 else: 1117 del reply[80] 1118 add_message_authenticator_attr(reply, hmac_obj.digest()) 1119 self.SendReplyPacket(pkt.fd, reply) 1120 1121 def RunWithStop(self, t_events): 1122 self._poll = select.poll() 1123 self._fdmap = {} 1124 self._PrepareSockets() 1125 self.t_events = t_events 1126 1127 while not t_events['stop'].is_set(): 1128 for (fd, event) in self._poll.poll(1000): 1129 if event == select.POLLIN: 1130 try: 1131 fdo = self._fdmap[fd] 1132 self._ProcessInput(fdo) 1133 except pyrad.server.ServerPacketError as err: 1134 logger.info("pyrad server dropping packet: " + str(err)) 1135 except pyrad.packet.PacketError as err: 1136 logger.info("pyrad server received invalid packet: " + str(err)) 1137 else: 1138 logger.error("Unexpected event in pyrad server main loop") 1139 1140 for fd in self.authfds + self.acctfds: 1141 fd.close() 1142 1143 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"), 1144 authport=18138, acctport=18139) 1145 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1", 1146 b"radius", 1147 "localhost") 1148 srv.BindToAddress("127.0.0.1") 1149 t_events = {} 1150 t_events['stop'] = threading.Event() 1151 t_events['msg_auth'] = threading.Event() 1152 t_events['wrong_secret'] = threading.Event() 1153 t_events['double_msg_auth'] = threading.Event() 1154 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events)) 1155 t.start() 1156 1157 try: 1158 params = hostapd.wpa2_eap_params(ssid="radius-test") 1159 params['auth_server_port'] = "18138" 1160 hapd = hostapd.add_ap(apdev[0], params) 1161 connect(dev[0], "radius-test", wait_connect=False) 1162 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15) 1163 if ev is None: 1164 raise Exception("Timeout on EAP start") 1165 time.sleep(1) 1166 dev[0].request("REMOVE_NETWORK all") 1167 time.sleep(0.1) 1168 dev[0].dump_monitor() 1169 t_events['msg_auth'].set() 1170 t_events['wrong_secret'].set() 1171 connect(dev[0], "radius-test", wait_connect=False) 1172 time.sleep(1) 1173 dev[0].request("REMOVE_NETWORK all") 1174 time.sleep(0.1) 1175 dev[0].dump_monitor() 1176 t_events['wrong_secret'].clear() 1177 connect(dev[0], "radius-test", wait_connect=False) 1178 time.sleep(1) 1179 dev[0].request("REMOVE_NETWORK all") 1180 time.sleep(0.1) 1181 dev[0].dump_monitor() 1182 t_events['double_msg_auth'].set() 1183 connect(dev[0], "radius-test", wait_connect=False) 1184 time.sleep(1) 1185 finally: 1186 t_events['stop'].set() 1187 t.join() 1188 1189def build_tunnel_password(secret, authenticator, psk): 1190 a = b"\xab\xcd" 1191 psk = psk.encode() 1192 padlen = 16 - (1 + len(psk)) % 16 1193 if padlen == 16: 1194 padlen = 0 1195 p = struct.pack('B', len(psk)) + psk + padlen * b'\x00' 1196 cc_all = bytes() 1197 b = hashlib.md5(secret + authenticator + a).digest() 1198 while len(p) > 0: 1199 pp = bytearray(p[0:16]) 1200 p = p[16:] 1201 bb = bytearray(b) 1202 cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb))) 1203 cc_all += cc 1204 b = hashlib.md5(secret + cc).digest() 1205 data = b'\x00' + a + bytes(cc_all) 1206 return data 1207 1208def start_radius_psk_server(psk, invalid_code=False, acct_interim_interval=0, 1209 session_timeout=0, reject=False, 1210 inject_invalid=False): 1211 try: 1212 import pyrad.server 1213 import pyrad.packet 1214 import pyrad.dictionary 1215 except ImportError: 1216 raise HwsimSkip("No pyrad modules available") 1217 1218 class TestServer(pyrad.server.Server): 1219 def _HandleAuthPacket(self, pkt): 1220 pyrad.server.Server._HandleAuthPacket(self, pkt) 1221 logger.info("Received authentication request") 1222 1223 if self.t_events['inject_invalid']: 1224 reply = self.CreateReplyPacket(pkt) 1225 reply.code = pyrad.packet.AccessAccept 1226 build_message_auth(pkt, reply, secret=b'\x00') 1227 self.SendReplyPacket(pkt.fd, reply) 1228 1229 reply = self.CreateReplyPacket(pkt) 1230 reply.code = pyrad.packet.AccessAccept 1231 if self.t_events['invalid_code']: 1232 reply.code = pyrad.packet.AccessRequest 1233 if self.t_events['reject']: 1234 reply.code = pyrad.packet.AccessReject 1235 data = build_tunnel_password(reply.secret, pkt.authenticator, 1236 self.t_events['psk']) 1237 reply.AddAttribute("Tunnel-Password", data) 1238 if self.t_events['acct_interim_interval']: 1239 reply.AddAttribute("Acct-Interim-Interval", 1240 self.t_events['acct_interim_interval']) 1241 if self.t_events['session_timeout']: 1242 reply.AddAttribute("Session-Timeout", 1243 self.t_events['session_timeout']) 1244 build_message_auth(pkt, reply) 1245 1246 self.SendReplyPacket(pkt.fd, reply) 1247 1248 def RunWithStop(self, t_events): 1249 self._poll = select.poll() 1250 self._fdmap = {} 1251 self._PrepareSockets() 1252 self.t_events = t_events 1253 1254 while not t_events['stop'].is_set(): 1255 for (fd, event) in self._poll.poll(1000): 1256 if event == select.POLLIN: 1257 try: 1258 fdo = self._fdmap[fd] 1259 self._ProcessInput(fdo) 1260 except pyrad.server.ServerPacketError as err: 1261 logger.info("pyrad server dropping packet: " + str(err)) 1262 except pyrad.packet.PacketError as err: 1263 logger.info("pyrad server received invalid packet: " + str(err)) 1264 else: 1265 logger.error("Unexpected event in pyrad server main loop") 1266 1267 for fd in self.authfds + self.acctfds: 1268 fd.close() 1269 1270 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"), 1271 authport=18138, acctport=18139) 1272 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1", 1273 b"radius", 1274 "localhost") 1275 srv.BindToAddress("127.0.0.1") 1276 t_events = {} 1277 t_events['stop'] = threading.Event() 1278 t_events['psk'] = psk 1279 t_events['invalid_code'] = invalid_code 1280 t_events['acct_interim_interval'] = acct_interim_interval 1281 t_events['session_timeout'] = session_timeout 1282 t_events['reject'] = reject 1283 t_events['inject_invalid'] = inject_invalid 1284 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events)) 1285 t.start() 1286 return t, t_events 1287 1288def hostapd_radius_psk_test_params(): 1289 params = hostapd.radius_params() 1290 params['ssid'] = "test-wpa2-psk" 1291 params["wpa"] = "2" 1292 params["wpa_key_mgmt"] = "WPA-PSK" 1293 params["rsn_pairwise"] = "CCMP" 1294 params['macaddr_acl'] = '2' 1295 params['wpa_psk_radius'] = '2' 1296 params['auth_server_port'] = "18138" 1297 return params 1298 1299def test_radius_psk(dev, apdev): 1300 """WPA2 with PSK from RADIUS""" 1301 t, t_events = start_radius_psk_server("12345678") 1302 1303 try: 1304 params = hostapd_radius_psk_test_params() 1305 hapd = hostapd.add_ap(apdev[0], params) 1306 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412") 1307 t_events['psk'] = "0123456789abcdef" 1308 dev[1].connect("test-wpa2-psk", psk="0123456789abcdef", 1309 scan_freq="2412") 1310 finally: 1311 t_events['stop'].set() 1312 t.join() 1313 1314def test_radius_psk_during_4way_hs(dev, apdev): 1315 """WPA2 with PSK from RADIUS during 4-way handshake""" 1316 run_radius_psk_during_4way_hs(dev, apdev, 0) 1317 1318def test_radius_psk_during_4way_hs_session_timeout(dev, apdev): 1319 """WPA2 with PSK from RADIUS during 4-way handshake with Session-Timeout""" 1320 run_radius_psk_during_4way_hs(dev, apdev, 10000) 1321 1322def run_radius_psk_during_4way_hs(dev, apdev, session_timeout): 1323 t, t_events = start_radius_psk_server("12345678", 1324 session_timeout=session_timeout) 1325 1326 try: 1327 params = hostapd_radius_psk_test_params() 1328 params['macaddr_acl'] = '0' 1329 params['wpa_psk_radius'] = '3' 1330 hapd = hostapd.add_ap(apdev[0], params) 1331 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412") 1332 t_events['psk'] = "0123456789abcdef" 1333 dev[1].connect("test-wpa2-psk", psk="0123456789abcdef", 1334 scan_freq="2412") 1335 finally: 1336 t_events['stop'].set() 1337 t.join() 1338 1339def test_radius_psk_invalid(dev, apdev): 1340 """WPA2 with invalid PSK from RADIUS""" 1341 t, t_events = start_radius_psk_server("1234567") 1342 1343 try: 1344 params = hostapd_radius_psk_test_params() 1345 hapd = hostapd.add_ap(apdev[0], params) 1346 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1347 wait_connect=False) 1348 time.sleep(1) 1349 finally: 1350 t_events['stop'].set() 1351 t.join() 1352 1353def test_radius_psk_invalid2(dev, apdev): 1354 """WPA2 with invalid PSK (hexstring) from RADIUS""" 1355 t, t_events = start_radius_psk_server(64*'q') 1356 1357 try: 1358 params = hostapd_radius_psk_test_params() 1359 hapd = hostapd.add_ap(apdev[0], params) 1360 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1361 wait_connect=False) 1362 time.sleep(1) 1363 finally: 1364 t_events['stop'].set() 1365 t.join() 1366 1367def test_radius_psk_hex_psk(dev, apdev): 1368 """WPA2 with PSK hexstring from RADIUS""" 1369 t, t_events = start_radius_psk_server(64*'2', acct_interim_interval=19, 1370 session_timeout=123) 1371 1372 try: 1373 params = hostapd_radius_psk_test_params() 1374 hapd = hostapd.add_ap(apdev[0], params) 1375 dev[0].connect("test-wpa2-psk", raw_psk=64*'2', scan_freq="2412") 1376 finally: 1377 t_events['stop'].set() 1378 t.join() 1379 1380def test_radius_psk_unknown_code(dev, apdev): 1381 """WPA2 with PSK from RADIUS and unknown code""" 1382 t, t_events = start_radius_psk_server(64*'2', invalid_code=True) 1383 1384 try: 1385 params = hostapd_radius_psk_test_params() 1386 hapd = hostapd.add_ap(apdev[0], params) 1387 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1388 wait_connect=False) 1389 time.sleep(1) 1390 finally: 1391 t_events['stop'].set() 1392 t.join() 1393 1394def test_radius_psk_reject(dev, apdev): 1395 """WPA2 with PSK from RADIUS and reject""" 1396 t, t_events = start_radius_psk_server("12345678", reject=True) 1397 1398 try: 1399 params = hostapd_radius_psk_test_params() 1400 hapd = hostapd.add_ap(apdev[0], params) 1401 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1402 wait_connect=False) 1403 ev = dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10) 1404 if ev is None: 1405 raise Exception("No CTRL-EVENT-AUTH-REJECT event") 1406 dev[0].request("DISCONNECT") 1407 finally: 1408 t_events['stop'].set() 1409 t.join() 1410 1411def test_radius_psk_reject_during_4way_hs(dev, apdev): 1412 """WPA2 with PSK from RADIUS and reject""" 1413 t, t_events = start_radius_psk_server("12345678", reject=True) 1414 1415 try: 1416 params = hostapd_radius_psk_test_params() 1417 params['macaddr_acl'] = '0' 1418 params['wpa_psk_radius'] = '3' 1419 hapd = hostapd.add_ap(apdev[0], params) 1420 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1421 wait_connect=False) 1422 dev[0].wait_disconnected() 1423 dev[0].request("DISCONNECT") 1424 finally: 1425 t_events['stop'].set() 1426 t.join() 1427 1428def test_radius_psk_oom(dev, apdev): 1429 """WPA2 with PSK from RADIUS and OOM""" 1430 t, t_events = start_radius_psk_server(64*'2') 1431 1432 try: 1433 params = hostapd_radius_psk_test_params() 1434 hapd = hostapd.add_ap(apdev[0], params) 1435 bssid = hapd.own_addr() 1436 dev[0].scan_for_bss(bssid, freq="2412") 1437 with alloc_fail(hapd, 1, "=hostapd_acl_recv_radius"): 1438 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1439 wait_connect=False) 1440 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1441 finally: 1442 t_events['stop'].set() 1443 t.join() 1444 1445def test_radius_psk_discard(dev, apdev): 1446 """WPA2 with PSK from RADIUS and discarding invalid RADIUS messages""" 1447 t, t_events = start_radius_psk_server("12345678", inject_invalid=True) 1448 1449 try: 1450 params = hostapd_radius_psk_test_params() 1451 hapd = hostapd.add_ap(apdev[0], params) 1452 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412") 1453 t_events['psk'] = "0123456789abcdef" 1454 dev[1].connect("test-wpa2-psk", psk="0123456789abcdef", 1455 scan_freq="2412") 1456 finally: 1457 t_events['stop'].set() 1458 t.join() 1459 1460def test_radius_sae_password(dev, apdev): 1461 """WPA3 with SAE password from RADIUS""" 1462 check_sae_capab(dev[0]) 1463 check_sae_capab(dev[1]) 1464 1465 t, t_events = start_radius_psk_server("12345678") 1466 1467 try: 1468 params = hostapd_radius_psk_test_params() 1469 params['ssid'] = "test-wpa3-sae" 1470 params["wpa_key_mgmt"] = "SAE" 1471 params['ieee80211w'] = '2' 1472 hapd = hostapd.add_ap(apdev[0], params) 1473 dev[0].set("sae_groups", "") 1474 dev[0].connect("test-wpa3-sae", sae_password="12345678", key_mgmt="SAE", 1475 ieee80211w="2", scan_freq="2412") 1476 t_events['psk'] = "0123456789abcdef" 1477 dev[1].set("sae_groups", "") 1478 dev[1].connect("test-wpa3-sae", sae_password="0123456789abcdef", 1479 key_mgmt="SAE", ieee80211w="2", scan_freq="2412") 1480 finally: 1481 t_events['stop'].set() 1482 t.join() 1483 1484def test_radius_psk_default(dev, apdev): 1485 """WPA2 with default PSK""" 1486 ssid = "test-wpa2-psk" 1487 params = hostapd.radius_params() 1488 params['ssid'] = ssid 1489 params["wpa"] = "2" 1490 params["wpa_key_mgmt"] = "WPA-PSK" 1491 params["rsn_pairwise"] = "CCMP" 1492 params['macaddr_acl'] = '2' 1493 params['wpa_psk_radius'] = '1' 1494 params['wpa_passphrase'] = 'qwertyuiop' 1495 hapd = hostapd.add_ap(apdev[0], params) 1496 1497 dev[0].connect(ssid, psk="qwertyuiop", scan_freq="2412") 1498 dev[0].dump_monitor() 1499 dev[0].request("REMOVE_NETWORK all") 1500 dev[0].wait_disconnected() 1501 dev[0].dump_monitor() 1502 1503 hapd.disable() 1504 hapd.set("wpa_psk_radius", "2") 1505 hapd.enable() 1506 dev[0].connect(ssid, psk="qwertyuiop", scan_freq="2412", wait_connect=False) 1507 ev = dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10) 1508 if ev is None: 1509 raise Exception("No CTRL-EVENT-AUTH-REJECT event") 1510 dev[0].request("DISCONNECT") 1511 1512def test_radius_auth_force_client_addr(dev, apdev): 1513 """RADIUS client address specified""" 1514 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1515 params['radius_client_addr'] = "127.0.0.1" 1516 hapd = hostapd.add_ap(apdev[0], params) 1517 connect(dev[0], "radius-auth") 1518 1519def test_radius_auth_force_client_dev(dev, apdev): 1520 """RADIUS client device specified""" 1521 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1522 params['radius_client_dev'] = "lo" 1523 hapd = hostapd.add_ap(apdev[0], params) 1524 connect(dev[0], "radius-auth") 1525 1526@remote_compatible 1527def test_radius_auth_force_invalid_client_addr(dev, apdev): 1528 """RADIUS client address specified and invalid address""" 1529 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1530 #params['radius_client_addr'] = "10.11.12.14" 1531 params['radius_client_addr'] = "1::2" 1532 hapd = hostapd.add_ap(apdev[0], params) 1533 connect(dev[0], "radius-auth", wait_connect=False) 1534 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"]) 1535 if ev is None: 1536 raise Exception("Timeout on EAP start") 1537 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1) 1538 if ev is not None: 1539 raise Exception("Unexpected connection") 1540 1541def add_message_auth(req): 1542 req.authenticator = req.CreateAuthenticator() 1543 hmac_obj = hmac.new(req.secret, digestmod=hashlib.md5) 1544 hmac_obj.update(struct.pack("B", req.code)) 1545 hmac_obj.update(struct.pack("B", req.id)) 1546 1547 # request attributes 1548 req.AddAttribute("Message-Authenticator", 16*b"\x00") 1549 attrs = req._PktEncodeAttributes() 1550 1551 # Length 1552 flen = 4 + 16 + len(attrs) 1553 hmac_obj.update(struct.pack(">H", flen)) 1554 hmac_obj.update(req.authenticator) 1555 hmac_obj.update(attrs) 1556 del req[80] 1557 add_message_authenticator_attr(req, hmac_obj.digest()) 1558 1559def test_radius_server_failures(dev, apdev): 1560 """RADIUS server failure cases""" 1561 try: 1562 import pyrad.client 1563 import pyrad.packet 1564 import pyrad.dictionary 1565 except ImportError: 1566 raise HwsimSkip("No pyrad modules available") 1567 1568 dict = pyrad.dictionary.Dictionary("dictionary.radius") 1569 client = pyrad.client.Client(server="127.0.0.1", authport=1812, 1570 secret=b"radius", dict=dict) 1571 client.retries = 1 1572 client.timeout = 1 1573 1574 # unexpected State 1575 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest, 1576 User_Name="foo") 1577 req['State'] = b'foo-state' 1578 add_message_auth(req) 1579 reply = client.SendPacket(req) 1580 if reply.code != pyrad.packet.AccessReject: 1581 raise Exception("Unexpected RADIUS response code " + str(reply.code)) 1582 1583 # no EAP-Message 1584 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest, 1585 User_Name="foo") 1586 add_message_auth(req) 1587 try: 1588 reply = client.SendPacket(req) 1589 raise Exception("Unexpected response") 1590 except pyrad.client.Timeout: 1591 pass 1592 1593def test_ap_vlan_wpa2_psk_radius_required(dev, apdev): 1594 """AP VLAN with WPA2-PSK and RADIUS attributes required""" 1595 try: 1596 import pyrad.server 1597 import pyrad.packet 1598 import pyrad.dictionary 1599 except ImportError: 1600 raise HwsimSkip("No pyrad modules available") 1601 1602 class TestServer(pyrad.server.Server): 1603 def _HandleAuthPacket(self, pkt): 1604 pyrad.server.Server._HandleAuthPacket(self, pkt) 1605 logger.info("Received authentication request") 1606 reply = self.CreateReplyPacket(pkt) 1607 reply.code = pyrad.packet.AccessAccept 1608 secret = reply.secret 1609 if self.t_events['extra'].is_set(): 1610 reply.AddAttribute("Chargeable-User-Identity", "test-cui") 1611 reply.AddAttribute("User-Name", "test-user") 1612 if self.t_events['long'].is_set(): 1613 reply.AddAttribute("Tunnel-Type", 13) 1614 reply.AddAttribute("Tunnel-Medium-Type", 6) 1615 reply.AddAttribute("Tunnel-Private-Group-ID", "1") 1616 build_message_auth(pkt, reply) 1617 self.SendReplyPacket(pkt.fd, reply) 1618 1619 def RunWithStop(self, t_events): 1620 self._poll = select.poll() 1621 self._fdmap = {} 1622 self._PrepareSockets() 1623 self.t_events = t_events 1624 1625 while not t_events['stop'].is_set(): 1626 for (fd, event) in self._poll.poll(1000): 1627 if event == select.POLLIN: 1628 try: 1629 fdo = self._fdmap[fd] 1630 self._ProcessInput(fdo) 1631 except pyrad.server.ServerPacketError as err: 1632 logger.info("pyrad server dropping packet: " + str(err)) 1633 except pyrad.packet.PacketError as err: 1634 logger.info("pyrad server received invalid packet: " + str(err)) 1635 else: 1636 logger.error("Unexpected event in pyrad server main loop") 1637 1638 for fd in self.authfds + self.acctfds: 1639 fd.close() 1640 1641 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"), 1642 authport=18138, acctport=18139) 1643 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1", 1644 b"radius", 1645 "localhost") 1646 srv.BindToAddress("127.0.0.1") 1647 t_events = {} 1648 t_events['stop'] = threading.Event() 1649 t_events['long'] = threading.Event() 1650 t_events['extra'] = threading.Event() 1651 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events)) 1652 t.start() 1653 1654 try: 1655 ssid = "test-wpa2-psk" 1656 params = hostapd.radius_params() 1657 params['ssid'] = ssid 1658 params["wpa"] = "2" 1659 params["wpa_key_mgmt"] = "WPA-PSK" 1660 params["rsn_pairwise"] = "CCMP" 1661 params['macaddr_acl'] = '2' 1662 params['dynamic_vlan'] = "2" 1663 params['wpa_passphrase'] = '0123456789abcdefghi' 1664 params['auth_server_port'] = "18138" 1665 hapd = hostapd.add_ap(apdev[0], params) 1666 1667 logger.info("connecting without VLAN") 1668 dev[0].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1669 wait_connect=False) 1670 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", 1671 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1672 if ev is None: 1673 raise Exception("Timeout on connection attempt") 1674 if "CTRL-EVENT-CONNECTED" in ev: 1675 raise Exception("Unexpected success without vlan parameters") 1676 logger.info("connecting without VLAN failed as expected") 1677 1678 logger.info("connecting without VLAN (CUI/User-Name)") 1679 t_events['extra'].set() 1680 dev[1].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1681 wait_connect=False) 1682 ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED", 1683 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1684 if ev is None: 1685 raise Exception("Timeout on connection attempt") 1686 if "CTRL-EVENT-CONNECTED" in ev: 1687 raise Exception("Unexpected success without vlan parameters(2)") 1688 logger.info("connecting without VLAN failed as expected(2)") 1689 t_events['extra'].clear() 1690 1691 t_events['long'].set() 1692 logger.info("connecting with VLAN") 1693 dev[2].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1694 wait_connect=False) 1695 ev = dev[2].wait_event(["CTRL-EVENT-CONNECTED", 1696 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1697 if ev is None: 1698 raise Exception("Timeout on connection attempt") 1699 if "CTRL-EVENT-SSID-TEMP-DISABLED" in ev: 1700 raise Exception("Unexpected failure with vlan parameters") 1701 logger.info("connecting with VLAN succeeded as expected") 1702 finally: 1703 t_events['stop'].set() 1704 t.join() 1705 1706def test_radius_mppe_failure(dev, apdev): 1707 """RADIUS failure when adding MPPE keys""" 1708 params = {"ssid": "as", "beacon_int": "2000", 1709 "radius_server_clients": "auth_serv/radius_clients.conf", 1710 "radius_server_auth_port": '18127', 1711 "eap_server": "1", 1712 "eap_user_file": "auth_serv/eap_user.conf", 1713 "ca_cert": "auth_serv/ca.pem", 1714 "server_cert": "auth_serv/server.pem", 1715 "private_key": "auth_serv/server.key"} 1716 authsrv = hostapd.add_ap(apdev[1], params) 1717 1718 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") 1719 params['auth_server_port'] = "18127" 1720 hapd = hostapd.add_ap(apdev[0], params) 1721 1722 with fail_test(authsrv, 1, "os_get_random;radius_msg_add_mppe_keys"): 1723 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", 1724 identity="user", anonymous_identity="ttls", 1725 password="password", 1726 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC", 1727 wait_connect=False, scan_freq="2412") 1728 dev[0].wait_disconnected() 1729 dev[0].request("REMOVE_NETWORK all") 1730 1731def test_radius_acct_failure(dev, apdev): 1732 """RADIUS Accounting and failure to add attributes""" 1733 # Connection goes through, but Accounting-Request cannot be sent out due to 1734 # NAS-Identifier being too long to fit into a RADIUS attribute. 1735 params = {"ssid": "radius-acct-open", 1736 'acct_server_addr': "127.0.0.1", 1737 'acct_server_port': "1813", 1738 'acct_server_shared_secret': "radius", 1739 'nas_identifier': 255*'A'} 1740 hapd = hostapd.add_ap(apdev[0], params) 1741 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1742 1743def test_radius_acct_failure_oom(dev, apdev): 1744 """RADIUS Accounting and failure to add attributes due to OOM""" 1745 params = {"ssid": "radius-acct-open", 1746 'acct_server_addr': "127.0.0.1", 1747 'acct_server_port': "1813", 1748 'acct_server_shared_secret': "radius", 1749 'radius_acct_interim_interval': "1", 1750 'nas_identifier': 250*'A', 1751 'radius_acct_req_attr': ["126:s:" + 250*'B', 1752 "77:s:" + 250*'C', 1753 "127:s:" + 250*'D', 1754 "181:s:" + 250*'E']} 1755 hapd = hostapd.add_ap(apdev[0], params) 1756 bssid = hapd.own_addr() 1757 1758 dev[0].scan_for_bss(bssid, freq="2412") 1759 with alloc_fail(hapd, 1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1760 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1761 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1762 dev[0].request("REMOVE_NETWORK all") 1763 dev[0].wait_disconnected() 1764 1765 dev[1].scan_for_bss(bssid, freq="2412") 1766 with alloc_fail(hapd, 1, "accounting_sta_report"): 1767 dev[1].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1768 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1769 dev[1].request("REMOVE_NETWORK all") 1770 dev[1].wait_disconnected() 1771 1772 tests = [(1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"), 1773 (2, "radius_msg_add_attr;accounting_msg"), 1774 (3, "radius_msg_add_attr;accounting_msg")] 1775 for count, func in tests: 1776 with fail_test(hapd, count, func): 1777 dev[0].connect("radius-acct-open", key_mgmt="NONE", 1778 scan_freq="2412") 1779 wait_fail_trigger(hapd, "GET_FAIL") 1780 dev[0].request("REMOVE_NETWORK all") 1781 dev[0].wait_disconnected() 1782 1783 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1784 with fail_test(hapd, 8, 1785 "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_sta_report"): 1786 dev[0].request("REMOVE_NETWORK all") 1787 dev[0].wait_disconnected() 1788 wait_fail_trigger(hapd, "GET_FAIL") 1789 1790 with fail_test(hapd, 1, "radius_msg_add_attr;=accounting_report_state"): 1791 hapd.disable() 1792 1793def test_radius_acct_failure_oom_rsn(dev, apdev): 1794 """RADIUS Accounting in RSN and failure to add attributes due to OOM""" 1795 params = hostapd.wpa2_eap_params(ssid="radius-acct") 1796 params['acct_server_addr'] = "127.0.0.1" 1797 params['acct_server_port'] = "1813" 1798 params['acct_server_shared_secret'] = "radius" 1799 params['radius_acct_interim_interval'] = "1" 1800 params['nas_identifier'] = 250*'A' 1801 params['radius_acct_req_attr'] = ["126:s:" + 250*'B', 1802 "77:s:" + 250*'C', 1803 "127:s:" + 250*'D', 1804 "181:s:" + 250*'E'] 1805 hapd = hostapd.add_ap(apdev[0], params) 1806 bssid = hapd.own_addr() 1807 1808 dev[0].scan_for_bss(bssid, freq="2412") 1809 with alloc_fail(hapd, 1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1810 connect(dev[0], "radius-acct") 1811 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1812 1813 dev[1].scan_for_bss(bssid, freq="2412") 1814 with alloc_fail(hapd, 1, "accounting_sta_report"): 1815 connect(dev[1], "radius-acct") 1816 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1817 1818 dev[2].scan_for_bss(bssid, freq="2412") 1819 connect(dev[2], "radius-acct") 1820 1821 for i in range(1, 8): 1822 with alloc_fail(hapd, i, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1823 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1824 1825 for i in range(1, 15): 1826 with alloc_fail(hapd, i, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_sta_report"): 1827 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1828 1829def test_radius_acct_failure_sta_data(dev, apdev): 1830 """RADIUS Accounting and failure to get STA data""" 1831 params = {"ssid": "radius-acct-open", 1832 'acct_server_addr': "127.0.0.1", 1833 'acct_server_port': "1813", 1834 'acct_server_shared_secret': "radius"} 1835 hapd = hostapd.add_ap(apdev[0], params) 1836 1837 with fail_test(hapd, 1, "accounting_sta_update_stats"): 1838 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1839 dev[0].request("DISCONNECT") 1840 dev[0].wait_disconnected() 1841 hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=1) 1842 1843def test_radius_tls_freeradius(dev, apdev, test_params): 1844 """RADIUS/TLS with FreeRADIUS""" 1845 if not os.path.exists("FreeRADIUS"): 1846 raise HwsimSkip("FreeRADIUS not available") 1847 1848 confdir = "FreeRADIUS/etc/raddb" 1849 certdir = confdir + "/certs" 1850 pidfile = "/tmp/radiusd.pid" 1851 1852 subprocess.call(['FreeRADIUS/sbin/radiusd', 1853 '-d', confdir, 1854 '-xx', 1855 '-l', test_params['prefix'] + ".freeradius"]) 1856 time.sleep(1) 1857 if not os.path.exists(pidfile): 1858 raise Exception("Could not start FreeRADIUS") 1859 1860 params = hostapd.wpa2_eap_params(ssid="radius-tls") 1861 for s in ["auth", "acct"]: 1862 params[s + '_server_addr'] = "127.0.0.1" 1863 params[s + '_server_port'] = "2083" 1864 params[s + '_server_type'] = "TLS" 1865 params[s + '_server_shared_secret'] = "radsec" 1866 params[s + '_server_ca_cert'] = certdir + "/ca.pem" 1867 params[s + '_server_client_cert'] = certdir + "/client.pem" 1868 params[s + '_server_private_key'] = certdir + "/client.key" 1869 params[s + '_server_private_key_passwd'] = "whatever" 1870 1871 try: 1872 hapd = hostapd.add_ap(apdev[0], params) 1873 time.sleep(1) 1874 dev[0].connect("radius-tls", key_mgmt="WPA-EAP", scan_freq="2412", 1875 eap="PEAP", identity="bob", password="hello") 1876 time.sleep(1) 1877 dev[0].request("DISCONNECT") 1878 dev[0].wait_disconnected() 1879 time.sleep(1) 1880 finally: 1881 with open(pidfile, "r") as f: 1882 pid = int(f.read()) 1883 if pid > 0: 1884 os.kill(pid, signal.SIGTERM) 1885 1886def foo(): 1887 params['auth_server_addr'] = "127.0.0.1" 1888 params['auth_server_port'] = "2083" 1889 params['auth_server_type'] = "TLS" 1890 params['auth_server_shared_secret'] = "radsec" 1891 params['auth_server_ca_cert'] = certdir + "/ca.pem" 1892 params['auth_server_client_cert'] = certdir + "/client.pem" 1893 params['auth_server_private_key'] = certdir + "/client.key" 1894 params['auth_server_private_key_passwd'] = "whatever" 1895 params['acct_server_addr'] = "127.0.0.1" 1896 params['acct_server_port'] = "2083" 1897 params['acct_server_type'] = "TLS" 1898 params['acct_server_shared_secret'] = "radsec" 1899 params['acct_server_ca_cert'] = certdir + "/ca.pem" 1900 params['acct_server_client_cert'] = certdir + "/client.pem" 1901 params['acct_server_private_key'] = certdir + "/client.key" 1902 params['acct_server_private_key_passwd'] = "whatever" 1903