Support strict conservative peer mode for EAP-SIM/AKA/AKA'

Bug: 239710602
Test: atest VtsHalWifiSupplicantStaNetworkTargetTest
Change-Id: I23cd42ba749c5c2f9d7651a88e813f3def2488bc
diff --git a/wpa_supplicant/aidl/sta_network.cpp b/wpa_supplicant/aidl/sta_network.cpp
index f9f980c..0d5d4e6 100644
--- a/wpa_supplicant/aidl/sta_network.cpp
+++ b/wpa_supplicant/aidl/sta_network.cpp
@@ -304,6 +304,15 @@
 		in_identity);
 }
 
+::ndk::ScopedAStatus StaNetwork::setStrictConservativePeerMode(
+	bool in_enable)
+{
+	return validateAndCall(
+		this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
+		&StaNetwork::setStrictConservativePeerModeInternal,
+		in_enable);
+}
+
 ::ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentity(
 	const std::vector<uint8_t>& in_identity)
 {
@@ -1246,6 +1255,13 @@
 	return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus StaNetwork::setStrictConservativePeerModeInternal(bool enable)
+{
+	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
+	wpa_ssid->eap.strict_conservative_peer_mode = enable ? 1 : 0;
+	return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus StaNetwork::setEapAnonymousIdentityInternal(
 	const std::vector<uint8_t> &identity)
 {
diff --git a/wpa_supplicant/aidl/sta_network.h b/wpa_supplicant/aidl/sta_network.h
index 6661130..f794844 100644
--- a/wpa_supplicant/aidl/sta_network.h
+++ b/wpa_supplicant/aidl/sta_network.h
@@ -85,6 +85,8 @@
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapEncryptedImsiIdentity(
 		const std::vector<uint8_t>& in_identity) override;
+	::ndk::ScopedAStatus setStrictConservativePeerMode(
+		bool in_enable) override;
 	::ndk::ScopedAStatus setEapAnonymousIdentity(
 		const std::vector<uint8_t>& in_identity) override;
 	::ndk::ScopedAStatus setEapPassword(
@@ -212,6 +214,8 @@
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapEncryptedImsiIdentityInternal(
 		const std::vector<uint8_t>& identity);
+	ndk::ScopedAStatus setStrictConservativePeerModeInternal(
+		bool enable);
 	ndk::ScopedAStatus setEapAnonymousIdentityInternal(
 		const std::vector<uint8_t>& identity);
 	ndk::ScopedAStatus setEapPasswordInternal(
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 065b6fb..2b1bdeb 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2529,6 +2529,7 @@
 	{ INTe(sim_num, sim_num) },
 	{ STRe(imsi_privacy_cert, imsi_privacy_cert) },
 	{ STRe(imsi_privacy_attr, imsi_privacy_attr) },
+	{ INTe(strict_conservative_peer_mode, strict_conservative_peer_mode) },
 	{ STRe(openssl_ciphers, openssl_ciphers) },
 	{ INTe(erp, erp) },
 #endif /* IEEE8021X_EAPOL */
@@ -3953,6 +3954,11 @@
 		return 0;
 	}
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0) {
+		cred->strict_conservative_peer_mode = atoi(val);
+		return 0;
+	}
+
 	if (line) {
 		wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
 			   line, var);
@@ -4109,6 +4115,9 @@
 	if (os_strcmp(var, "imsi_privacy_attr") == 0)
 		return alloc_strdup(cred->imsi_privacy_attr);
 
+	if (os_strcmp(var, "strict_conservative_peer_mode") == 0)
+		return alloc_int_str(cred->strict_conservative_peer_mode);
+
 	if (os_strcmp(var, "milenage") == 0) {
 		if (!(cred->milenage))
 			return NULL;
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index a81e9eb..0316e9b 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -202,6 +202,18 @@
 	char *imsi_privacy_attr;
 
 	/**
+	 * strict_conservative_peer_mode - Whether the strict conservative peer
+	 * mode is enabled or not
+	 *
+	 * This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+	 * for EAP-SIM/AKA/AKA', in convervative peer mode, a client error would
+	 * be sent to the server, but it allows to send the permanent identity
+	 * in some special cases according to 4.6.2 of RFC 4187; With the strict
+	 * mode, it never send the permanent identity to server for privacy concern.
+	 */
+	int strict_conservative_peer_mode;
+
+	/**
 	 * engine - Use an engine for private key operations
 	 */
 	int engine;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 260df8f..372a57b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -1044,6 +1044,9 @@
 	if (cred->imsi_privacy_attr)
 		fprintf(f, "\timsi_privacy_attr=\"%s\"\n",
 			cred->imsi_privacy_attr);
+	if (cred->strict_conservative_peer_mode)
+		fprintf(f,"\tstrict_conservative_peer_mode=\"%d\"\n",
+			cred->strict_conservative_peer_mode);
 }
 
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 6198bd7..acd9044 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1077,6 +1077,12 @@
 			goto fail;
 	}
 
+	if (cred->strict_conservative_peer_mode) {
+		if (wpa_config_set_quoted(ssid, "strict_conservative_peer_mode",
+					  "1") < 0)
+			goto fail;
+	}
+
 	wpa_s->next_ssid = ssid;
 	wpa_config_update_prio_list(wpa_s->conf);
 	if (!only_add)
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 8262eef..b6a1a74 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1175,6 +1175,14 @@
 #	unencrypted identity with EAP types that support different tunnelled
 #	identity, e.g., EAP-TTLS). This field can also be used with
 #	EAP-SIM/AKA/AKA' to store the pseudonym identity.
+# strict_conservative_peer_mode: Whether the strict conservative peer mode
+#	is enabled. This field is used to handle the reponse of AT_PERMANENT_ID_REQ
+#	for EAP-SIM/AKA/AKA'. In non-strict convervative peer mode, a client
+#	error would be sent to the server, but the mode will send the permanent
+#	identity in some special cases according to 4.6.2 of RFC 4187; With the
+#	strict mode, the permanent identity is never sent to the server.
+#	0 = disabled (default)
+#	1 = enabled
 # password: Password string for EAP. This field can include either the
 #	plaintext password (using ASCII or hex string) or a NtPasswordHash
 #	(16-byte MD4 hash of password) in hash:<32 hex digits> format.