]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
tests: IMSI privacy with imsi_identity
authorJouni Malinen <quic_jouni@quicinc.com>
Sat, 30 Apr 2022 13:28:33 +0000 (16:28 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 1 May 2022 13:25:16 +0000 (16:25 +0300)
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 <quic_jouni@quicinc.com>
tests/hwsim/auth_serv/as.conf
tests/hwsim/auth_serv/imsi-privacy-cert.pem [new file with mode: 0644]
tests/hwsim/auth_serv/imsi-privacy-key.pem [new file with mode: 0644]
tests/hwsim/test_ap_eap.py
tests/hwsim/wpasupplicant.py

index 3c0eda22f7392c704083a7ecd2f4aa68c161392f..805ad077ec7b95dd69f2abe8b26ceba596344e13 100644 (file)
@@ -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 (file)
index 0000000..57edd2f
--- /dev/null
@@ -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 (file)
index 0000000..2e7350a
--- /dev/null
@@ -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-----
index 757cb5399b4632257e3e8a62470c2101dd4c4fb4..afdeb5541a0e9421f6254d0580579d1ff4be8adf 100644 (file)
@@ -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()
index e663e9f117f1fd1c32fa3cd7548689544dab4caa..08bf1f649764f9f78ac431e1b5260db05019604c 100644 (file)
@@ -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']: