Make server cert validation check public
Make server cert validation check public to allow Apps check before
build suggestions
Cherry pick from ag/13221115
Bug: 175629207
Test: atest android.net.wifi
Change-Id: If523264475e0c210c6054e1b65a9526d9ba08cc2
diff --git a/framework/api/current.txt b/framework/api/current.txt
index f8b95dd..130a124 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -206,6 +206,7 @@
ctor public WifiEnterpriseConfig();
ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
method public int describeContents();
+ method public boolean doesEapMethodUseServerCert();
method public String getAltSubjectMatch();
method public String getAnonymousIdentity();
method @Nullable public java.security.cert.X509Certificate getCaCertificate();
@@ -222,6 +223,7 @@
method public String getRealm();
method @Deprecated public String getSubjectMatch();
method public boolean isAuthenticationSimBased();
+ method public boolean isServerCertValidationEnabled();
method public void setAltSubjectMatch(String);
method public void setAnonymousIdentity(String);
method public void setCaCertificate(@Nullable java.security.cert.X509Certificate);
diff --git a/framework/java/android/net/wifi/WifiEnterpriseConfig.java b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
index e127ea9..2a874d4 100644
--- a/framework/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/framework/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -25,6 +25,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.modules.utils.build.SdkLevel;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
@@ -1436,34 +1438,71 @@
}
/**
- * Method determines whether the Enterprise configuration is insecure. An insecure
- * configuration is one where EAP method requires a CA certification, i.e. PEAP, TLS, or
- * TTLS, and any of the following conditions are met:
- * - Both certificate and CA path are not configured.
- * - Both alternative subject match and domain suffix match are not set.
- *
- * Note: this method does not exhaustively check security of the configuration - i.e. a return
- * value of {@code false} is not a guarantee that the configuration is secure.
+ * Determines whether an Enterprise configuration's EAP method requires a Root CA certification
+ * to validate the authentication server i.e. PEAP, TLS, or TTLS.
+ * @return True if configuration requires a CA certification, false otherwise.
+ */
+ public boolean doesEapMethodUseServerCert() {
+ if (!SdkLevel.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ return isTlsBasedEapMethod();
+ }
+
+ /**
+ * A helper method to check if the EAP method of enterprise config is one of the target types.
+ * @return true if EAP method of enterprise config is one the target types, false otherwise.
* @hide
*/
- public boolean isInsecure() {
- if (mEapMethod != Eap.PEAP && mEapMethod != Eap.TLS && mEapMethod != Eap.TTLS) {
- return false;
+ public boolean isTlsBasedEapMethod() {
+ return mEapMethod == Eap.PEAP || mEapMethod == Eap.TLS || mEapMethod == Eap.TTLS;
+ }
+ /**
+ * Determines whether an Enterprise configuration enables server certificate validation.
+ * <p>
+ * The caller can determine, along with {@link #doesEapMethodUseServerCert()}, if an
+ * Enterprise configuration enables server certificate validation, which is a mandatory
+ * requirement for networks that use TLS based EAP methods. A configuration that does not
+ * enable server certificate validation will be ignored and will not be considered for
+ * network selection. A network suggestion with such a configuration will cause an
+ * IllegalArgumentException to be thrown when suggested.
+ * Server validation is achieved by the following:
+ * - Either certificate or CA path is configured.
+ * - Either alternative subject match or domain suffix match is set.
+ * @return True for server certificate validation is enabled, false otherwise.
+ * @throws IllegalStateException on configuration which doesn't use server certificate.
+ * @see #doesEapMethodUseServerCert()
+ */
+ public boolean isServerCertValidationEnabled() {
+ if (!SdkLevel.isAtLeastS()) {
+ throw new UnsupportedOperationException();
}
+ if (!doesEapMethodUseServerCert()) {
+ throw new IllegalStateException("Configuration doesn't use server certificates for "
+ + "authentication");
+ }
+ return isMandatoryParameterSetForServerCertValidation();
+ }
+
+ /**
+ * Helper method to check if mandatory parameter for server cert validation is set.
+ * @hide
+ */
+ public boolean isMandatoryParameterSetForServerCertValidation() {
if (TextUtils.isEmpty(getAltSubjectMatch())
&& TextUtils.isEmpty(getDomainSuffixMatch())) {
- // Both subject and domain match are not set, it's insecure.
- return true;
+ // Both subject and domain match are not set, validation is not enabled.
+ return false;
}
if (mIsAppInstalledCaCert) {
- // CA certificate is installed by App, it's secure.
- return false;
+ // CA certificate is installed by App, validation is enabled.
+ return true;
}
if (getCaCertificateAliases() != null) {
- // CA certificate alias from keyStore is set, it's secure.
- return false;
+ // CA certificate alias from keyStore is set, validation is enabled.
+ return true;
}
- return TextUtils.isEmpty(getCaPath());
+ return !TextUtils.isEmpty(getCaPath());
}
/**
diff --git a/framework/java/android/net/wifi/WifiNetworkSuggestion.java b/framework/java/android/net/wifi/WifiNetworkSuggestion.java
index 8e124a2..ab0a14f 100644
--- a/framework/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/framework/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -319,14 +319,16 @@
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
- * @throws IllegalArgumentException if configuration CA certificate or
- * AltSubjectMatch/DomainSuffixMatch is not set.
+ * @throws IllegalArgumentException If configuration uses server certificate but validation
+ * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
*/
public @NonNull Builder setWpa2EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
- if (enterpriseConfig.isInsecure()) {
- throw new IllegalArgumentException("Enterprise configuration is insecure");
+ if (enterpriseConfig.isTlsBasedEapMethod()
+ && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
+ throw new IllegalArgumentException("Enterprise configuration mandates server "
+ + "certificate but validation is not enabled.");
}
mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
@@ -346,15 +348,17 @@
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
- * @throws IllegalArgumentException if configuration CA certificate or
- * AltSubjectMatch/DomainSuffixMatch is not set.
+ * @throws IllegalArgumentException If configuration uses server certificate but validation
+ * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
*/
@Deprecated
public @NonNull Builder setWpa3EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
- if (enterpriseConfig.isInsecure()) {
- throw new IllegalArgumentException("Enterprise configuration is insecure");
+ if (enterpriseConfig.isTlsBasedEapMethod()
+ && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
+ throw new IllegalArgumentException("Enterprise configuration mandates server "
+ + "certificate but validation is not enabled.");
}
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
@@ -368,14 +372,16 @@
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link Builder} to enable chaining of the builder method.
- * @throws IllegalArgumentException if configuration CA certificate or
- * AltSubjectMatch/DomainSuffixMatch is not set.
+ * @throws IllegalArgumentException If configuration uses server certificate but validation
+ * is not enabled. See {@link WifiEnterpriseConfig#isServerCertValidationEnabled()}
*/
public @NonNull Builder setWpa3EnterpriseStandardModeConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
- if (enterpriseConfig.isInsecure()) {
- throw new IllegalArgumentException("Enterprise configuration is insecure");
+ if (enterpriseConfig.isTlsBasedEapMethod()
+ && !enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
+ throw new IllegalArgumentException("Enterprise configuration mandates server "
+ + "certificate but validation is not enabled.");
}
mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
mWpa3EnterpriseType = WPA3_ENTERPRISE_STANDARD;
diff --git a/framework/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/framework/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 62485ec..3197edc 100644
--- a/framework/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/framework/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -48,6 +48,7 @@
public static final String CA_CERT_PREFIX = KEYSTORE_URI + Credentials.CA_CERTIFICATE;
public static final String KEYSTORES_URI = "keystores://";
private static final String TEST_DOMAIN_SUFFIX_MATCH = "domainSuffixMatch";
+ private static final String TEST_ALT_SUBJECT_MATCH = "DNS:server.test.com";
private WifiEnterpriseConfig mEnterpriseConfig;
@@ -543,35 +544,78 @@
}
@Test
- public void testIsEnterpriseConfigSecure() {
+ public void testIsEnterpriseConfigServerCertNotEnabled() {
WifiEnterpriseConfig baseConfig = new WifiEnterpriseConfig();
baseConfig.setEapMethod(Eap.PEAP);
baseConfig.setPhase2Method(Phase2.MSCHAPV2);
- assertTrue(baseConfig.isInsecure());
+ assertTrue(baseConfig.doesEapMethodUseServerCert());
+ assertFalse(baseConfig.isServerCertValidationEnabled());
WifiEnterpriseConfig noMatchConfig = new WifiEnterpriseConfig(baseConfig);
noMatchConfig.setCaCertificate(FakeKeys.CA_CERT0);
- // Missing match is insecure.
- assertTrue(noMatchConfig.isInsecure());
+ // Missing match disables validation.
+ assertTrue(baseConfig.doesEapMethodUseServerCert());
+ assertFalse(baseConfig.isServerCertValidationEnabled());
WifiEnterpriseConfig noCaConfig = new WifiEnterpriseConfig(baseConfig);
noCaConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
- // Missing CA certificate is insecure.
- assertTrue(noCaConfig.isInsecure());
+ // Missing CA certificate disables validation.
+ assertTrue(baseConfig.doesEapMethodUseServerCert());
+ assertFalse(baseConfig.isServerCertValidationEnabled());
- WifiEnterpriseConfig secureConfig = new WifiEnterpriseConfig();
- secureConfig.setEapMethod(Eap.PEAP);
- secureConfig.setPhase2Method(Phase2.MSCHAPV2);
- secureConfig.setCaCertificate(FakeKeys.CA_CERT0);
- secureConfig.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
- assertFalse(secureConfig.isInsecure());
-
- WifiEnterpriseConfig secureConfigWithCaAlias = new WifiEnterpriseConfig();
- secureConfigWithCaAlias.setEapMethod(Eap.PEAP);
- secureConfigWithCaAlias.setPhase2Method(Phase2.MSCHAPV2);
- secureConfigWithCaAlias.setCaCertificateAliases(new String[]{"alias1", "alisa2"});
- secureConfigWithCaAlias.setDomainSuffixMatch(TEST_DOMAIN_SUFFIX_MATCH);
- assertFalse(secureConfigWithCaAlias.isInsecure());
+ WifiEnterpriseConfig noValidationConfig = new WifiEnterpriseConfig();
+ noValidationConfig.setEapMethod(Eap.AKA);
+ assertFalse(noValidationConfig.doesEapMethodUseServerCert());
}
+ @Test
+ public void testIsEnterpriseConfigServerCertEnabledWithPeap() {
+ testIsEnterpriseConfigServerCertEnabled(Eap.PEAP);
+ }
+
+ @Test
+ public void testIsEnterpriseConfigServerCertEnabledWithTls() {
+ testIsEnterpriseConfigServerCertEnabled(Eap.TLS);
+ }
+
+ @Test
+ public void testIsEnterpriseConfigServerCertEnabledWithTTLS() {
+ testIsEnterpriseConfigServerCertEnabled(Eap.TTLS);
+ }
+
+ private void testIsEnterpriseConfigServerCertEnabled(int eapMethod) {
+ WifiEnterpriseConfig configWithCertAndDomainSuffixMatch = createEnterpriseConfig(eapMethod,
+ Phase2.NONE, FakeKeys.CA_CERT0, null, TEST_DOMAIN_SUFFIX_MATCH, null);
+ assertTrue(configWithCertAndDomainSuffixMatch.doesEapMethodUseServerCert());
+ assertTrue(configWithCertAndDomainSuffixMatch.isServerCertValidationEnabled());
+
+ WifiEnterpriseConfig configWithCertAndAltSubjectMatch = createEnterpriseConfig(eapMethod,
+ Phase2.NONE, FakeKeys.CA_CERT0, null, null, TEST_ALT_SUBJECT_MATCH);
+ assertTrue(configWithCertAndAltSubjectMatch.doesEapMethodUseServerCert());
+ assertTrue(configWithCertAndAltSubjectMatch.isServerCertValidationEnabled());
+
+ WifiEnterpriseConfig configWithAliasAndDomainSuffixMatch = createEnterpriseConfig(eapMethod,
+ Phase2.NONE, null, new String[]{"alias1", "alisa2"}, TEST_DOMAIN_SUFFIX_MATCH,
+ null);
+ assertTrue(configWithAliasAndDomainSuffixMatch.doesEapMethodUseServerCert());
+ assertTrue(configWithAliasAndDomainSuffixMatch.isServerCertValidationEnabled());
+
+ WifiEnterpriseConfig configWithAliasAndAltSubjectMatch = createEnterpriseConfig(eapMethod,
+ Phase2.NONE, null, new String[]{"alias1", "alisa2"}, null, TEST_ALT_SUBJECT_MATCH);
+ assertTrue(configWithAliasAndAltSubjectMatch.doesEapMethodUseServerCert());
+ assertTrue(configWithAliasAndAltSubjectMatch.isServerCertValidationEnabled());
+ }
+
+ private WifiEnterpriseConfig createEnterpriseConfig(int eapMethod, int phase2Method,
+ X509Certificate caCertificate, String[] aliases, String domainSuffixMatch,
+ String altSubjectMatch) {
+ WifiEnterpriseConfig config = new WifiEnterpriseConfig();
+ config.setEapMethod(eapMethod);
+ config.setPhase2Method(phase2Method);
+ config.setCaCertificate(caCertificate);
+ config.setCaCertificateAliases(aliases);
+ config.setDomainSuffixMatch(domainSuffixMatch);
+ config.setAltSubjectMatch(altSubjectMatch);
+ return config;
+ }
}
diff --git a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
index 2f6ee23..a40a0ae 100644
--- a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
+++ b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
@@ -236,7 +236,9 @@
boolean untrustedNetworkAllowed, boolean oemPaidNetworkAllowed,
boolean oemPrivateNetworkAllowed) {
// Ignore insecure enterprise config.
- if (config.isEnterprise() && config.enterpriseConfig.isInsecure()) {
+ if (config.isEnterprise() && config.enterpriseConfig.isTlsBasedEapMethod()
+ && !config.enterpriseConfig
+ .isMandatoryParameterSetForServerCertValidation()) {
mLocalLog.log("Ignoring insecure enterprise network: " + config);
return false;
}
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index a27803b4..646b119 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -1045,12 +1045,14 @@
return false;
}
if (wns.passpointConfiguration == null) {
- if (!WifiConfigurationUtil.validate(wns.wifiConfiguration,
+ WifiConfiguration config = wns.wifiConfiguration;
+ if (!WifiConfigurationUtil.validate(config,
WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
return false;
}
- if (wns.wifiConfiguration.isEnterprise()
- && wns.wifiConfiguration.enterpriseConfig.isInsecure()) {
+ if (config.isEnterprise() && config.enterpriseConfig.isTlsBasedEapMethod()
+ && !config.enterpriseConfig
+ .isMandatoryParameterSetForServerCertValidation()) {
Log.e(TAG, "Insecure enterprise suggestion is invalid.");
return false;
}
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index fd855b2..75c087b 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -2662,7 +2662,8 @@
}
if (config.isEnterprise()) {
- if (config.enterpriseConfig.isInsecure()) {
+ if (config.enterpriseConfig.isTlsBasedEapMethod()
+ && !config.enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
Log.e(TAG, "Enterprise network configuration is missing either a Root CA "
+ "or a domain name");
return -1;