tests: EAP-FAST protocol testing

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2016-02-20 12:05:48 +02:00
parent 5558b9980f
commit bccd22f356

View file

@ -20,6 +20,12 @@ from utils import HwsimSkip, alloc_fail, fail_test, wait_fail_trigger
from test_ap_eap import check_eap_capa, check_hlr_auc_gw_support, int_eap_server_params
from test_erp import check_erp_capa
try:
import OpenSSL
openssl_imported = True
except ImportError:
openssl_imported = False
EAP_CODE_REQUEST = 1
EAP_CODE_RESPONSE = 2
EAP_CODE_SUCCESS = 3
@ -7911,3 +7917,367 @@ def test_eap_nak_expanded(dev, apdev):
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
EAP_TLV_RESULT_TLV = 3
EAP_TLV_NAK_TLV = 4
EAP_TLV_ERROR_CODE_TLV = 5
EAP_TLV_CONNECTION_BINDING_TLV = 6
EAP_TLV_VENDOR_SPECIFIC_TLV = 7
EAP_TLV_URI_TLV = 8
EAP_TLV_EAP_PAYLOAD_TLV = 9
EAP_TLV_INTERMEDIATE_RESULT_TLV = 10
EAP_TLV_PAC_TLV = 11
EAP_TLV_CRYPTO_BINDING_TLV = 12
EAP_TLV_CALLING_STATION_ID_TLV = 13
EAP_TLV_CALLED_STATION_ID_TLV = 14
EAP_TLV_NAS_PORT_TYPE_TLV = 15
EAP_TLV_SERVER_IDENTIFIER_TLV = 16
EAP_TLV_IDENTITY_TYPE_TLV = 17
EAP_TLV_SERVER_TRUSTED_ROOT_TLV = 18
EAP_TLV_REQUEST_ACTION_TLV = 19
EAP_TLV_PKCS7_TLV = 20
EAP_TLV_RESULT_SUCCESS = 1
EAP_TLV_RESULT_FAILURE = 2
EAP_TLV_TYPE_MANDATORY = 0x8000
EAP_TLV_TYPE_MASK = 0x3fff
PAC_TYPE_PAC_KEY = 1
PAC_TYPE_PAC_OPAQUE = 2
PAC_TYPE_CRED_LIFETIME = 3
PAC_TYPE_A_ID = 4
PAC_TYPE_I_ID = 5
PAC_TYPE_A_ID_INFO = 7
PAC_TYPE_PAC_ACKNOWLEDGEMENT = 8
PAC_TYPE_PAC_INFO = 9
PAC_TYPE_PAC_TYPE = 10
def eap_fast_start(ctx):
logger.info("Send EAP-FAST/Start")
return struct.pack(">BBHBBHH", EAP_CODE_REQUEST, ctx['id'],
4 + 1 + 1 + 4 + 16,
EAP_TYPE_FAST, 0x21, 4, 16) + 16*'A'
def test_eap_fast_proto(dev, apdev):
"""EAP-FAST Phase protocol testing"""
check_eap_capa(dev[0], "FAST")
global eap_fast_proto_ctx
eap_fast_proto_ctx = None
def eap_handler(ctx, req):
logger.info("eap_handler - RX " + req.encode("hex"))
if 'num' not in ctx:
ctx['num'] = 0
ctx['num'] = ctx['num'] + 1
if 'id' not in ctx:
ctx['id'] = 1
ctx['id'] = (ctx['id'] + 1) % 256
idx = 0
global eap_fast_proto_ctx
eap_fast_proto_ctx = ctx
ctx['test_done'] = False
idx += 1
if ctx['num'] == idx:
return eap_fast_start(ctx)
idx += 1
if ctx['num'] == idx:
logger.info("EAP-FAST: TLS processing failed")
data = 'ABCDEFGHIK'
return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
4 + 1 + 1 + len(data),
EAP_TYPE_FAST, 0x01) + data
idx += 1
if ctx['num'] == idx:
ctx['test_done'] = True
return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
logger.info("Past last test case")
return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
srv = start_radius_server(eap_handler)
try:
hapd = start_ap(apdev[0]['ifname'])
dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
eap="FAST", anonymous_identity="FAST",
identity="user", password="password",
ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
phase1="fast_provisioning=1",
pac_file="blob://fast_pac_proto",
wait_connect=False)
ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
if ev is None:
raise Exception("Could not start EAP-FAST")
ok = False
for i in range(100):
if eap_fast_proto_ctx:
if eap_fast_proto_ctx['test_done']:
ok = True
break
time.sleep(0.05)
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
finally:
stop_radius_server(srv)
def run_eap_fast_phase2(dev, test_payload, test_failure=True):
global eap_fast_proto_ctx
eap_fast_proto_ctx = None
def ssl_info_callback(conn, where, ret):
logger.debug("SSL: info where=%d ret=%d" % (where, ret))
def process_clienthello(ctx, payload):
logger.info("Process ClientHello")
ctx['sslctx'] = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD)
ctx['sslctx'].set_info_callback(ssl_info_callback)
ctx['sslctx'].load_tmp_dh("auth_serv/dh.conf")
ctx['sslctx'].set_cipher_list("ADH-AES128-SHA")
ctx['conn'] = OpenSSL.SSL.Connection(ctx['sslctx'], None)
ctx['conn'].set_accept_state()
logger.info("State: " + ctx['conn'].state_string())
ctx['conn'].bio_write(payload)
try:
ctx['conn'].do_handshake()
except OpenSSL.SSL.WantReadError:
pass
logger.info("State: " + ctx['conn'].state_string())
data = ctx['conn'].bio_read(4096)
logger.info("State: " + ctx['conn'].state_string())
return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
4 + 1 + 1 + len(data),
EAP_TYPE_FAST, 0x01) + data
def process_clientkeyexchange(ctx, payload, appl_data):
logger.info("Process ClientKeyExchange")
logger.info("State: " + ctx['conn'].state_string())
ctx['conn'].bio_write(payload)
try:
ctx['conn'].do_handshake()
except OpenSSL.SSL.WantReadError:
pass
ctx['conn'].send(appl_data)
logger.info("State: " + ctx['conn'].state_string())
data = ctx['conn'].bio_read(4096)
logger.info("State: " + ctx['conn'].state_string())
return struct.pack(">BBHBB", EAP_CODE_REQUEST, ctx['id'],
4 + 1 + 1 + len(data),
EAP_TYPE_FAST, 0x01) + data
def eap_handler(ctx, req):
logger.info("eap_handler - RX " + req.encode("hex"))
if 'num' not in ctx:
ctx['num'] = 0
ctx['num'] = ctx['num'] + 1
if 'id' not in ctx:
ctx['id'] = 1
ctx['id'] = (ctx['id'] + 1) % 256
idx = 0
global eap_fast_proto_ctx
eap_fast_proto_ctx = ctx
ctx['test_done'] = False
logger.debug("ctx['num']=%d" % ctx['num'])
idx += 1
if ctx['num'] == idx:
return eap_fast_start(ctx)
idx += 1
if ctx['num'] == idx:
return process_clienthello(ctx, req[6:])
idx += 1
if ctx['num'] == idx:
if not test_failure:
ctx['test_done'] = True
return process_clientkeyexchange(ctx, req[6:], test_payload)
idx += 1
if ctx['num'] == idx:
ctx['test_done'] = True
return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
logger.info("Past last test case")
return struct.pack(">BBH", EAP_CODE_FAILURE, ctx['id'], 4)
srv = start_radius_server(eap_handler)
try:
dev[0].connect("eap-test", key_mgmt="WPA-EAP", scan_freq="2412",
eap="FAST", anonymous_identity="FAST",
identity="user", password="password",
ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
phase1="fast_provisioning=1",
pac_file="blob://fast_pac_proto",
wait_connect=False)
ev = dev[0].wait_event(["CTRL-EVENT-EAP-METHOD"], timeout=5)
if ev is None:
raise Exception("Could not start EAP-FAST")
dev[0].dump_monitor()
ok = False
for i in range(100):
if eap_fast_proto_ctx:
if eap_fast_proto_ctx['test_done']:
ok = True
break
time.sleep(0.05)
time.sleep(0.1)
dev[0].request("REMOVE_NETWORK all")
dev[0].wait_disconnected()
if not ok:
raise Exception("EAP-FAST TLS exchange did not complete")
for i in range(3):
dev[i].dump_monitor()
finally:
stop_radius_server(srv)
def test_eap_fast_proto_phase2(dev, apdev):
"""EAP-FAST Phase 2 protocol testing"""
if not openssl_imported:
raise HwsimSkip("OpenSSL python method not available")
check_eap_capa(dev[0], "FAST")
hapd = start_ap(apdev[0]['ifname'])
tests = [ ("Too short Phase 2 TLV frame (len=3)",
"ABC",
False),
("EAP-FAST: TLV overflow",
struct.pack(">HHB", 0, 2, 0xff),
False),
("EAP-FAST: Unknown TLV (optional and mandatory)",
struct.pack(">HHB", 0, 1, 0xff) +
struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY, 1, 0xff),
True),
("EAP-FAST: More than one EAP-Payload TLV in the message",
struct.pack(">HHBHHB",
EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff,
EAP_TLV_EAP_PAYLOAD_TLV, 1, 0xff),
True),
("EAP-FAST: Unknown Result 255 and More than one Result TLV in the message",
struct.pack(">HHHHHH",
EAP_TLV_RESULT_TLV, 2, 0xff,
EAP_TLV_RESULT_TLV, 2, 0xff),
True),
("EAP-FAST: Too short Result TLV",
struct.pack(">HHB", EAP_TLV_RESULT_TLV, 1, 0xff),
True),
("EAP-FAST: Unknown Intermediate Result 255 and More than one Intermediate-Result TLV in the message",
struct.pack(">HHHHHH",
EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff,
EAP_TLV_INTERMEDIATE_RESULT_TLV, 2, 0xff),
True),
("EAP-FAST: Too short Intermediate-Result TLV",
struct.pack(">HHB", EAP_TLV_INTERMEDIATE_RESULT_TLV, 1, 0xff),
True),
("EAP-FAST: More than one Crypto-Binding TLV in the message",
struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A' +
struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A',
True),
("EAP-FAST: Too short Crypto-Binding TLV",
struct.pack(">HHB", EAP_TLV_CRYPTO_BINDING_TLV, 1, 0xff),
True),
("EAP-FAST: More than one Request-Action TLV in the message",
struct.pack(">HHBBHHBB",
EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff,
EAP_TLV_REQUEST_ACTION_TLV, 2, 0xff, 0xff),
True),
("EAP-FAST: Too short Request-Action TLV",
struct.pack(">HHB", EAP_TLV_REQUEST_ACTION_TLV, 1, 0xff),
True),
("EAP-FAST: More than one PAC TLV in the message",
struct.pack(">HHBHHB",
EAP_TLV_PAC_TLV, 1, 0xff,
EAP_TLV_PAC_TLV, 1, 0xff),
True),
("EAP-FAST: Too short EAP Payload TLV (Len=3)",
struct.pack(">HH3B",
EAP_TLV_EAP_PAYLOAD_TLV, 3, 0, 0, 0),
False),
("EAP-FAST: Too short Phase 2 request (Len=0)",
struct.pack(">HHBBH",
EAP_TLV_EAP_PAYLOAD_TLV, 4,
EAP_CODE_REQUEST, 0, 0),
False),
("EAP-FAST: EAP packet overflow in EAP Payload TLV",
struct.pack(">HHBBH",
EAP_TLV_EAP_PAYLOAD_TLV, 4,
EAP_CODE_REQUEST, 0, 4 + 1),
False),
("EAP-FAST: Unexpected code=0 in Phase 2 EAP header",
struct.pack(">HHBBH",
EAP_TLV_EAP_PAYLOAD_TLV, 4,
0, 0, 0),
False),
("EAP-FAST: PAC TLV without Result TLV acknowledging success",
struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
True),
("EAP-FAST: PAC TLV does not include all the required fields",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHB", EAP_TLV_PAC_TLV, 1, 0xff),
True),
("EAP-FAST: Invalid PAC-Key length 0, Ignored unknown PAC type 0, and PAC TLV overrun (type=0 len=2 left=1)",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHHB", EAP_TLV_PAC_TLV, 4 + 4 + 5,
PAC_TYPE_PAC_KEY, 0, 0, 0, 0, 2, 0),
True),
("EAP-FAST: PAC-Info does not include all the required fields",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 4 + 32,
PAC_TYPE_PAC_OPAQUE, 0,
PAC_TYPE_PAC_INFO, 0,
PAC_TYPE_PAC_KEY, 32) + 32*'A',
True),
("EAP-FAST: Invalid CRED_LIFETIME length, Ignored unknown PAC-Info type 0, and Invalid PAC-Type length 1",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 13 + 4 + 32,
PAC_TYPE_PAC_OPAQUE, 0,
PAC_TYPE_PAC_INFO, 13, PAC_TYPE_CRED_LIFETIME, 0,
0, 0, PAC_TYPE_PAC_TYPE, 1, 0,
PAC_TYPE_PAC_KEY, 32) + 32*'A',
True),
("EAP-FAST: Unsupported PAC-Type 0",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHHHHH", EAP_TLV_PAC_TLV, 4 + 4 + 6 + 4 + 32,
PAC_TYPE_PAC_OPAQUE, 0,
PAC_TYPE_PAC_INFO, 6, PAC_TYPE_PAC_TYPE, 2, 0,
PAC_TYPE_PAC_KEY, 32) + 32*'A',
True),
("EAP-FAST: PAC-Info overrun (type=0 len=2 left=1)",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHHBHH", EAP_TLV_PAC_TLV, 4 + 4 + 5 + 4 + 32,
PAC_TYPE_PAC_OPAQUE, 0,
PAC_TYPE_PAC_INFO, 5, 0, 2, 1,
PAC_TYPE_PAC_KEY, 32) + 32*'A',
True),
("EAP-FAST: Valid PAC",
struct.pack(">HHH", EAP_TLV_RESULT_TLV, 2,
EAP_TLV_RESULT_SUCCESS) +
struct.pack(">HHHHHHHHBHHBHH", EAP_TLV_PAC_TLV,
4 + 4 + 10 + 4 + 32,
PAC_TYPE_PAC_OPAQUE, 0,
PAC_TYPE_PAC_INFO, 10, PAC_TYPE_A_ID, 1, 0x41,
PAC_TYPE_A_ID_INFO, 1, 0x42,
PAC_TYPE_PAC_KEY, 32) + 32*'A',
True),
("EAP-FAST: Invalid version/subtype in Crypto-Binding TLV",
struct.pack(">HH", EAP_TLV_CRYPTO_BINDING_TLV, 60) + 60*'A',
True) ]
for title, payload, failure in tests:
logger.info("Phase 2 test: " + title)
run_eap_fast_phase2(dev, payload, failure)
def test_eap_fast_tlv_nak_oom(dev, apdev):
"""EAP-FAST Phase 2 TLV NAK OOM"""
if not openssl_imported:
raise HwsimSkip("OpenSSL python method not available")
check_eap_capa(dev[0], "FAST")
hapd = start_ap(apdev[0]['ifname'])
with alloc_fail(dev[0], 1, "eap_fast_tlv_nak"):
run_eap_fast_phase2(dev, struct.pack(">HHB", EAP_TLV_TYPE_MANDATORY,
1, 0xff), False)