EAP-SIM/AKA: Separate identity for MK derivation

This allows a separate configuration parameter (imsi_identity) to be
used in EAP-SIM/AKA/AKA' profiles to override the identity used in MK
derivation for the case where the identity is expected to be from the
last AT_IDENTITY attribute (or EAP-Response/Identity if AT_IDENTITY was
not used). This may be needed to avoid sending out an unprotected
permanent identity information over-the-air and if the EAP-SIM/AKA
server ends up using a value based on the real IMSI during the internal
key derivation operation (that does not expose the data to others).

Bug: 30988281
Change-Id: I41df97009fbd4dbeb968b3ec31d0c1b45d8f2c70
Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index f7e3cd6..7a6bfc9 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -1025,8 +1025,17 @@
 	} else if (data->pseudonym) {
 		identity = data->pseudonym;
 		identity_len = data->pseudonym_len;
-	} else
-		identity = eap_get_config_identity(sm, &identity_len);
+	} else {
+		struct eap_peer_config *config;
+
+		config = eap_get_config(sm);
+		if (config && config->imsi_identity) {
+			identity = config->imsi_identity;
+			identity_len = config->imsi_identity_len;
+		} else {
+			identity = eap_get_config_identity(sm, &identity_len);
+		}
+	}
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
 			  "derivation", identity, identity_len);
 	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 16521c3..d416afd 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -46,6 +46,9 @@
 	 */
 	size_t anonymous_identity_len;
 
+	u8 *imsi_identity;
+	size_t imsi_identity_len;
+
 	/**
 	 * password - Password string for EAP
 	 *
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 25f592c..cd687cb 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -767,8 +767,17 @@
 	} else if (data->pseudonym) {
 		identity = data->pseudonym;
 		identity_len = data->pseudonym_len;
-	} else
-		identity = eap_get_config_identity(sm, &identity_len);
+	} else {
+		struct eap_peer_config *config;
+
+		config = eap_get_config(sm);
+		if (config && config->imsi_identity) {
+			identity = config->imsi_identity;
+			identity_len = config->imsi_identity_len;
+		} else {
+			identity = eap_get_config_identity(sm, &identity_len);
+		}
+	}
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
 			  "derivation", identity, identity_len);
 	eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index a0d480e..a22434c 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2154,6 +2154,7 @@
 	{ FUNC(eap) },
 	{ STR_LENe(identity) },
 	{ STR_LENe(anonymous_identity) },
+	{ STR_LENe(imsi_identity) },
 	{ FUNC_KEY(password) },
 	{ STRe(ca_cert) },
 	{ STRe(ca_path) },
@@ -2411,6 +2412,7 @@
 	os_free(eap->eap_methods);
 	bin_clear_free(eap->identity, eap->identity_len);
 	os_free(eap->anonymous_identity);
+	os_free(eap->imsi_identity);
 	bin_clear_free(eap->password, eap->password_len);
 	os_free(eap->ca_cert);
 	os_free(eap->ca_path);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 6b7abe2..058b366 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -760,6 +760,7 @@
 	write_eap(f, ssid);
 	STR(identity);
 	STR(anonymous_identity);
+	STR(imsi_identity);
 	STR(password);
 	STR(ca_cert);
 	STR(ca_path);
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index 24f496b..0ba1aa5 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -880,6 +880,7 @@
 	write_eap(netw, ssid);
 	STR(identity);
 	STR(anonymous_identity);
+	STR(imsi_identity);
 	STR(password);
 	STR(ca_cert);
 	STR(ca_path);