diff options
4 files changed, 204 insertions, 40 deletions
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java index 71d4173a389c..26bdb181e4a1 100644 --- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java @@ -20,10 +20,10 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; +import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; -import android.os.Parcel; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -467,24 +467,54 @@ public final class PasspointConfiguration implements Parcelable { } /** - * Validate the configuration data. + * Validate the R1 configuration data. * * @return true on success or false on failure * @hide */ public boolean validate() { - if (mHomeSp == null || !mHomeSp.validate()) { + // Optional: PerProviderSubscription/<X+>/SubscriptionUpdate + if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) { return false; } - if (mCredential == null || !mCredential.validate()) { + return validateForCommonR1andR2(true); + } + + /** + * Validate the R2 configuration data. + * + * @return true on success or false on failure + * @hide + */ + public boolean validateForR2() { + // Required: PerProviderSubscription/UpdateIdentifier + if (mUpdateIdentifier == Integer.MIN_VALUE) { return false; } - if (mPolicy != null && !mPolicy.validate()) { + + // Required: PerProviderSubscription/<X+>/SubscriptionUpdate + if (mSubscriptionUpdate == null || !mSubscriptionUpdate.validate()) { return false; } - if (mSubscriptionUpdate != null && !mSubscriptionUpdate.validate()) { + return validateForCommonR1andR2(false); + } + + private boolean validateForCommonR1andR2(boolean isR1) { + // Required: PerProviderSubscription/<X+>/HomeSP + if (mHomeSp == null || !mHomeSp.validate()) { + return false; + } + + // Required: PerProviderSubscription/<X+>/Credential + if (mCredential == null || !mCredential.validate(isR1)) { + return false; + } + + // Optional: PerProviderSubscription/<X+>/Policy + if (mPolicy != null && !mPolicy.validate()) { return false; } + if (mTrustRootCertList != null) { for (Map.Entry<String, byte[]> entry : mTrustRootCertList.entrySet()) { String url = entry.getKey(); diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index e8fcbfd6731e..7689fc34ff5b 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -18,8 +18,8 @@ package android.net.wifi.hotspot2.pps; import android.net.wifi.EAPConstants; import android.net.wifi.ParcelUtil; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; @@ -1019,10 +1019,11 @@ public final class Credential implements Parcelable { /** * Validate the configuration data. * + * @param isR1 {@code true} if the configuration is for R1 * @return true on success or false on failure * @hide */ - public boolean validate() { + public boolean validate(boolean isR1) { if (TextUtils.isEmpty(mRealm)) { Log.d(TAG, "Missing realm"); return false; @@ -1035,11 +1036,11 @@ public final class Credential implements Parcelable { // Verify the credential. if (mUserCredential != null) { - if (!verifyUserCredential()) { + if (!verifyUserCredential(isR1)) { return false; } } else if (mCertCredential != null) { - if (!verifyCertCredential()) { + if (!verifyCertCredential(isR1)) { return false; } } else if (mSimCredential != null) { @@ -1081,9 +1082,10 @@ public final class Credential implements Parcelable { /** * Verify user credential. * + * @param isR1 {@code true} if credential is for R1 * @return true if user credential is valid, false otherwise. */ - private boolean verifyUserCredential() { + private boolean verifyUserCredential(boolean isR1) { if (mUserCredential == null) { Log.d(TAG, "Missing user credential"); return false; @@ -1095,7 +1097,10 @@ public final class Credential implements Parcelable { if (!mUserCredential.validate()) { return false; } - if (mCaCertificate == null) { + + // CA certificate is required for R1 Passpoint profile. + // For R2, it is downloaded using cert URL provided in PPS MO after validation completes. + if (isR1 && mCaCertificate == null) { Log.d(TAG, "Missing CA Certificate for user credential"); return false; } @@ -1106,9 +1111,10 @@ public final class Credential implements Parcelable { * Verify certificate credential, which is used for EAP-TLS. This will verify * that the necessary client key and certificates are provided. * + * @param isR1 {@code true} if credential is for R1 * @return true if certificate credential is valid, false otherwise. */ - private boolean verifyCertCredential() { + private boolean verifyCertCredential(boolean isR1) { if (mCertCredential == null) { Log.d(TAG, "Missing certificate credential"); return false; @@ -1123,7 +1129,9 @@ public final class Credential implements Parcelable { } // Verify required key and certificates for certificate credential. - if (mCaCertificate == null) { + // CA certificate is required for R1 Passpoint profile. + // For R2, it is downloaded using cert URL provided in PPS MO after validation completes. + if (isR1 && mCaCertificate == null) { Log.d(TAG, "Missing CA Certificate for certificate credential"); return false; } diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index 940adc809535..775ce21656f7 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -146,6 +146,7 @@ public class PasspointConfigurationTest { */ private static PasspointConfiguration createConfig() { PasspointConfiguration config = new PasspointConfiguration(); + config.setUpdateIdentifier(1234); config.setHomeSp(createHomeSp()); config.setCredential(createCredential()); config.setPolicy(createPolicy()); @@ -273,18 +274,37 @@ public class PasspointConfigurationTest { @Test public void validateDefaultConfig() throws Exception { PasspointConfiguration config = new PasspointConfiguration(); + assertFalse(config.validate()); + assertFalse(config.validateForR2()); } /** - * Verify that a configuration contained all fields is valid. + * Verify that a configuration containing all fields is valid for R1/R2. * * @throws Exception */ @Test public void validateFullConfig() throws Exception { PasspointConfiguration config = createConfig(); + + assertTrue(config.validate()); + assertTrue(config.validateForR2()); + } + + /** + * Verify that a configuration containing all fields except for UpdateIdentifier is valid for + * R1, but invalid for R2. + * + * @throws Exception + */ + @Test + public void validateFullConfigWithoutUpdateIdentifier() throws Exception { + PasspointConfiguration config = createConfig(); + config.setUpdateIdentifier(Integer.MIN_VALUE); + assertTrue(config.validate()); + assertFalse(config.validateForR2()); } /** @@ -296,7 +316,9 @@ public class PasspointConfigurationTest { public void validateConfigWithoutCredential() throws Exception { PasspointConfiguration config = createConfig(); config.setCredential(null); + assertFalse(config.validate()); + assertFalse(config.validateForR2()); } /** @@ -308,12 +330,14 @@ public class PasspointConfigurationTest { public void validateConfigWithoutHomeSp() throws Exception { PasspointConfiguration config = createConfig(); config.setHomeSp(null); + assertFalse(config.validate()); + assertFalse(config.validateForR2()); } /** * Verify that a configuration without Policy is valid, since Policy configurations - * are optional (applied for Hotspot 2.0 Release only). + * are optional for R1 and R2. * * @throws Exception */ @@ -321,12 +345,14 @@ public class PasspointConfigurationTest { public void validateConfigWithoutPolicy() throws Exception { PasspointConfiguration config = createConfig(); config.setPolicy(null); + assertTrue(config.validate()); + assertTrue(config.validateForR2()); } /** - * Verify that a configuration without subscription update is valid, since subscription - * update configurations are optional (applied for Hotspot 2.0 Release only). + * Verify that a configuration without subscription update is valid for R1 and invalid for R2, + * since subscription update configuration is only applicable for R2. * * @throws Exception */ @@ -334,7 +360,9 @@ public class PasspointConfigurationTest { public void validateConfigWithoutSubscriptionUpdate() throws Exception { PasspointConfiguration config = createConfig(); config.setSubscriptionUpdate(null); + assertTrue(config.validate()); + assertFalse(config.validateForR2()); } /** @@ -352,12 +380,15 @@ public class PasspointConfigurationTest { trustRootCertList.put(new String(rawUrlBytes, StandardCharsets.UTF_8), new byte[CERTIFICATE_FINGERPRINT_BYTES]); config.setTrustRootCertList(trustRootCertList); + assertFalse(config.validate()); trustRootCertList = new HashMap<>(); trustRootCertList.put(null, new byte[CERTIFICATE_FINGERPRINT_BYTES]); config.setTrustRootCertList(trustRootCertList); + assertFalse(config.validate()); + assertFalse(config.validateForR2()); } /** @@ -382,6 +413,7 @@ public class PasspointConfigurationTest { trustRootCertList.put("test.cert.com", null); config.setTrustRootCertList(trustRootCertList); assertFalse(config.validate()); + assertFalse(config.validateForR2()); } /** diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index c5ad7de12d19..c07db6c323a2 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -24,14 +24,13 @@ import android.net.wifi.FakeKeys; import android.os.Parcel; import android.support.test.filters.SmallTest; +import org.junit.Test; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.util.Arrays; - -import org.junit.Test; /** * Unit tests for {@link android.net.wifi.hotspot2.pps.CredentialTest}. @@ -169,7 +168,12 @@ public class CredentialTest { @Test public void validateUserCredential() throws Exception { Credential cred = createCredentialWithUserCredential(); - assertTrue(cred.validate()); + + // For R1 validation + assertTrue(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -181,7 +185,12 @@ public class CredentialTest { public void validateUserCredentialWithoutCaCert() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.setCaCertificate(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -193,7 +202,12 @@ public class CredentialTest { public void validateUserCredentialWithEapTls() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.getUserCredential().setEapType(EAPConstants.EAP_TLS); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } @@ -206,7 +220,12 @@ public class CredentialTest { public void validateUserCredentialWithoutRealm() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.setRealm(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -218,7 +237,12 @@ public class CredentialTest { public void validateUserCredentialWithoutUsername() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.getUserCredential().setUsername(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -230,7 +254,12 @@ public class CredentialTest { public void validateUserCredentialWithoutPassword() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.getUserCredential().setPassword(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -242,7 +271,12 @@ public class CredentialTest { public void validateUserCredentialWithoutAuthMethod() throws Exception { Credential cred = createCredentialWithUserCredential(); cred.getUserCredential().setNonEapInnerMethod(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -255,7 +289,12 @@ public class CredentialTest { @Test public void validateCertCredential() throws Exception { Credential cred = createCredentialWithCertificateCredential(); - assertTrue(cred.validate()); + + // For R1 validation + assertTrue(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(true)); } /** @@ -267,7 +306,12 @@ public class CredentialTest { public void validateCertCredentialWithoutCaCert() throws Exception { Credential cred = createCredentialWithCertificateCredential(); cred.setCaCertificate(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -279,7 +323,12 @@ public class CredentialTest { public void validateCertCredentialWithoutClientCertChain() throws Exception { Credential cred = createCredentialWithCertificateCredential(); cred.setClientCertificateChain(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -291,7 +340,12 @@ public class CredentialTest { public void validateCertCredentialWithoutClientPrivateKey() throws Exception { Credential cred = createCredentialWithCertificateCredential(); cred.setClientPrivateKey(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -304,7 +358,12 @@ public class CredentialTest { public void validateCertCredentialWithMismatchFingerprint() throws Exception { Credential cred = createCredentialWithCertificateCredential(); cred.getCertCredential().setCertSha256Fingerprint(new byte[32]); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -315,7 +374,12 @@ public class CredentialTest { @Test public void validateSimCredentialWithEapSim() throws Exception { Credential cred = createCredentialWithSimCredential(); - assertTrue(cred.validate()); + + // For R1 validation + assertTrue(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -327,7 +391,12 @@ public class CredentialTest { public void validateSimCredentialWithEapAka() throws Exception { Credential cred = createCredentialWithSimCredential(); cred.getSimCredential().setEapType(EAPConstants.EAP_AKA); - assertTrue(cred.validate()); + + // For R1 validation + assertTrue(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -339,7 +408,12 @@ public class CredentialTest { public void validateSimCredentialWithEapAkaPrime() throws Exception { Credential cred = createCredentialWithSimCredential(); cred.getSimCredential().setEapType(EAPConstants.EAP_AKA_PRIME); - assertTrue(cred.validate()); + + // For R1 validation + assertTrue(cred.validate(true)); + + // For R2 validation + assertTrue(cred.validate(false)); } /** @@ -351,7 +425,12 @@ public class CredentialTest { public void validateSimCredentialWithoutIMSI() throws Exception { Credential cred = createCredentialWithSimCredential(); cred.getSimCredential().setImsi(null); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -363,7 +442,12 @@ public class CredentialTest { public void validateSimCredentialWithInvalidIMSI() throws Exception { Credential cred = createCredentialWithSimCredential(); cred.getSimCredential().setImsi("dummy"); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -375,7 +459,12 @@ public class CredentialTest { public void validateSimCredentialWithEapTls() throws Exception { Credential cred = createCredentialWithSimCredential(); cred.getSimCredential().setEapType(EAPConstants.EAP_TLS); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** @@ -391,7 +480,12 @@ public class CredentialTest { simCredential.setImsi("1234*"); simCredential.setEapType(EAPConstants.EAP_SIM); cred.setSimCredential(simCredential); - assertFalse(cred.validate()); + + // For R1 validation + assertFalse(cred.validate(true)); + + // For R2 validation + assertFalse(cred.validate(false)); } /** |