]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: EAP-FAST protocol testing
authorJouni Malinen <j@w1.fi>
Sat, 20 Feb 2016 10:05:48 +0000 (12:05 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 20 Feb 2016 16:25:13 +0000 (18:25 +0200)
Signed-off-by: Jouni Malinen <j@w1.fi>
tests/hwsim/test_eap_proto.py

index 554ae7c9d264c8422edcb3ae19ed3940d8c7dd49..af5c0a8d2b2c1758b553542e449757ac113bbd49 100644 (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)