From 9dd2ea536860903889185adbbf3e484d1bab5515 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 30 Apr 2022 16:28:33 +0300 Subject: [PATCH] tests: IMSI privacy with imsi_identity Add RSA public key (in an X.509v3 certificate) and private key for IMSI privacy. These were generated with openssl req -new -x509 -sha256 -newkey rsa:2048 -nodes -days 7500 \ -keyout imsi-privacy-key.pem -out imsi-privacy-cert.pem Test the case where wpa_supplicant side RSA-OAEP operation for IMSI privacy is done in an external component while the hostapd (EAP server) processing of the encrypted identity is internal. Signed-off-by: Jouni Malinen --- tests/hwsim/auth_serv/as.conf | 1 + tests/hwsim/auth_serv/imsi-privacy-cert.pem | 20 +++ tests/hwsim/auth_serv/imsi-privacy-key.pem | 28 +++++ tests/hwsim/test_ap_eap.py | 130 +++++++++++++++++++- tests/hwsim/wpasupplicant.py | 7 +- 5 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 tests/hwsim/auth_serv/imsi-privacy-cert.pem create mode 100644 tests/hwsim/auth_serv/imsi-privacy-key.pem diff --git a/tests/hwsim/auth_serv/as.conf b/tests/hwsim/auth_serv/as.conf index 3c0eda22f..805ad077e 100644 --- a/tests/hwsim/auth_serv/as.conf +++ b/tests/hwsim/auth_serv/as.conf @@ -20,6 +20,7 @@ pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f eap_fast_a_id=101112131415161718191a1b1c1d1e1f eap_fast_a_id_info=test server eap_sim_aka_result_ind=1 +imsi_privacy_key=auth_serv/imsi-privacy-key.pem tls_flags=[ENABLE-TLSv1.3] dump_msk_file=LOGDIR/as-msk.lst diff --git a/tests/hwsim/auth_serv/imsi-privacy-cert.pem b/tests/hwsim/auth_serv/imsi-privacy-cert.pem new file mode 100644 index 000000000..57edd2f5d --- /dev/null +++ b/tests/hwsim/auth_serv/imsi-privacy-cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIUegWQhMTybRQSmWSWMIrT+RqTrawwDQYJKoZIhvcNAQEL +BQAwOTELMAkGA1UEBhMCRkkxETAPBgNVBAcMCEhlbHNpbmtpMRcwFQYDVQQDDA5o +b3N0YXAgdGVzdGluZzAeFw0yMjA0MzAxMzAxMDFaFw00MjExMTExMzAxMDFaMDkx +CzAJBgNVBAYTAkZJMREwDwYDVQQHDAhIZWxzaW5raTEXMBUGA1UEAwwOaG9zdGFw +IHRlc3RpbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCHnFl+bVA +9WiPdu+falDLhM3+wA6n5gtbPX90yVhl6yX5UAhwzeFgV1uVRqMv3LMbapGGkJYn +wUv1qjuloD8Qe+l6zmxhGaI0unjaRrosiWZf5XdSKc8O3YoYkZlPhlUreG6/0elD +Rnka9yBncxK/u3Qt2w+hDRc8sYLYkvfhGCoArFgt30kPg1+xdOBX97C0lOUJqgR6 +mKl/D3pYBtDMEqJl7ZXWcKt23QVv/O3luEPTlY8uSuz2SNGoBKKX8ekTTdF9Vdhb +v3iber9ImLB0ZOb154u40pmxMitSpEoHqJGBsWfCiG/ghRd43njJm0e3mmsTDfUT +6y45oNIbtJFrAgMBAAGjUzBRMB0GA1UdDgQWBBTEttO3uwTr6dfAp9DbW1SiSOVV +EjAfBgNVHSMEGDAWgBTEttO3uwTr6dfAp9DbW1SiSOVVEjAPBgNVHRMBAf8EBTAD +AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQB0uouWgGQgM5O8QJNBKK2+qypiTJgqSVpK +TbuOD9MCIC8ZPF1kTvRmMDn0Sa5vgaNoyD6dckj+MPUpMQ6srhRpgMWB4x7dUFB8 +CkGIHI+XsdZ1ihlPWH5vuKOFtJjCKZESqpCwzWHU/HwTUriSIPJXJTfvrHaBoi2m +xjI7sd2sXCe2xYN9gWBP6wz+X1/qiLZvM5fzdJKWlBpo6qLL+C1tAB48PHwpFRU2 +vWi+SMg38buYFyOn+x9yiAtB0SIKXnrTPRbFTUT8LuZVmG4FBCBS8+6qbg7qhR8U +VWzcib4UAjOI9fu8Yh/2cG8wRvUEv7kHPUup8XtL6IsMQ74bOn5l +-----END CERTIFICATE----- diff --git a/tests/hwsim/auth_serv/imsi-privacy-key.pem b/tests/hwsim/auth_serv/imsi-privacy-key.pem new file mode 100644 index 000000000..2e7350a73 --- /dev/null +++ b/tests/hwsim/auth_serv/imsi-privacy-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDCHnFl+bVA9WiP +du+falDLhM3+wA6n5gtbPX90yVhl6yX5UAhwzeFgV1uVRqMv3LMbapGGkJYnwUv1 +qjuloD8Qe+l6zmxhGaI0unjaRrosiWZf5XdSKc8O3YoYkZlPhlUreG6/0elDRnka +9yBncxK/u3Qt2w+hDRc8sYLYkvfhGCoArFgt30kPg1+xdOBX97C0lOUJqgR6mKl/ +D3pYBtDMEqJl7ZXWcKt23QVv/O3luEPTlY8uSuz2SNGoBKKX8ekTTdF9Vdhbv3ib +er9ImLB0ZOb154u40pmxMitSpEoHqJGBsWfCiG/ghRd43njJm0e3mmsTDfUT6y45 +oNIbtJFrAgMBAAECggEAZiNEgWaBEzvNF2d6L4PuHRe0l60QSRGGuixCiv2CEKZI +pcSRnGEHi/yLCKFRLdbPOsa46XfcOfC/+fPnTH9jj1XThLVmWzT0nw/alOcQAG0P +O7fuL4ImG2k/xyuc4jYJTEUi6LUXKjnDcQfEugnXPKDyQUp5D8Fmj53K/g9ec8Wp +WahjALrsFYDexHYnitle41uERSrdQysFoOLgiRoVFmCcEO7leEqb4M4rVLfPd/j4 +pJB9sWKRh7P70FoY24Ro2XOuUcebVa8XXr1e2hI69T2WY2wrXGn47w3hp8zIMkyv +EXHHg+/qPA1hh59NuSZfFIg9P7CCZbTAiba1JqgTqQKBgQD/X29hpKlW504ZPO24 +OVq6qe+JesNIcpeaCHeJiVmkrIXpbxb+BwLgV/L+xzWrst/pG03e00Z/A/Yb66/8 +DFGDxyMg1UNYL2t714vON8IwFJj37apqGraDUgW+QjFznL09mRN68JihzMPbHFxi +AirYLKb2iy/LFgcYFIEs/onThQKBgQDCmH6jRolsE9CavoXlBZwjlQSUePhPq8vt +wHVCoHcYTEJLTRFUCwcaqGmqOXwiX665RlJJ0wYC68GqFcKcztz+of23rRlM14Gd +Uwgp8d1UzpZqz8Sig+phqGecpY4qRyiy5anNvtqfiWPgFOfJfg2CiLEWM9w340Zm +aMa26fKMLwKBgQCP4PkkDl3KNK/v0EAvF0FjAfOPhbcYzldT1Ylj2BrFiN450vkl +TlX0iBjEKwC2KCW3dEa/UFHbpiO3P2b7nwUeNcg4627x9GWedKa0HP4vkKtOpHzr +IvnJqyDJPQoXlSuZ1PEAxyV3o6KFhMkX/xiciyvWpDzdMx/0FTliXFbS8QKBgQC7 +weuemraJo2zJgj8qxQjshCIRJ89fAAIZ+nKpwK5osVvd0BSCJMnL/OdHKYQOnoe1 +mJZZSNUqCFOqSqimKCqvPZnSmaAptl4HcFAWOJo388TKdoHh1KpXY+flCxBq1pH8 +WwBF1nqXKDdHxKQIlClw43cKVyuKeS46LapeXsh6XQKBgQDnr0rZo0iDoFM5QLua +78KMi6G+dJ8DvIELyhCljy6Bvs9tmaILdixlOtIxoDAfyws/ls9BxFTCgWOIud4v +UI4WCCIrc50cYnuTeWn/iIhNCSooD+S7m9iVbMhmLvXhxp0vpFghmQ5Bqf7Xi0Tr +iOMcKRNNgdYou4FwQ17P8FnqkQ== +-----END PRIVATE KEY----- diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py index 757cb5399..afdeb5541 100644 --- a/tests/hwsim/test_ap_eap.py +++ b/tests/hwsim/test_ap_eap.py @@ -149,12 +149,12 @@ def read_pem(fname, decode=True): return base64.b64decode(cert) return cert.encode() -def eap_connect(dev, hapd, method, identity, +def eap_connect(dev, hapd, method, identity, raw_identity=None, sha256=False, expect_failure=False, local_error_report=False, maybe_local_error=False, report_failure=False, expect_cert_error=None, **kwargs): id = dev.connect("test-wpa2-eap", key_mgmt="WPA-EAP WPA-EAP-SHA256", - eap=method, identity=identity, + eap=method, identity=identity, raw_identity=raw_identity, wait_connect=False, scan_freq="2412", ieee80211w="1", **kwargs) eap_check_auth(dev, method, True, sha256=sha256, @@ -303,6 +303,48 @@ def test_ap_wpa2_eap_sim(dev, apdev): eap_connect(dev[0], hapd, "SIM", "1232010000000000", expect_failure=True) +def test_ap_wpa2_eap_sim_imsi_identity(dev, apdev, params): + """WPA2-Enterprise connection using EAP-SIM and imsi_identity""" + check_hlr_auc_gw_support() + prefix = params['prefix'] + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hapd = hostapd.add_ap(apdev[0], params) + tls = hapd.request("GET tls_library") + if not tls.startswith("OpenSSL"): + raise HwsimSkip("IMSI privacy not supported with this TLS library: " + tls) + + imsi = "232010000000000" + realm = "wlan.mnc232.mcc02.3gppnetwork.org" + method_id = '1' + permanent_id = method_id + imsi + '@' + realm + # RSA-OAEP(permanent_id) + perm_id = prefix + '.permanent-id' + enc_id = prefix + '.enc-permanent-id' + with open(perm_id, 'w') as f: + f.write(permanent_id) + pubkey = prefix + ".cert-pub.pem" + subprocess.check_call(["openssl", "x509", + "-in", "auth_serv/imsi-privacy-cert.pem", + "-pubkey", "-noout", + "-out", pubkey]) + subprocess.check_call(["openssl", "pkeyutl", + "-inkey", pubkey, "-pubin", "-in", perm_id, + "-pkeyopt", "rsa_padding_mode:oaep", + "-pkeyopt", "rsa_oaep_md:sha256", + "-encrypt", + "-out", enc_id]) + with open(enc_id, 'rb') as f: + data = f.read() + encrypted_id = base64.b64encode(data).decode() + if len(encrypted_id) != 344: + raise Exception("Unexpected length of the base64 encoded identity: " + b64) + eap_connect(dev[0], hapd, "SIM", identity=None, + raw_identity='P"\\0' + encrypted_id + '"', + anonymous_identity=method_id + "anonymous@" + realm, + imsi_identity=permanent_id, + password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581") + eap_reauth(dev[0], "SIM") + def test_ap_wpa2_eap_sim_sql(dev, apdev, params): """WPA2-Enterprise connection using EAP-SIM (SQL)""" check_hlr_auc_gw_support() @@ -1028,6 +1070,48 @@ def test_ap_wpa2_eap_aka(dev, apdev): eap_connect(dev[0], hapd, "AKA", "0232010000000000", expect_failure=True) +def test_ap_wpa2_eap_aka_imsi_identity(dev, apdev, params): + """WPA2-Enterprise connection using EAP-AKA and imsi_identity""" + check_hlr_auc_gw_support() + prefix = params['prefix'] + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hapd = hostapd.add_ap(apdev[0], params) + tls = hapd.request("GET tls_library") + if not tls.startswith("OpenSSL"): + raise HwsimSkip("IMSI privacy not supported with this TLS library: " + tls) + + imsi = "232010000000000" + realm = "wlan.mnc232.mcc02.3gppnetwork.org" + method_id = '0' + permanent_id = method_id + imsi + '@' + realm + # RSA-OAEP(permanent_id) + perm_id = prefix + '.permanent-id' + enc_id = prefix + '.enc-permanent-id' + with open(perm_id, 'w') as f: + f.write(permanent_id) + pubkey = prefix + ".cert-pub.pem" + subprocess.check_call(["openssl", "x509", + "-in", "auth_serv/imsi-privacy-cert.pem", + "-pubkey", "-noout", + "-out", pubkey]) + subprocess.check_call(["openssl", "pkeyutl", + "-inkey", pubkey, "-pubin", "-in", perm_id, + "-pkeyopt", "rsa_padding_mode:oaep", + "-pkeyopt", "rsa_oaep_md:sha256", + "-encrypt", + "-out", enc_id]) + with open(enc_id, 'rb') as f: + data = f.read() + encrypted_id = base64.b64encode(data).decode() + if len(encrypted_id) != 344: + raise Exception("Unexpected length of the base64 encoded identity: " + b64) + eap_connect(dev[0], hapd, "AKA", identity=None, + raw_identity='P"\\0' + encrypted_id + '"', + anonymous_identity=method_id + "anonymous@" + realm, + imsi_identity=permanent_id, + password="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123") + eap_reauth(dev[0], "AKA") + def test_ap_wpa2_eap_aka_sql(dev, apdev, params): """WPA2-Enterprise connection using EAP-AKA (SQL)""" check_hlr_auc_gw_support() @@ -1241,6 +1325,48 @@ def test_ap_wpa2_eap_aka_prime(dev, apdev): password="ff22250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123", expect_failure=True) +def test_ap_wpa2_eap_aka_prime_imsi_identity(dev, apdev, params): + """WPA2-Enterprise connection using EAP-AKA' and imsi_identity""" + check_hlr_auc_gw_support() + prefix = params['prefix'] + params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap") + hapd = hostapd.add_ap(apdev[0], params) + tls = hapd.request("GET tls_library") + if not tls.startswith("OpenSSL"): + raise HwsimSkip("IMSI privacy not supported with this TLS library: " + tls) + + imsi = "555444333222111" + realm = "wlan.mnc555.mcc44.3gppnetwork.org" + method_id = '6' + permanent_id = method_id + imsi + '@' + realm + # RSA-OAEP(permanent_id) + perm_id = prefix + '.permanent-id' + enc_id = prefix + '.enc-permanent-id' + with open(perm_id, 'w') as f: + f.write(permanent_id) + pubkey = prefix + ".cert-pub.pem" + subprocess.check_call(["openssl", "x509", + "-in", "auth_serv/imsi-privacy-cert.pem", + "-pubkey", "-noout", + "-out", pubkey]) + subprocess.check_call(["openssl", "pkeyutl", + "-inkey", pubkey, "-pubin", "-in", perm_id, + "-pkeyopt", "rsa_padding_mode:oaep", + "-pkeyopt", "rsa_oaep_md:sha256", + "-encrypt", + "-out", enc_id]) + with open(enc_id, 'rb') as f: + data = f.read() + encrypted_id = base64.b64encode(data).decode() + if len(encrypted_id) != 344: + raise Exception("Unexpected length of the base64 encoded identity: " + b64) + eap_connect(dev[0], hapd, "AKA'", identity=None, + raw_identity='P"\\0' + encrypted_id + '"', + anonymous_identity=method_id + "anonymous@" + realm, + imsi_identity=permanent_id, + password="5122250214c33e723a5dd523fc145fc0:981d464c7c52eb6e5036234984ad0bcf:000000000123") + eap_reauth(dev[0], "AKA'") + def test_ap_wpa2_eap_aka_prime_sql(dev, apdev, params): """WPA2-Enterprise connection using EAP-AKA' (SQL)""" check_hlr_auc_gw_support() diff --git a/tests/hwsim/wpasupplicant.py b/tests/hwsim/wpasupplicant.py index e663e9f11..08bf1f649 100644 --- a/tests/hwsim/wpasupplicant.py +++ b/tests/hwsim/wpasupplicant.py @@ -1082,7 +1082,8 @@ class WpaSupplicant: "domain_match", "dpp_connector", "sae_password", "sae_password_id", "check_cert_subject", "machine_ca_cert", "machine_client_cert", - "machine_private_key", "machine_phase2"] + "machine_private_key", "machine_phase2", + "imsi_identity"] for field in quoted: if field in kwargs and kwargs[field]: self.set_network_quoted(id, field, kwargs[field]) @@ -1113,7 +1114,7 @@ class WpaSupplicant: self.set_network(id, field, kwargs[field]) known_args = {"raw_psk", "password_hex", "peerkey", "okc", "ocsp", - "only_add_network", "wait_connect"} + "only_add_network", "wait_connect", "raw_identity"} unknown = set(kwargs.keys()) unknown -= set(quoted) unknown -= set(not_quoted) @@ -1121,6 +1122,8 @@ class WpaSupplicant: if unknown: raise Exception("Unknown WpaSupplicant::connect() arguments: " + str(unknown)) + if "raw_identity" in kwargs and kwargs['raw_identity']: + self.set_network(id, "identity", kwargs['raw_identity']) if "raw_psk" in kwargs and kwargs['raw_psk']: self.set_network(id, "psk", kwargs['raw_psk']) if "password_hex" in kwargs and kwargs['password_hex']: