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 try: 1211 import pyrad.server 1212 import pyrad.packet 1213 import pyrad.dictionary 1214 except ImportError: 1215 raise HwsimSkip("No pyrad modules available") 1216 1217 class TestServer(pyrad.server.Server): 1218 def _HandleAuthPacket(self, pkt): 1219 pyrad.server.Server._HandleAuthPacket(self, pkt) 1220 logger.info("Received authentication request") 1221 reply = self.CreateReplyPacket(pkt) 1222 reply.code = pyrad.packet.AccessAccept 1223 if self.t_events['invalid_code']: 1224 reply.code = pyrad.packet.AccessRequest 1225 if self.t_events['reject']: 1226 reply.code = pyrad.packet.AccessReject 1227 data = build_tunnel_password(reply.secret, pkt.authenticator, 1228 self.t_events['psk']) 1229 reply.AddAttribute("Tunnel-Password", data) 1230 if self.t_events['acct_interim_interval']: 1231 reply.AddAttribute("Acct-Interim-Interval", 1232 self.t_events['acct_interim_interval']) 1233 if self.t_events['session_timeout']: 1234 reply.AddAttribute("Session-Timeout", 1235 self.t_events['session_timeout']) 1236 build_message_auth(pkt, reply) 1237 1238 self.SendReplyPacket(pkt.fd, reply) 1239 1240 def RunWithStop(self, t_events): 1241 self._poll = select.poll() 1242 self._fdmap = {} 1243 self._PrepareSockets() 1244 self.t_events = t_events 1245 1246 while not t_events['stop'].is_set(): 1247 for (fd, event) in self._poll.poll(1000): 1248 if event == select.POLLIN: 1249 try: 1250 fdo = self._fdmap[fd] 1251 self._ProcessInput(fdo) 1252 except pyrad.server.ServerPacketError as err: 1253 logger.info("pyrad server dropping packet: " + str(err)) 1254 except pyrad.packet.PacketError as err: 1255 logger.info("pyrad server received invalid packet: " + str(err)) 1256 else: 1257 logger.error("Unexpected event in pyrad server main loop") 1258 1259 for fd in self.authfds + self.acctfds: 1260 fd.close() 1261 1262 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"), 1263 authport=18138, acctport=18139) 1264 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1", 1265 b"radius", 1266 "localhost") 1267 srv.BindToAddress("127.0.0.1") 1268 t_events = {} 1269 t_events['stop'] = threading.Event() 1270 t_events['psk'] = psk 1271 t_events['invalid_code'] = invalid_code 1272 t_events['acct_interim_interval'] = acct_interim_interval 1273 t_events['session_timeout'] = session_timeout 1274 t_events['reject'] = reject 1275 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events)) 1276 t.start() 1277 return t, t_events 1278 1279def hostapd_radius_psk_test_params(): 1280 params = hostapd.radius_params() 1281 params['ssid'] = "test-wpa2-psk" 1282 params["wpa"] = "2" 1283 params["wpa_key_mgmt"] = "WPA-PSK" 1284 params["rsn_pairwise"] = "CCMP" 1285 params['macaddr_acl'] = '2' 1286 params['wpa_psk_radius'] = '2' 1287 params['auth_server_port'] = "18138" 1288 return params 1289 1290def test_radius_psk(dev, apdev): 1291 """WPA2 with PSK from RADIUS""" 1292 t, t_events = start_radius_psk_server("12345678") 1293 1294 try: 1295 params = hostapd_radius_psk_test_params() 1296 hapd = hostapd.add_ap(apdev[0], params) 1297 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412") 1298 t_events['psk'] = "0123456789abcdef" 1299 dev[1].connect("test-wpa2-psk", psk="0123456789abcdef", 1300 scan_freq="2412") 1301 finally: 1302 t_events['stop'].set() 1303 t.join() 1304 1305def test_radius_psk_during_4way_hs(dev, apdev): 1306 """WPA2 with PSK from RADIUS during 4-way handshake""" 1307 run_radius_psk_during_4way_hs(dev, apdev, 0) 1308 1309def test_radius_psk_during_4way_hs_session_timeout(dev, apdev): 1310 """WPA2 with PSK from RADIUS during 4-way handshake with Session-Timeout""" 1311 run_radius_psk_during_4way_hs(dev, apdev, 10000) 1312 1313def run_radius_psk_during_4way_hs(dev, apdev, session_timeout): 1314 t, t_events = start_radius_psk_server("12345678", 1315 session_timeout=session_timeout) 1316 1317 try: 1318 params = hostapd_radius_psk_test_params() 1319 params['macaddr_acl'] = '0' 1320 params['wpa_psk_radius'] = '3' 1321 hapd = hostapd.add_ap(apdev[0], params) 1322 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412") 1323 t_events['psk'] = "0123456789abcdef" 1324 dev[1].connect("test-wpa2-psk", psk="0123456789abcdef", 1325 scan_freq="2412") 1326 finally: 1327 t_events['stop'].set() 1328 t.join() 1329 1330def test_radius_psk_invalid(dev, apdev): 1331 """WPA2 with invalid PSK from RADIUS""" 1332 t, t_events = start_radius_psk_server("1234567") 1333 1334 try: 1335 params = hostapd_radius_psk_test_params() 1336 hapd = hostapd.add_ap(apdev[0], params) 1337 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1338 wait_connect=False) 1339 time.sleep(1) 1340 finally: 1341 t_events['stop'].set() 1342 t.join() 1343 1344def test_radius_psk_invalid2(dev, apdev): 1345 """WPA2 with invalid PSK (hexstring) from RADIUS""" 1346 t, t_events = start_radius_psk_server(64*'q') 1347 1348 try: 1349 params = hostapd_radius_psk_test_params() 1350 hapd = hostapd.add_ap(apdev[0], params) 1351 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1352 wait_connect=False) 1353 time.sleep(1) 1354 finally: 1355 t_events['stop'].set() 1356 t.join() 1357 1358def test_radius_psk_hex_psk(dev, apdev): 1359 """WPA2 with PSK hexstring from RADIUS""" 1360 t, t_events = start_radius_psk_server(64*'2', acct_interim_interval=19, 1361 session_timeout=123) 1362 1363 try: 1364 params = hostapd_radius_psk_test_params() 1365 hapd = hostapd.add_ap(apdev[0], params) 1366 dev[0].connect("test-wpa2-psk", raw_psk=64*'2', scan_freq="2412") 1367 finally: 1368 t_events['stop'].set() 1369 t.join() 1370 1371def test_radius_psk_unknown_code(dev, apdev): 1372 """WPA2 with PSK from RADIUS and unknown code""" 1373 t, t_events = start_radius_psk_server(64*'2', invalid_code=True) 1374 1375 try: 1376 params = hostapd_radius_psk_test_params() 1377 hapd = hostapd.add_ap(apdev[0], params) 1378 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1379 wait_connect=False) 1380 time.sleep(1) 1381 finally: 1382 t_events['stop'].set() 1383 t.join() 1384 1385def test_radius_psk_reject(dev, apdev): 1386 """WPA2 with PSK from RADIUS and reject""" 1387 t, t_events = start_radius_psk_server("12345678", reject=True) 1388 1389 try: 1390 params = hostapd_radius_psk_test_params() 1391 hapd = hostapd.add_ap(apdev[0], params) 1392 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1393 wait_connect=False) 1394 ev = dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10) 1395 if ev is None: 1396 raise Exception("No CTRL-EVENT-AUTH-REJECT event") 1397 dev[0].request("DISCONNECT") 1398 finally: 1399 t_events['stop'].set() 1400 t.join() 1401 1402def test_radius_psk_reject_during_4way_hs(dev, apdev): 1403 """WPA2 with PSK from RADIUS and reject""" 1404 t, t_events = start_radius_psk_server("12345678", reject=True) 1405 1406 try: 1407 params = hostapd_radius_psk_test_params() 1408 params['macaddr_acl'] = '0' 1409 params['wpa_psk_radius'] = '3' 1410 hapd = hostapd.add_ap(apdev[0], params) 1411 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1412 wait_connect=False) 1413 dev[0].wait_disconnected() 1414 dev[0].request("DISCONNECT") 1415 finally: 1416 t_events['stop'].set() 1417 t.join() 1418 1419def test_radius_psk_oom(dev, apdev): 1420 """WPA2 with PSK from RADIUS and OOM""" 1421 t, t_events = start_radius_psk_server(64*'2') 1422 1423 try: 1424 params = hostapd_radius_psk_test_params() 1425 hapd = hostapd.add_ap(apdev[0], params) 1426 bssid = hapd.own_addr() 1427 dev[0].scan_for_bss(bssid, freq="2412") 1428 with alloc_fail(hapd, 1, "=hostapd_acl_recv_radius"): 1429 dev[0].connect("test-wpa2-psk", psk="12345678", scan_freq="2412", 1430 wait_connect=False) 1431 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1432 finally: 1433 t_events['stop'].set() 1434 t.join() 1435 1436def test_radius_sae_password(dev, apdev): 1437 """WPA3 with SAE password from RADIUS""" 1438 check_sae_capab(dev[0]) 1439 check_sae_capab(dev[1]) 1440 1441 t, t_events = start_radius_psk_server("12345678") 1442 1443 try: 1444 params = hostapd_radius_psk_test_params() 1445 params['ssid'] = "test-wpa3-sae" 1446 params["wpa_key_mgmt"] = "SAE" 1447 params['ieee80211w'] = '2' 1448 hapd = hostapd.add_ap(apdev[0], params) 1449 dev[0].set("sae_groups", "") 1450 dev[0].connect("test-wpa3-sae", sae_password="12345678", key_mgmt="SAE", 1451 ieee80211w="2", scan_freq="2412") 1452 t_events['psk'] = "0123456789abcdef" 1453 dev[1].set("sae_groups", "") 1454 dev[1].connect("test-wpa3-sae", sae_password="0123456789abcdef", 1455 key_mgmt="SAE", ieee80211w="2", scan_freq="2412") 1456 finally: 1457 t_events['stop'].set() 1458 t.join() 1459 1460def test_radius_psk_default(dev, apdev): 1461 """WPA2 with default PSK""" 1462 ssid = "test-wpa2-psk" 1463 params = hostapd.radius_params() 1464 params['ssid'] = ssid 1465 params["wpa"] = "2" 1466 params["wpa_key_mgmt"] = "WPA-PSK" 1467 params["rsn_pairwise"] = "CCMP" 1468 params['macaddr_acl'] = '2' 1469 params['wpa_psk_radius'] = '1' 1470 params['wpa_passphrase'] = 'qwertyuiop' 1471 hapd = hostapd.add_ap(apdev[0], params) 1472 1473 dev[0].connect(ssid, psk="qwertyuiop", scan_freq="2412") 1474 dev[0].dump_monitor() 1475 dev[0].request("REMOVE_NETWORK all") 1476 dev[0].wait_disconnected() 1477 dev[0].dump_monitor() 1478 1479 hapd.disable() 1480 hapd.set("wpa_psk_radius", "2") 1481 hapd.enable() 1482 dev[0].connect(ssid, psk="qwertyuiop", scan_freq="2412", wait_connect=False) 1483 ev = dev[0].wait_event(["CTRL-EVENT-AUTH-REJECT"], timeout=10) 1484 if ev is None: 1485 raise Exception("No CTRL-EVENT-AUTH-REJECT event") 1486 dev[0].request("DISCONNECT") 1487 1488def test_radius_auth_force_client_addr(dev, apdev): 1489 """RADIUS client address specified""" 1490 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1491 params['radius_client_addr'] = "127.0.0.1" 1492 hapd = hostapd.add_ap(apdev[0], params) 1493 connect(dev[0], "radius-auth") 1494 1495def test_radius_auth_force_client_dev(dev, apdev): 1496 """RADIUS client device specified""" 1497 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1498 params['radius_client_dev'] = "lo" 1499 hapd = hostapd.add_ap(apdev[0], params) 1500 connect(dev[0], "radius-auth") 1501 1502@remote_compatible 1503def test_radius_auth_force_invalid_client_addr(dev, apdev): 1504 """RADIUS client address specified and invalid address""" 1505 params = hostapd.wpa2_eap_params(ssid="radius-auth") 1506 #params['radius_client_addr'] = "10.11.12.14" 1507 params['radius_client_addr'] = "1::2" 1508 hapd = hostapd.add_ap(apdev[0], params) 1509 connect(dev[0], "radius-auth", wait_connect=False) 1510 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"]) 1511 if ev is None: 1512 raise Exception("Timeout on EAP start") 1513 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1) 1514 if ev is not None: 1515 raise Exception("Unexpected connection") 1516 1517def add_message_auth(req): 1518 req.authenticator = req.CreateAuthenticator() 1519 hmac_obj = hmac.new(req.secret, digestmod=hashlib.md5) 1520 hmac_obj.update(struct.pack("B", req.code)) 1521 hmac_obj.update(struct.pack("B", req.id)) 1522 1523 # request attributes 1524 req.AddAttribute("Message-Authenticator", 16*b"\x00") 1525 attrs = req._PktEncodeAttributes() 1526 1527 # Length 1528 flen = 4 + 16 + len(attrs) 1529 hmac_obj.update(struct.pack(">H", flen)) 1530 hmac_obj.update(req.authenticator) 1531 hmac_obj.update(attrs) 1532 del req[80] 1533 add_message_authenticator_attr(req, hmac_obj.digest()) 1534 1535def test_radius_server_failures(dev, apdev): 1536 """RADIUS server failure cases""" 1537 try: 1538 import pyrad.client 1539 import pyrad.packet 1540 import pyrad.dictionary 1541 except ImportError: 1542 raise HwsimSkip("No pyrad modules available") 1543 1544 dict = pyrad.dictionary.Dictionary("dictionary.radius") 1545 client = pyrad.client.Client(server="127.0.0.1", authport=1812, 1546 secret=b"radius", dict=dict) 1547 client.retries = 1 1548 client.timeout = 1 1549 1550 # unexpected State 1551 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest, 1552 User_Name="foo") 1553 req['State'] = b'foo-state' 1554 add_message_auth(req) 1555 reply = client.SendPacket(req) 1556 if reply.code != pyrad.packet.AccessReject: 1557 raise Exception("Unexpected RADIUS response code " + str(reply.code)) 1558 1559 # no EAP-Message 1560 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest, 1561 User_Name="foo") 1562 add_message_auth(req) 1563 try: 1564 reply = client.SendPacket(req) 1565 raise Exception("Unexpected response") 1566 except pyrad.client.Timeout: 1567 pass 1568 1569def test_ap_vlan_wpa2_psk_radius_required(dev, apdev): 1570 """AP VLAN with WPA2-PSK and RADIUS attributes required""" 1571 try: 1572 import pyrad.server 1573 import pyrad.packet 1574 import pyrad.dictionary 1575 except ImportError: 1576 raise HwsimSkip("No pyrad modules available") 1577 1578 class TestServer(pyrad.server.Server): 1579 def _HandleAuthPacket(self, pkt): 1580 pyrad.server.Server._HandleAuthPacket(self, pkt) 1581 logger.info("Received authentication request") 1582 reply = self.CreateReplyPacket(pkt) 1583 reply.code = pyrad.packet.AccessAccept 1584 secret = reply.secret 1585 if self.t_events['extra'].is_set(): 1586 reply.AddAttribute("Chargeable-User-Identity", "test-cui") 1587 reply.AddAttribute("User-Name", "test-user") 1588 if self.t_events['long'].is_set(): 1589 reply.AddAttribute("Tunnel-Type", 13) 1590 reply.AddAttribute("Tunnel-Medium-Type", 6) 1591 reply.AddAttribute("Tunnel-Private-Group-ID", "1") 1592 build_message_auth(pkt, reply) 1593 self.SendReplyPacket(pkt.fd, reply) 1594 1595 def RunWithStop(self, t_events): 1596 self._poll = select.poll() 1597 self._fdmap = {} 1598 self._PrepareSockets() 1599 self.t_events = t_events 1600 1601 while not t_events['stop'].is_set(): 1602 for (fd, event) in self._poll.poll(1000): 1603 if event == select.POLLIN: 1604 try: 1605 fdo = self._fdmap[fd] 1606 self._ProcessInput(fdo) 1607 except pyrad.server.ServerPacketError as err: 1608 logger.info("pyrad server dropping packet: " + str(err)) 1609 except pyrad.packet.PacketError as err: 1610 logger.info("pyrad server received invalid packet: " + str(err)) 1611 else: 1612 logger.error("Unexpected event in pyrad server main loop") 1613 1614 for fd in self.authfds + self.acctfds: 1615 fd.close() 1616 1617 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"), 1618 authport=18138, acctport=18139) 1619 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1", 1620 b"radius", 1621 "localhost") 1622 srv.BindToAddress("127.0.0.1") 1623 t_events = {} 1624 t_events['stop'] = threading.Event() 1625 t_events['long'] = threading.Event() 1626 t_events['extra'] = threading.Event() 1627 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events)) 1628 t.start() 1629 1630 try: 1631 ssid = "test-wpa2-psk" 1632 params = hostapd.radius_params() 1633 params['ssid'] = ssid 1634 params["wpa"] = "2" 1635 params["wpa_key_mgmt"] = "WPA-PSK" 1636 params["rsn_pairwise"] = "CCMP" 1637 params['macaddr_acl'] = '2' 1638 params['dynamic_vlan'] = "2" 1639 params['wpa_passphrase'] = '0123456789abcdefghi' 1640 params['auth_server_port'] = "18138" 1641 hapd = hostapd.add_ap(apdev[0], params) 1642 1643 logger.info("connecting without VLAN") 1644 dev[0].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1645 wait_connect=False) 1646 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED", 1647 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1648 if ev is None: 1649 raise Exception("Timeout on connection attempt") 1650 if "CTRL-EVENT-CONNECTED" in ev: 1651 raise Exception("Unexpected success without vlan parameters") 1652 logger.info("connecting without VLAN failed as expected") 1653 1654 logger.info("connecting without VLAN (CUI/User-Name)") 1655 t_events['extra'].set() 1656 dev[1].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1657 wait_connect=False) 1658 ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED", 1659 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1660 if ev is None: 1661 raise Exception("Timeout on connection attempt") 1662 if "CTRL-EVENT-CONNECTED" in ev: 1663 raise Exception("Unexpected success without vlan parameters(2)") 1664 logger.info("connecting without VLAN failed as expected(2)") 1665 t_events['extra'].clear() 1666 1667 t_events['long'].set() 1668 logger.info("connecting with VLAN") 1669 dev[2].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412", 1670 wait_connect=False) 1671 ev = dev[2].wait_event(["CTRL-EVENT-CONNECTED", 1672 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20) 1673 if ev is None: 1674 raise Exception("Timeout on connection attempt") 1675 if "CTRL-EVENT-SSID-TEMP-DISABLED" in ev: 1676 raise Exception("Unexpected failure with vlan parameters") 1677 logger.info("connecting with VLAN succeeded as expected") 1678 finally: 1679 t_events['stop'].set() 1680 t.join() 1681 1682def test_radius_mppe_failure(dev, apdev): 1683 """RADIUS failure when adding MPPE keys""" 1684 params = {"ssid": "as", "beacon_int": "2000", 1685 "radius_server_clients": "auth_serv/radius_clients.conf", 1686 "radius_server_auth_port": '18127', 1687 "eap_server": "1", 1688 "eap_user_file": "auth_serv/eap_user.conf", 1689 "ca_cert": "auth_serv/ca.pem", 1690 "server_cert": "auth_serv/server.pem", 1691 "private_key": "auth_serv/server.key"} 1692 authsrv = hostapd.add_ap(apdev[1], params) 1693 1694 params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") 1695 params['auth_server_port'] = "18127" 1696 hapd = hostapd.add_ap(apdev[0], params) 1697 1698 with fail_test(authsrv, 1, "os_get_random;radius_msg_add_mppe_keys"): 1699 dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS", 1700 identity="user", anonymous_identity="ttls", 1701 password="password", 1702 ca_cert="auth_serv/ca.pem", phase2="autheap=GTC", 1703 wait_connect=False, scan_freq="2412") 1704 dev[0].wait_disconnected() 1705 dev[0].request("REMOVE_NETWORK all") 1706 1707def test_radius_acct_failure(dev, apdev): 1708 """RADIUS Accounting and failure to add attributes""" 1709 # Connection goes through, but Accounting-Request cannot be sent out due to 1710 # NAS-Identifier being too long to fit into a RADIUS attribute. 1711 params = {"ssid": "radius-acct-open", 1712 'acct_server_addr': "127.0.0.1", 1713 'acct_server_port': "1813", 1714 'acct_server_shared_secret': "radius", 1715 'nas_identifier': 255*'A'} 1716 hapd = hostapd.add_ap(apdev[0], params) 1717 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1718 1719def test_radius_acct_failure_oom(dev, apdev): 1720 """RADIUS Accounting and failure to add attributes due to OOM""" 1721 params = {"ssid": "radius-acct-open", 1722 'acct_server_addr': "127.0.0.1", 1723 'acct_server_port': "1813", 1724 'acct_server_shared_secret': "radius", 1725 'radius_acct_interim_interval': "1", 1726 'nas_identifier': 250*'A', 1727 'radius_acct_req_attr': ["126:s:" + 250*'B', 1728 "77:s:" + 250*'C', 1729 "127:s:" + 250*'D', 1730 "181:s:" + 250*'E']} 1731 hapd = hostapd.add_ap(apdev[0], params) 1732 bssid = hapd.own_addr() 1733 1734 dev[0].scan_for_bss(bssid, freq="2412") 1735 with alloc_fail(hapd, 1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1736 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1737 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1738 dev[0].request("REMOVE_NETWORK all") 1739 dev[0].wait_disconnected() 1740 1741 dev[1].scan_for_bss(bssid, freq="2412") 1742 with alloc_fail(hapd, 1, "accounting_sta_report"): 1743 dev[1].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1744 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1745 dev[1].request("REMOVE_NETWORK all") 1746 dev[1].wait_disconnected() 1747 1748 tests = [(1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"), 1749 (2, "radius_msg_add_attr;accounting_msg"), 1750 (3, "radius_msg_add_attr;accounting_msg")] 1751 for count, func in tests: 1752 with fail_test(hapd, count, func): 1753 dev[0].connect("radius-acct-open", key_mgmt="NONE", 1754 scan_freq="2412") 1755 wait_fail_trigger(hapd, "GET_FAIL") 1756 dev[0].request("REMOVE_NETWORK all") 1757 dev[0].wait_disconnected() 1758 1759 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1760 with fail_test(hapd, 8, 1761 "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_sta_report"): 1762 dev[0].request("REMOVE_NETWORK all") 1763 dev[0].wait_disconnected() 1764 wait_fail_trigger(hapd, "GET_FAIL") 1765 1766 with fail_test(hapd, 1, "radius_msg_add_attr;=accounting_report_state"): 1767 hapd.disable() 1768 1769def test_radius_acct_failure_oom_rsn(dev, apdev): 1770 """RADIUS Accounting in RSN and failure to add attributes due to OOM""" 1771 params = hostapd.wpa2_eap_params(ssid="radius-acct") 1772 params['acct_server_addr'] = "127.0.0.1" 1773 params['acct_server_port'] = "1813" 1774 params['acct_server_shared_secret'] = "radius" 1775 params['radius_acct_interim_interval'] = "1" 1776 params['nas_identifier'] = 250*'A' 1777 params['radius_acct_req_attr'] = ["126:s:" + 250*'B', 1778 "77:s:" + 250*'C', 1779 "127:s:" + 250*'D', 1780 "181:s:" + 250*'E'] 1781 hapd = hostapd.add_ap(apdev[0], params) 1782 bssid = hapd.own_addr() 1783 1784 dev[0].scan_for_bss(bssid, freq="2412") 1785 with alloc_fail(hapd, 1, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1786 connect(dev[0], "radius-acct") 1787 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1788 1789 dev[1].scan_for_bss(bssid, freq="2412") 1790 with alloc_fail(hapd, 1, "accounting_sta_report"): 1791 connect(dev[1], "radius-acct") 1792 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1793 1794 dev[2].scan_for_bss(bssid, freq="2412") 1795 connect(dev[2], "radius-acct") 1796 1797 for i in range(1, 8): 1798 with alloc_fail(hapd, i, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_msg"): 1799 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1800 1801 for i in range(1, 15): 1802 with alloc_fail(hapd, i, "radius_msg_add_attr;?radius_msg_add_attr_int32;=accounting_sta_report"): 1803 wait_fail_trigger(hapd, "GET_ALLOC_FAIL") 1804 1805def test_radius_acct_failure_sta_data(dev, apdev): 1806 """RADIUS Accounting and failure to get STA data""" 1807 params = {"ssid": "radius-acct-open", 1808 'acct_server_addr': "127.0.0.1", 1809 'acct_server_port': "1813", 1810 'acct_server_shared_secret': "radius"} 1811 hapd = hostapd.add_ap(apdev[0], params) 1812 1813 with fail_test(hapd, 1, "accounting_sta_update_stats"): 1814 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412") 1815 dev[0].request("DISCONNECT") 1816 dev[0].wait_disconnected() 1817 hapd.wait_event(["AP-STA-DISCONNECTED"], timeout=1) 1818 1819def test_radius_tls_freeradius(dev, apdev, test_params): 1820 """RADIUS/TLS with FreeRADIUS""" 1821 if not os.path.exists("FreeRADIUS"): 1822 raise HwsimSkip("FreeRADIUS not available") 1823 1824 confdir = "FreeRADIUS/etc/raddb" 1825 certdir = confdir + "/certs" 1826 pidfile = "/tmp/radiusd.pid" 1827 1828 subprocess.call(['FreeRADIUS/sbin/radiusd', 1829 '-d', confdir, 1830 '-xx', 1831 '-l', test_params['prefix'] + ".freeradius"]) 1832 time.sleep(1) 1833 if not os.path.exists(pidfile): 1834 raise Exception("Could not start FreeRADIUS") 1835 1836 params = hostapd.wpa2_eap_params(ssid="radius-tls") 1837 for s in ["auth", "acct"]: 1838 params[s + '_server_addr'] = "127.0.0.1" 1839 params[s + '_server_port'] = "2083" 1840 params[s + '_server_type'] = "TLS" 1841 params[s + '_server_shared_secret'] = "radsec" 1842 params[s + '_server_ca_cert'] = certdir + "/ca.pem" 1843 params[s + '_server_client_cert'] = certdir + "/client.pem" 1844 params[s + '_server_private_key'] = certdir + "/client.key" 1845 params[s + '_server_private_key_passwd'] = "whatever" 1846 1847 try: 1848 hapd = hostapd.add_ap(apdev[0], params) 1849 time.sleep(1) 1850 dev[0].connect("radius-tls", key_mgmt="WPA-EAP", scan_freq="2412", 1851 eap="PEAP", identity="bob", password="hello") 1852 time.sleep(1) 1853 dev[0].request("DISCONNECT") 1854 dev[0].wait_disconnected() 1855 time.sleep(1) 1856 finally: 1857 with open(pidfile, "r") as f: 1858 pid = int(f.read()) 1859 if pid > 0: 1860 os.kill(pid, signal.SIGTERM) 1861 1862def foo(): 1863 params['auth_server_addr'] = "127.0.0.1" 1864 params['auth_server_port'] = "2083" 1865 params['auth_server_type'] = "TLS" 1866 params['auth_server_shared_secret'] = "radsec" 1867 params['auth_server_ca_cert'] = certdir + "/ca.pem" 1868 params['auth_server_client_cert'] = certdir + "/client.pem" 1869 params['auth_server_private_key'] = certdir + "/client.key" 1870 params['auth_server_private_key_passwd'] = "whatever" 1871 params['acct_server_addr'] = "127.0.0.1" 1872 params['acct_server_port'] = "2083" 1873 params['acct_server_type'] = "TLS" 1874 params['acct_server_shared_secret'] = "radsec" 1875 params['acct_server_ca_cert'] = certdir + "/ca.pem" 1876 params['acct_server_client_cert'] = certdir + "/client.pem" 1877 params['acct_server_private_key'] = certdir + "/client.key" 1878 params['acct_server_private_key_passwd'] = "whatever" 1879