mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
tests: Verify that wpa_supplicant clears keys from memory
Check that PMK and PTK and not left in memory (heap or stack) unnecessarily after they are not needed anymore. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
4e70bbf1c6
commit
5b3c40a65b
@ -74,6 +74,8 @@ radius_accept_attr=27:d:3
|
||||
"8"* AKA' [2]
|
||||
|
||||
"pap user" TTLS-PAP "password" [2]
|
||||
"pap-secret" TTLS-PAP "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25" [2]
|
||||
"pap-secret@example.com" TTLS-PAP "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25" [2]
|
||||
"chap user" TTLS-CHAP "password" [2]
|
||||
"mschap user" TTLS-MSCHAP "password" [2]
|
||||
"DOMAIN\mschapv2 user" TTLS-MSCHAPV2 hash:8846f7eaee8fb117ad06bdd830b7586c [2]
|
||||
|
@ -6,6 +6,7 @@
|
||||
# See README for more details.
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
import time
|
||||
import subprocess
|
||||
import logging
|
||||
@ -14,7 +15,7 @@ import os
|
||||
|
||||
import hwsim_utils
|
||||
import hostapd
|
||||
from test_ap_psk import check_mib
|
||||
from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations
|
||||
|
||||
def read_pem(fname):
|
||||
with open(fname, "r") as f:
|
||||
@ -2243,3 +2244,98 @@ def test_openssl_cipher_suite_config_hapd(dev, apdev):
|
||||
anonymous_identity="ttls", password="password",
|
||||
openssl_ciphers="HIGH:!ADH",
|
||||
ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
|
||||
|
||||
def test_wpa2_eap_ttls_pap_key_lifetime_in_memory(dev, apdev, params):
|
||||
"""Key lifetime in memory with WPA2-Enterprise using EAP-TTLS/PAP"""
|
||||
p = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
|
||||
hapd = hostapd.add_ap(apdev[0]['ifname'], p)
|
||||
password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
|
||||
pid = find_wpas_process(dev[0])
|
||||
id = eap_connect(dev[0], apdev[0], "TTLS", "pap-secret",
|
||||
anonymous_identity="ttls", password=password,
|
||||
ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
|
||||
time.sleep(0.1)
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected()
|
||||
|
||||
dev[0].relog()
|
||||
pmk = None
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "WPA: PMK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmk = binascii.unhexlify(val)
|
||||
if "WPA: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: Group Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not pmk or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
if len(gtk) != 16:
|
||||
raise Exception("Unexpected GTK length")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
fname = os.path.join(params['logdir'],
|
||||
'wpa2_eap_ttls_pap_key_lifetime_in_memory.memctx-')
|
||||
|
||||
logger.info("Checking keys in memory while associated")
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
if password not in buf:
|
||||
print("Password not found while associated")
|
||||
return "skip"
|
||||
if pmk not in buf:
|
||||
print("PMK not found while associated")
|
||||
return "skip"
|
||||
if kck not in buf:
|
||||
raise Exception("KCK not found while associated")
|
||||
if kek not in buf:
|
||||
raise Exception("KEK not found while associated")
|
||||
if tk in buf:
|
||||
raise Exception("TK found from memory")
|
||||
if gtk in buf:
|
||||
raise Exception("GTK found from memory")
|
||||
|
||||
logger.info("Checking keys in memory after disassociation")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
# Note: Password is still present in network configuration
|
||||
# Note: PMK is in PMKSA cache and EAP fast re-auth data
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("PMKSA_FLUSH")
|
||||
dev[0].set_network_quoted(id, "identity", "foo")
|
||||
logger.info("Checking keys in memory after PMKSA cache and EAP fast reauth flush")
|
||||
buf = read_process_memory(pid, password)
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, password, fname, "password")
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
@ -4,6 +4,8 @@
|
||||
# This software may be distributed under the terms of the BSD license.
|
||||
# See README for more details.
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import logging
|
||||
@ -12,7 +14,7 @@ logger = logging.getLogger()
|
||||
import hwsim_utils
|
||||
import hostapd
|
||||
from wlantest import Wlantest
|
||||
from test_ap_psk import check_mib
|
||||
from test_ap_psk import check_mib, find_wpas_process, read_process_memory, verify_not_present, get_key_locations
|
||||
|
||||
def ft_base_rsn():
|
||||
params = { "wpa": "2",
|
||||
@ -456,3 +458,108 @@ def test_ap_ft_gtk_rekey(dev, apdev):
|
||||
if ev is None:
|
||||
raise Exception("GTK rekey timed out after FT protocol")
|
||||
hwsim_utils.test_connectivity(dev[0], hapd1)
|
||||
|
||||
def test_ft_psk_key_lifetime_in_memory(dev, apdev, params):
|
||||
"""WPA2-PSK-FT and key lifetime in memory"""
|
||||
ssid = "test-ft"
|
||||
passphrase="04c2726b4b8d5f1b4db9c07aa4d9e9d8f765cb5d25ec817e6cc4fcdd5255db0"
|
||||
psk = '93c90846ff67af9037ed83fb72b63dbeddaa81d47f926c20909b5886f1d9358d'
|
||||
pmk = binascii.unhexlify(psk)
|
||||
p = ft_params1(ssid=ssid, passphrase=passphrase)
|
||||
hapd0 = hostapd.add_ap(apdev[0]['ifname'], p)
|
||||
p = ft_params2(ssid=ssid, passphrase=passphrase)
|
||||
hapd1 = hostapd.add_ap(apdev[1]['ifname'], p)
|
||||
|
||||
pid = find_wpas_process(dev[0])
|
||||
|
||||
dev[0].connect(ssid, psk=passphrase, key_mgmt="FT-PSK", proto="WPA2",
|
||||
scan_freq="2412")
|
||||
time.sleep(0.1)
|
||||
|
||||
buf = read_process_memory(pid, pmk)
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected()
|
||||
|
||||
dev[0].relog()
|
||||
pmkr0 = None
|
||||
pmkr1 = None
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "FT: PMK-R0 - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmkr0 = binascii.unhexlify(val)
|
||||
if "FT: PMK-R1 - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmkr1 = binascii.unhexlify(val)
|
||||
if "FT: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: Group Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not pmkr0 or not pmkr1 or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
if len(gtk) != 16:
|
||||
raise Exception("Unexpected GTK length")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
logger.info("Checking keys in memory while associated")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, pmkr0, "PMK-R0")
|
||||
get_key_locations(buf, pmkr1, "PMK-R1")
|
||||
if pmk not in buf:
|
||||
print("PMK not found while associated")
|
||||
return "skip"
|
||||
if pmkr0 not in buf:
|
||||
print("PMK-R0 not found while associated")
|
||||
return "skip"
|
||||
if pmkr1 not in buf:
|
||||
print("PMK-R1 not found while associated")
|
||||
return "skip"
|
||||
if kck not in buf:
|
||||
raise Exception("KCK not found while associated")
|
||||
if kek not in buf:
|
||||
raise Exception("KEK not found while associated")
|
||||
if tk in buf:
|
||||
raise Exception("TK found from memory")
|
||||
if gtk in buf:
|
||||
raise Exception("GTK found from memory")
|
||||
|
||||
logger.info("Checking keys in memory after disassociation")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, pmkr0, "PMK-R0")
|
||||
get_key_locations(buf, pmkr1, "PMK-R1")
|
||||
|
||||
# Note: PMK/PSK is still present in network configuration
|
||||
|
||||
fname = os.path.join(params['logdir'],
|
||||
'ft_psk_key_lifetime_in_memory.memctx-')
|
||||
verify_not_present(buf, pmkr0, fname, "PMK-R0")
|
||||
verify_not_present(buf, pmkr1, fname, "PMK-R1")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, pmkr0, "PMK-R0")
|
||||
get_key_locations(buf, pmkr1, "PMK-R1")
|
||||
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
verify_not_present(buf, pmkr0, fname, "PMK-R0")
|
||||
verify_not_present(buf, pmkr1, fname, "PMK-R1")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
@ -10,6 +10,7 @@ import hmac
|
||||
import logging
|
||||
logger = logging.getLogger()
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import subprocess
|
||||
import time
|
||||
@ -818,3 +819,159 @@ def test_ap_wpa2_psk_ext_eapol_key_info(dev, apdev):
|
||||
|
||||
reply_eapol("4/4", hapd, addr, msg, 0x030a, None, None, kck)
|
||||
hapd_connected(hapd)
|
||||
|
||||
def find_wpas_process(dev):
|
||||
ifname = dev.ifname
|
||||
cmd = subprocess.Popen(['ps', 'ax'], stdout=subprocess.PIPE)
|
||||
(data,err) = cmd.communicate()
|
||||
for l in data.splitlines():
|
||||
if "wpa_supplicant" not in l:
|
||||
continue
|
||||
if "-i" + ifname not in l:
|
||||
continue
|
||||
return int(l.strip().split(' ')[0])
|
||||
raise Exception("Could not find wpa_supplicant process")
|
||||
|
||||
def read_process_memory(pid, key=None):
|
||||
buf = bytes()
|
||||
with open('/proc/%d/maps' % pid, 'r') as maps, \
|
||||
open('/proc/%d/mem' % pid, 'r') as mem:
|
||||
for l in maps.readlines():
|
||||
m = re.match(r'([0-9a-f]+)-([0-9a-f]+) ([-r][-w][-x][-p])', l)
|
||||
if not m:
|
||||
continue
|
||||
start = int(m.group(1), 16)
|
||||
end = int(m.group(2), 16)
|
||||
perm = m.group(3)
|
||||
if start > 0xffffffffffff:
|
||||
continue
|
||||
if end < start:
|
||||
continue
|
||||
if not perm.startswith('rw'):
|
||||
continue
|
||||
mem.seek(start)
|
||||
data = mem.read(end - start)
|
||||
buf += data
|
||||
if key and key in data:
|
||||
logger.info("Key found in " + l)
|
||||
return buf
|
||||
|
||||
def verify_not_present(buf, key, fname, keyname):
|
||||
pos = buf.find(key)
|
||||
if pos < 0:
|
||||
return
|
||||
|
||||
prefix = 2048 if pos > 2048 else pos
|
||||
with open(fname + keyname, 'w') as f:
|
||||
f.write(buf[pos - prefix:pos + 2048])
|
||||
raise Exception(keyname + " found after disassociation")
|
||||
|
||||
def get_key_locations(buf, key, keyname):
|
||||
count = 0
|
||||
pos = 0
|
||||
while True:
|
||||
pos = buf.find(key, pos)
|
||||
if pos < 0:
|
||||
break
|
||||
logger.info("Found %s at %d" % (keyname, pos))
|
||||
count += 1
|
||||
pos += len(key)
|
||||
return count
|
||||
|
||||
def test_wpa2_psk_key_lifetime_in_memory(dev, apdev, params):
|
||||
"""WPA2-PSK and PSK/PTK lifetime in memory"""
|
||||
ssid = "test-wpa2-psk"
|
||||
passphrase = 'qwertyuiop'
|
||||
psk = '602e323e077bc63bd80307ef4745b754b0ae0a925c2638ecd13a794b9527b9e6'
|
||||
pmk = binascii.unhexlify(psk)
|
||||
p = hostapd.wpa2_params(ssid=ssid)
|
||||
p['wpa_psk'] = psk
|
||||
hapd = hostapd.add_ap(apdev[0]['ifname'], p)
|
||||
|
||||
pid = find_wpas_process(dev[0])
|
||||
|
||||
id = dev[0].connect(ssid, raw_psk=psk, scan_freq="2412",
|
||||
only_add_network=True)
|
||||
|
||||
logger.info("Checking keys in memory after network profile configuration")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
|
||||
id = dev[0].connect(ssid, psk=passphrase, scan_freq="2412",
|
||||
only_add_network=True)
|
||||
|
||||
logger.info("Checking keys in memory before connection")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
|
||||
dev[0].connect_network(id, timeout=20)
|
||||
time.sleep(0.1)
|
||||
|
||||
buf = read_process_memory(pid, pmk)
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected()
|
||||
|
||||
dev[0].relog()
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "WPA: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: Group Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not pmk or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
if len(gtk) != 16:
|
||||
raise Exception("Unexpected GTK length")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
logger.info("Checking keys in memory while associated")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
if pmk not in buf:
|
||||
print("PMK not found while associated")
|
||||
return "skip"
|
||||
if kck not in buf:
|
||||
raise Exception("KCK not found while associated")
|
||||
if kek not in buf:
|
||||
raise Exception("KEK not found while associated")
|
||||
if tk in buf:
|
||||
raise Exception("TK found from memory")
|
||||
if gtk in buf:
|
||||
raise Exception("GTK found from memory")
|
||||
|
||||
logger.info("Checking keys in memory after disassociation")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
|
||||
# Note: PMK/PSK is still present in network configuration
|
||||
|
||||
fname = os.path.join(params['logdir'],
|
||||
'wpa2_psk_key_lifetime_in_memory.memctx-')
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, pmk)
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
@ -4,11 +4,15 @@
|
||||
# This software may be distributed under the terms of the BSD license.
|
||||
# See README for more details.
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
logger = logging.getLogger()
|
||||
import os
|
||||
import time
|
||||
|
||||
import hostapd
|
||||
from test_ap_eap import int_eap_server_params
|
||||
from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
|
||||
|
||||
def test_erp_initiate_reauth_start(dev, apdev):
|
||||
"""Authenticator sending EAP-Initiate/Re-auth-Start, but ERP disabled on peer"""
|
||||
@ -215,3 +219,173 @@ def test_erp_radius_eap_methods(dev, apdev):
|
||||
private_key="auth_serv/user.key")
|
||||
erp_test(dev[0], hapd, eap="TTLS", identity="erp-ttls@example.com",
|
||||
password="password", ca_cert="auth_serv/ca.pem", phase2="auth=PAP")
|
||||
|
||||
def test_erp_key_lifetime_in_memory(dev, apdev, params):
|
||||
"""ERP and key lifetime in memory"""
|
||||
capab = dev[0].get_capability("erp")
|
||||
if not capab or 'ERP' not in capab:
|
||||
return "skip"
|
||||
p = int_eap_server_params()
|
||||
p['erp_send_reauth_start'] = '1'
|
||||
p['erp_domain'] = 'example.com'
|
||||
p['eap_server_erp'] = '1'
|
||||
p['disable_pmksa_caching'] = '1'
|
||||
hapd = hostapd.add_ap(apdev[0]['ifname'], p)
|
||||
password = "63d2d21ac3c09ed567ee004a34490f1d16e7fa5835edf17ddba70a63f1a90a25"
|
||||
|
||||
pid = find_wpas_process(dev[0])
|
||||
|
||||
dev[0].request("ERP_FLUSH")
|
||||
dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
|
||||
identity="pap-secret@example.com", password=password,
|
||||
ca_cert="auth_serv/ca.pem", phase2="auth=PAP",
|
||||
erp="1", scan_freq="2412")
|
||||
|
||||
time.sleep(0.1)
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected(timeout=15)
|
||||
|
||||
dev[0].relog()
|
||||
rRK = None
|
||||
rIK = None
|
||||
pmk = None
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "EAP: ERP rRK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
rRK = binascii.unhexlify(val)
|
||||
if "EAP: ERP rIK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
rIK = binascii.unhexlify(val)
|
||||
if "WPA: PMK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmk = binascii.unhexlify(val)
|
||||
if "WPA: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: Group Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not rIK or not rRK or not pmk or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
if len(gtk) != 16:
|
||||
raise Exception("Unexpected GTK length")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
fname = os.path.join(params['logdir'],
|
||||
'erp_key_lifetime_in_memory.memctx-')
|
||||
|
||||
logger.info("Checking keys in memory while associated")
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, rRK, "rRK")
|
||||
get_key_locations(buf, rIK, "rIK")
|
||||
if password not in buf:
|
||||
print("Password not found while associated")
|
||||
return "skip"
|
||||
if pmk not in buf:
|
||||
print("PMK not found while associated")
|
||||
return "skip"
|
||||
if kck not in buf:
|
||||
raise Exception("KCK not found while associated")
|
||||
if kek not in buf:
|
||||
raise Exception("KEK not found while associated")
|
||||
if tk in buf:
|
||||
raise Exception("TK found from memory")
|
||||
if gtk in buf:
|
||||
raise Exception("GTK found from memory")
|
||||
|
||||
logger.info("Checking keys in memory after disassociation")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
# Note: Password is still present in network configuration
|
||||
# Note: PMK is in EAP fast re-auth data
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, rRK, "rRK")
|
||||
get_key_locations(buf, rIK, "rIK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("RECONNECT")
|
||||
ev = dev[0].wait_event(["CTRL-EVENT-EAP-SUCCESS"], timeout=15)
|
||||
if ev is None:
|
||||
raise Exception("EAP success timed out")
|
||||
if "EAP re-authentication completed successfully" not in ev:
|
||||
raise Exception("Did not use ERP")
|
||||
dev[0].wait_connected(timeout=15, error="Reconnection timed out")
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected(timeout=15)
|
||||
|
||||
dev[0].relog()
|
||||
pmk = None
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "WPA: PMK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmk = binascii.unhexlify(val)
|
||||
if "WPA: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: GTK in EAPOL-Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not pmk or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
logger.info("Checking keys in memory after ERP and disassociation")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
# Note: Password is still present in network configuration
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, rRK, "rRK")
|
||||
get_key_locations(buf, rIK, "rIK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
# Note: rRK and rIK are still in memory
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
get_key_locations(buf, rRK, "rRK")
|
||||
get_key_locations(buf, rIK, "rIK")
|
||||
verify_not_present(buf, password, fname, "password")
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
|
||||
dev[0].request("ERP_FLUSH")
|
||||
logger.info("Checking keys in memory after ERP_FLUSH")
|
||||
buf = read_process_memory(pid, password)
|
||||
get_key_locations(buf, rRK, "rRK")
|
||||
get_key_locations(buf, rIK, "rIK")
|
||||
verify_not_present(buf, rRK, fname, "rRK")
|
||||
verify_not_present(buf, rIK, fname, "rIK")
|
||||
|
@ -1,9 +1,11 @@
|
||||
# Test cases for SAE
|
||||
# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
|
||||
# Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
|
||||
#
|
||||
# This software may be distributed under the terms of the BSD license.
|
||||
# See README for more details.
|
||||
|
||||
import binascii
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import logging
|
||||
@ -11,6 +13,7 @@ logger = logging.getLogger()
|
||||
|
||||
import hwsim_utils
|
||||
import hostapd
|
||||
from test_ap_psk import find_wpas_process, read_process_memory, verify_not_present, get_key_locations
|
||||
|
||||
def test_sae(dev, apdev):
|
||||
"""SAE with default group"""
|
||||
@ -161,3 +164,123 @@ def test_sae_missing_password(dev, apdev):
|
||||
ev = dev[0].wait_event(['CTRL-EVENT-SSID-TEMP-DISABLED'], timeout=10)
|
||||
if ev is None:
|
||||
raise Exception("Invalid network not temporarily disabled")
|
||||
|
||||
|
||||
def test_sae_key_lifetime_in_memory(dev, apdev, params):
|
||||
"""SAE and key lifetime in memory"""
|
||||
password = "5ad144a7c1f5a5503baa6fa01dabc15b1843e8c01662d78d16b70b5cd23cf8b"
|
||||
p = hostapd.wpa2_params(ssid="test-sae", passphrase=password)
|
||||
p['wpa_key_mgmt'] = 'SAE'
|
||||
hapd = hostapd.add_ap(apdev[0]['ifname'], p)
|
||||
|
||||
pid = find_wpas_process(dev[0])
|
||||
|
||||
dev[0].request("SET sae_groups ")
|
||||
id = dev[0].connect("test-sae", psk=password, key_mgmt="SAE",
|
||||
scan_freq="2412")
|
||||
|
||||
time.sleep(0.1)
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
dev[0].request("DISCONNECT")
|
||||
dev[0].wait_disconnected()
|
||||
|
||||
dev[0].relog()
|
||||
sae_k = None
|
||||
sae_keyseed = None
|
||||
sae_kck = None
|
||||
pmk = None
|
||||
ptk = None
|
||||
gtk = None
|
||||
with open(os.path.join(params['logdir'], 'log0'), 'r') as f:
|
||||
for l in f.readlines():
|
||||
if "SAE: k - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
sae_k = binascii.unhexlify(val)
|
||||
if "SAE: keyseed - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
sae_keyseed = binascii.unhexlify(val)
|
||||
if "SAE: KCK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
sae_kck = binascii.unhexlify(val)
|
||||
if "SAE: PMK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
pmk = binascii.unhexlify(val)
|
||||
if "WPA: PTK - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
ptk = binascii.unhexlify(val)
|
||||
if "WPA: Group Key - hexdump" in l:
|
||||
val = l.strip().split(':')[3].replace(' ', '')
|
||||
gtk = binascii.unhexlify(val)
|
||||
if not sae_k or not sae_keyseed or not sae_kck or not pmk or not ptk or not gtk:
|
||||
raise Exception("Could not find keys from debug log")
|
||||
if len(gtk) != 16:
|
||||
raise Exception("Unexpected GTK length")
|
||||
|
||||
kck = ptk[0:16]
|
||||
kek = ptk[16:32]
|
||||
tk = ptk[32:48]
|
||||
|
||||
fname = os.path.join(params['logdir'],
|
||||
'sae_key_lifetime_in_memory.memctx-')
|
||||
|
||||
logger.info("Checking keys in memory while associated")
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
if password not in buf:
|
||||
print("Password not found while associated")
|
||||
return "skip"
|
||||
if pmk not in buf:
|
||||
print("PMK not found while associated")
|
||||
return "skip"
|
||||
if kck not in buf:
|
||||
raise Exception("KCK not found while associated")
|
||||
if kek not in buf:
|
||||
raise Exception("KEK not found while associated")
|
||||
if tk in buf:
|
||||
raise Exception("TK found from memory")
|
||||
if gtk in buf:
|
||||
raise Exception("GTK found from memory")
|
||||
verify_not_present(buf, sae_k, fname, "SAE(k)")
|
||||
verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
|
||||
verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
|
||||
|
||||
logger.info("Checking keys in memory after disassociation")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
# Note: Password is still present in network configuration
|
||||
# Note: PMK is in PMKSA cache
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
verify_not_present(buf, sae_k, fname, "SAE(k)")
|
||||
verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
|
||||
verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
|
||||
|
||||
dev[0].request("PMKSA_FLUSH")
|
||||
logger.info("Checking keys in memory after PMKSA cache flush")
|
||||
buf = read_process_memory(pid, password)
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
|
||||
dev[0].request("REMOVE_NETWORK all")
|
||||
|
||||
logger.info("Checking keys in memory after network profile removal")
|
||||
buf = read_process_memory(pid, password)
|
||||
|
||||
get_key_locations(buf, password, "Password")
|
||||
get_key_locations(buf, pmk, "PMK")
|
||||
verify_not_present(buf, password, fname, "password")
|
||||
verify_not_present(buf, pmk, fname, "PMK")
|
||||
verify_not_present(buf, kck, fname, "KCK")
|
||||
verify_not_present(buf, kek, fname, "KEK")
|
||||
verify_not_present(buf, tk, fname, "TK")
|
||||
verify_not_present(buf, gtk, fname, "GTK")
|
||||
verify_not_present(buf, sae_k, fname, "SAE(k)")
|
||||
verify_not_present(buf, sae_keyseed, fname, "SAE(keyseed)")
|
||||
verify_not_present(buf, sae_kck, fname, "SAE(KCK)")
|
||||
|
Loading…
Reference in New Issue
Block a user