summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHai Shalom <haishalom@google.com>2020-04-14 01:49:31 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-04-14 01:49:31 +0000
commit20641dfcb5c341b8335c7c44d272c58de7a5adbf (patch)
tree680158765898bf6400da1b832a0338cdf9bbe922
parent683eebfed79268183905f3584d51035c08827985 (diff)
parentf17e56bbd9dd09169b9b4a6b9735acda9d31b9d1 (diff)
Merge "[Passpoint] Add metrics for Root CA and Subscription Expiration" into rvc-dev
-rw-r--r--service/java/com/android/server/wifi/WifiMetrics.java27
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointManager.java69
-rw-r--r--service/proto/src/metrics.proto9
-rw-r--r--tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java19
-rw-r--r--tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java73
5 files changed, 197 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/WifiMetrics.java b/service/java/com/android/server/wifi/WifiMetrics.java
index 0760dee4a..a9385ed91 100644
--- a/service/java/com/android/server/wifi/WifiMetrics.java
+++ b/service/java/com/android/server/wifi/WifiMetrics.java
@@ -2657,6 +2657,33 @@ public class WifiMetrics {
}
/**
+ * Increment number of Passpoint providers with no Root CA in their profile.
+ */
+ public void incrementNumPasspointProviderWithNoRootCa() {
+ synchronized (mLock) {
+ mWifiLogProto.numPasspointProviderWithNoRootCa++;
+ }
+ }
+
+ /**
+ * Increment number of Passpoint providers with a self-signed Root CA in their profile.
+ */
+ public void incrementNumPasspointProviderWithSelfSignedRootCa() {
+ synchronized (mLock) {
+ mWifiLogProto.numPasspointProviderWithSelfSignedRootCa++;
+ }
+ }
+
+ /**
+ * Increment number of Passpoint providers with subscription expiration date in their profile.
+ */
+ public void incrementNumPasspointProviderWithSubscriptionExpiration() {
+ synchronized (mLock) {
+ mWifiLogProto.numPasspointProviderWithSubscriptionExpiration++;
+ }
+ }
+
+ /**
* Increment number of times we detected a radio mode change to MCC.
*/
public void incrementNumRadioModeChangeToMcc() {
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index a702c7e98..b60ef3f63 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -29,6 +29,8 @@ import static android.net.wifi.WifiManager.EXTRA_ICON;
import static android.net.wifi.WifiManager.EXTRA_SUBSCRIPTION_REMEDIATION_METHOD;
import static android.net.wifi.WifiManager.EXTRA_URL;
+import static java.security.cert.PKIXReason.NO_TRUST_ANCHOR;
+
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
@@ -65,7 +67,16 @@ import com.android.server.wifi.hotspot2.anqp.HSOsuProvidersElement;
import com.android.server.wifi.hotspot2.anqp.OsuProviderInfo;
import com.android.server.wifi.util.InformationElementUtil;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXParameters;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -439,6 +450,34 @@ public class PasspointManager {
mWifiCarrierInfoManager, mProviderIndex++, uid, packageName, isFromSuggestion);
newProvider.setTrusted(isTrusted);
+ boolean metricsNoRootCa = false;
+ boolean metricsSelfSignedRootCa = false;
+ boolean metricsSubscriptionExpiration = false;
+
+ if (config.getCredential().getUserCredential() != null
+ || config.getCredential().getCertCredential() != null) {
+ X509Certificate[] x509Certificates = config.getCredential().getCaCertificates();
+ if (x509Certificates == null) {
+ metricsNoRootCa = true;
+ } else {
+ try {
+ for (X509Certificate certificate : x509Certificates) {
+ verifyCaCert(certificate);
+ }
+ } catch (CertPathValidatorException e) {
+ // A self signed Root CA will fail path validation checks with NO_TRUST_ANCHOR
+ if (e.getReason() == NO_TRUST_ANCHOR) {
+ metricsSelfSignedRootCa = true;
+ }
+ } catch (Exception e) {
+ // Other exceptions, fall through, will be handled below
+ }
+ }
+ }
+ if (config.getSubscriptionExpirationTimeMillis() != Long.MIN_VALUE) {
+ metricsSubscriptionExpiration = true;
+ }
+
if (!newProvider.installCertsAndKeys()) {
Log.e(TAG, "Failed to install certificates and keys to keystore");
return false;
@@ -477,6 +516,15 @@ public class PasspointManager {
Log.d(TAG, "Added/updated Passpoint configuration for FQDN: "
+ config.getHomeSp().getFqdn() + " with unique ID: " + config.getUniqueId()
+ " by UID: " + uid);
+ if (metricsNoRootCa) {
+ mWifiMetrics.incrementNumPasspointProviderWithNoRootCa();
+ }
+ if (metricsSelfSignedRootCa) {
+ mWifiMetrics.incrementNumPasspointProviderWithSelfSignedRootCa();
+ }
+ if (metricsSubscriptionExpiration) {
+ mWifiMetrics.incrementNumPasspointProviderWithSubscriptionExpiration();
+ }
mWifiMetrics.incrementNumPasspointProviderInstallSuccess();
return true;
}
@@ -1256,4 +1304,25 @@ public class PasspointManager {
mAnqpRequestManager.clear();
mAnqpCache.flush();
}
+
+ /**
+ * Verify that the given certificate is trusted by one of the pre-loaded public CAs in the
+ * system key store.
+ *
+ * @param caCert The CA Certificate to verify
+ * @throws CertPathValidatorException
+ * @throws Exception
+ */
+ private void verifyCaCert(X509Certificate caCert)
+ throws GeneralSecurityException, IOException {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ CertPathValidator validator =
+ CertPathValidator.getInstance(CertPathValidator.getDefaultType());
+ CertPath path = factory.generateCertPath(Arrays.asList(caCert));
+ KeyStore ks = KeyStore.getInstance("AndroidCAStore");
+ ks.load(null, null);
+ PKIXParameters params = new PKIXParameters(ks);
+ params.setRevocationEnabled(false);
+ validator.validate(path, params);
+ }
}
diff --git a/service/proto/src/metrics.proto b/service/proto/src/metrics.proto
index 932fb2e0f..1f6848482 100644
--- a/service/proto/src/metrics.proto
+++ b/service/proto/src/metrics.proto
@@ -675,6 +675,15 @@ message WifiLog {
// (SSID, BSSID) tuple depending on AP configuration (in the above priority
// order).
repeated NumConnectableNetworksBucket observed_hotspot_r3_ess_in_scan_histogram = 188;
+
+ // Total number of Passpoint providers with no Root CA in their profile.
+ optional int32 num_passpoint_provider_with_no_root_ca = 189;
+
+ // Total number of Passpoint providers with self-signed root CA in their profile.
+ optional int32 num_passpoint_provider_with_self_signed_root_ca = 190;
+
+ // Total number of Passpoint providers with subscription expiration date in their profile.
+ optional int32 num_passpoint_provider_with_subscription_expiration = 191;
}
// Information that gets logged for every WiFi connection.
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
index c8b149ba6..3964d2d37 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiMetricsTest.java
@@ -398,6 +398,9 @@ public class WifiMetricsTest extends WifiBaseTest {
private static final int NUM_PASSPOINT_PROVIDER_UNINSTALLATION = 3;
private static final int NUM_PASSPOINT_PROVIDER_UNINSTALL_SUCCESS = 2;
private static final int NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED = 1;
+ private static final int NUM_PASSPOINT_PROVIDERS_WITH_NO_ROOT_CA = 2;
+ private static final int NUM_PASSPOINT_PROVIDERS_WITH_SELF_SIGNED_ROOT_CA = 3;
+ private static final int NUM_PASSPOINT_PROVIDERS_WITH_EXPIRATION_DATE = 4;
private static final int NUM_EAP_SIM_TYPE = 1;
private static final int NUM_EAP_TTLS_TYPE = 2;
private static final int NUM_EAP_TLS_TYPE = 3;
@@ -873,6 +876,15 @@ public class WifiMetricsTest extends WifiBaseTest {
for (int i = 0; i < NUM_PASSPOINT_PROVIDER_UNINSTALL_SUCCESS; i++) {
mWifiMetrics.incrementNumPasspointProviderUninstallSuccess();
}
+ for (int i = 0; i < NUM_PASSPOINT_PROVIDERS_WITH_NO_ROOT_CA; i++) {
+ mWifiMetrics.incrementNumPasspointProviderWithNoRootCa();
+ }
+ for (int i = 0; i < NUM_PASSPOINT_PROVIDERS_WITH_SELF_SIGNED_ROOT_CA; i++) {
+ mWifiMetrics.incrementNumPasspointProviderWithSelfSignedRootCa();
+ }
+ for (int i = 0; i < NUM_PASSPOINT_PROVIDERS_WITH_EXPIRATION_DATE; i++) {
+ mWifiMetrics.incrementNumPasspointProviderWithSubscriptionExpiration();
+ }
for (int i = 0; i < NUM_RADIO_MODE_CHANGE_TO_MCC; i++) {
mWifiMetrics.incrementNumRadioModeChangeToMcc();
}
@@ -1329,6 +1341,13 @@ public class WifiMetricsTest extends WifiBaseTest {
mDecodedProto.numPasspointProviderUninstallSuccess);
assertEquals(NUM_PASSPOINT_PROVIDERS_SUCCESSFULLY_CONNECTED,
mDecodedProto.numPasspointProvidersSuccessfullyConnected);
+ assertEquals(NUM_PASSPOINT_PROVIDERS_WITH_NO_ROOT_CA,
+ mDecodedProto.numPasspointProviderWithNoRootCa);
+ assertEquals(NUM_PASSPOINT_PROVIDERS_WITH_SELF_SIGNED_ROOT_CA,
+ mDecodedProto.numPasspointProviderWithSelfSignedRootCa);
+ assertEquals(NUM_PASSPOINT_PROVIDERS_WITH_EXPIRATION_DATE,
+ mDecodedProto.numPasspointProviderWithSubscriptionExpiration);
+
assertEquals(NUM_RADIO_MODE_CHANGE_TO_MCC, mDecodedProto.numRadioModeChangeToMcc);
assertEquals(NUM_RADIO_MODE_CHANGE_TO_SCC, mDecodedProto.numRadioModeChangeToScc);
assertEquals(NUM_RADIO_MODE_CHANGE_TO_SBS, mDecodedProto.numRadioModeChangeToSbs);
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 73c5713ac..861aa94ff 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -2560,4 +2560,77 @@ public class PasspointManagerTest extends WifiBaseTest {
// Verify content in the data source.
assertTrue(mUserDataSource.getProviders().isEmpty());
}
+
+ /**
+ * Verify that adding a provider with a self signed root CA increments the metrics correctly.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifySelfSignRootCaMetrics() throws Exception {
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ wifiConfig.FQDN = TEST_FQDN;
+ PasspointConfiguration config =
+ createTestConfigWithUserCredential(TEST_FQDN, TEST_FRIENDLY_NAME);
+ PasspointProvider provider = createMockProvider(config, wifiConfig, true);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mWifiCarrierInfoManager), anyLong(), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE),
+ eq(true))).thenReturn(provider);
+ when(provider.getPackageName()).thenReturn(TEST_PACKAGE);
+ assertTrue(mManager.addOrUpdateProvider(
+ config, TEST_CREATOR_UID, TEST_PACKAGE, true, false));
+ verify(mWifiMetrics).incrementNumPasspointProviderWithSelfSignedRootCa();
+ verify(mWifiMetrics, never()).incrementNumPasspointProviderWithNoRootCa();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallation();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess();
+ }
+
+ /**
+ * Verify that adding a provider with no root CA increments the metrics correctly.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifyNoRootCaMetrics() throws Exception {
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ wifiConfig.FQDN = TEST_FQDN;
+ PasspointConfiguration config =
+ createTestConfigWithUserCredential(TEST_FQDN, TEST_FRIENDLY_NAME);
+ config.getCredential().setCaCertificate(null);
+ PasspointProvider provider = createMockProvider(config, wifiConfig, true);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mWifiCarrierInfoManager), anyLong(), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE),
+ eq(true))).thenReturn(provider);
+ when(provider.getPackageName()).thenReturn(TEST_PACKAGE);
+ assertTrue(mManager.addOrUpdateProvider(
+ config, TEST_CREATOR_UID, TEST_PACKAGE, true, false));
+ verify(mWifiMetrics).incrementNumPasspointProviderWithNoRootCa();
+ verify(mWifiMetrics, never()).incrementNumPasspointProviderWithSelfSignedRootCa();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallation();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess();
+ }
+
+ /**
+ * Verify that adding a provider with subscription expiration increments the metrics correctly.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void verifySubscriptionExpirationMetrics() throws Exception {
+ WifiConfiguration wifiConfig = new WifiConfiguration();
+ wifiConfig.FQDN = TEST_FQDN;
+ PasspointConfiguration config =
+ createTestConfigWithUserCredential(TEST_FQDN, TEST_FRIENDLY_NAME);
+ config.setSubscriptionExpirationTimeInMillis(1586228641000L);
+ PasspointProvider provider = createMockProvider(config, wifiConfig, true);
+ when(mObjectFactory.makePasspointProvider(eq(config), eq(mWifiKeyStore),
+ eq(mWifiCarrierInfoManager), anyLong(), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE),
+ eq(true))).thenReturn(provider);
+ when(provider.getPackageName()).thenReturn(TEST_PACKAGE);
+ assertTrue(mManager.addOrUpdateProvider(
+ config, TEST_CREATOR_UID, TEST_PACKAGE, true, false));
+ verify(mWifiMetrics).incrementNumPasspointProviderWithSubscriptionExpiration();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallation();
+ verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess();
+ }
}