CA cert monitoring: add notifications and actions for dialog
In DevicePolicyManagementService, on boot and when certs are installed,
post notification to tell the user that their traffic may be
monitored.
Have QuickSettings use the MonitoringCertInfoActivity instead
of building the dialog itself.
Bug: 10633199
Change-Id: Ie4b97295a9fc25867c87872feccdb17f4bea071d
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0b1c00..ab82531 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1372,7 +1372,7 @@
*
* @hide
*/
- public boolean hasAnyCaCertsInstalled() {
+ public static boolean hasAnyCaCertsInstalled() {
TrustedCertificateStore certStore = new TrustedCertificateStore();
Set<String> aliases = certStore.userAliases();
return aliases != null && !aliases.isEmpty();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1a80818..1ba9821 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -160,6 +160,38 @@
"android.settings.SECURITY_SETTINGS";
/**
+ * Activity Action: Show trusted credentials settings, opening to the user tab,
+ * to allow management of installed credentials.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_TRUSTED_CREDENTIALS_USER =
+ "com.android.settings.TRUSTED_CREDENTIALS_USER";
+
+ /**
+ * Activity Action: Show dialog explaining that an installed CA cert may enable
+ * monitoring of encrypted network traffic.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MONITORING_CERT_INFO =
+ "com.android.settings.MONITORING_CERT_INFO";
+
+ /**
* Activity Action: Show settings to allow configuration of privacy options.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
diff --git a/core/res/res/drawable-hdpi/stat_sys_certificate_info.png b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3be426c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_certificate_info.png b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..e15cf38
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..3c93ea0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
new file mode 100644
index 0000000..d96ef64
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/stat_sys_certificate_info.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 68acd8c..b6e3a03 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -273,6 +273,18 @@
<!-- If MMS discovers there isn't much space left on the device, it will show a toast with this message. -->
<string name="low_memory" product="default">Phone storage is full. Delete some files to free space.</string>
+ <!-- SSL CA cert notification --> <skip />
+ <!-- Shows up when there is a user SSL CA Cert installed on the
+ device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
+ <string name="ssl_ca_cert_warning">Network may be monitored</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This says that an unknown party is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_by_unknown">By an unknown third party</string>
+ <!-- Content text for a notification. The Title of the notification is "ssl_ca_cert_warning",
+ i.e. "Network may be monitored". This indicates who is doing the monitoring.
+ [CHAR LIMIT=100]-->
+ <string name="ssl_ca_cert_noti_managed">By <xliff:g id="managing_domain">%s</xliff:g></string>
<!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. -->
<string name="me">Me</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 39e7127..c928a51 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -884,6 +884,9 @@
<java-symbol type="string" name="write_fail_reason_cannot_write" />
<java-symbol type="string" name="transient_navigation_confirmation" />
<java-symbol type="string" name="transient_navigation_confirmation_long" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_by_unknown" />
+ <java-symbol type="string" name="ssl_ca_cert_noti_managed" />
+ <java-symbol type="string" name="ssl_ca_cert_warning" />
<java-symbol type="plurals" name="abbrev_in_num_days" />
<java-symbol type="plurals" name="abbrev_in_num_hours" />
@@ -1006,6 +1009,7 @@
<java-symbol type="drawable" name="stat_notify_rssi_in_range" />
<java-symbol type="drawable" name="stat_sys_gps_on" />
<java-symbol type="drawable" name="stat_sys_tether_wifi" />
+ <java-symbol type="drawable" name="stat_sys_certificate_info" />
<java-symbol type="drawable" name="status_bar_background" />
<java-symbol type="drawable" name="sym_keyboard_shift" />
<java-symbol type="drawable" name="sym_keyboard_shift_locked" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3ffa6f4..bbfe383 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -500,16 +500,5 @@
<!-- Shows up when there is a user SSL CA Cert installed on the
device. Indicates to the user that SSL traffic can be intercepted. [CHAR LIMIT=NONE] -->
<string name="ssl_ca_cert_warning">Network may be monitored</string>
- <!-- Button to close the SSL CA cert warning dialog box. [CHAR LIMIT=NONE] -->
- <string name="done_button">Done</string>
- <!-- Title of Dialog warning users of SSL monitoring. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_dialog_title">Network Monitoring</string>
- <!-- Text of message to show to users whose administrator has installed a SSL CA Cert.
- [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_info_message">This device is managed by: <xliff:g id="managing_domain">%s</xliff:g>.\n\nYour administrator is capable of monitoring your network activity, including emails, apps, and secure websites.\n\nFor more information,contact your administrator.</string>
- <!-- Text of warning to show to users that have a SSL CA Cert installed. [CHAR LIMIT=NONE] -->
- <string name="ssl_ca_cert_warning_message">A third party is capable of monitoring your network\nactivity, including emails, apps, and secure websites.\n\nA trusted credential installed on your device is making this possible.</string>
- <!-- Label on button that will take the user to the Trusted Credentials settings page.
- [CHAR LIMIT=NONE]-->
- <string name="ssl_ca_cert_settings_button">Check trusted credentials</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 0d591ba..9015ba9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -192,7 +192,7 @@
mQueryCertTask = new AsyncTask<Void, Void, Pair<Boolean, Boolean>>() {
@Override
protected Pair<Boolean, Boolean> doInBackground(Void... params) {
- boolean hasCert = mDevicePolicyManager.hasAnyCaCertsInstalled();
+ boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
boolean isManaged = mDevicePolicyManager.getDeviceOwner() != null;
return Pair.create(hasCert, isManaged);
@@ -756,7 +756,7 @@
@Override
public void onClick(View v) {
collapsePanels();
- showSslCaCertWarningDialog();
+ startSettingsActivity(Settings.ACTION_MONITORING_CERT_INFO);
}
});
@@ -824,45 +824,6 @@
dialog.show();
}
- private void showSslCaCertWarningDialog() {
- final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(R.string.ssl_ca_cert_dialog_title);
- builder.setCancelable(true);
- final boolean hasDeviceOwner = mDevicePolicyManager.getDeviceOwner() != null;
- int buttonLabel;
- if (hasDeviceOwner) {
- // Institutional case. Show informational message.
- String message = mContext.getResources().getString(R.string.ssl_ca_cert_info_message,
- mDevicePolicyManager.getDeviceOwnerName());
- builder.setMessage(message);
- buttonLabel = R.string.done_button;
- } else {
- // Consumer case. Show scary warning.
- builder.setMessage(R.string.ssl_ca_cert_warning_message);
- buttonLabel = R.string.ssl_ca_cert_settings_button;
- }
-
- builder.setPositiveButton(buttonLabel, new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // do something.
- if (hasDeviceOwner) {
- // Close
- } else {
- startSettingsActivity("com.android.settings.TRUSTED_CREDENTIALS_USER");
- }
- }
- });
-
- final Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- try {
- WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
- } catch (RemoteException e) {
- }
- dialog.show();
- }
-
private void updateWifiDisplayStatus() {
mWifiDisplayStatus = mDisplayManager.getWifiDisplayStatus();
applyWifiDisplayStatus();
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 7e83396..2bca759 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -33,6 +34,9 @@
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
+import android.app.INotificationManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
@@ -51,6 +55,7 @@
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -123,6 +128,8 @@
protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
+ private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+
private static final boolean DBG = false;
final Context mContext;
@@ -130,6 +137,7 @@
IPowerManager mIPowerManager;
IWindowManager mIWindowManager;
+ NotificationManager mNotificationManager;
private DeviceOwner mDeviceOwner;
@@ -177,7 +185,12 @@
handlePasswordExpirationNotification(getUserData(userHandle));
}
});
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ }
+ if (Intent.ACTION_BOOT_COMPLETED.equals(action)
+ || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
+ manageMonitoringCertificateNotification(intent);
+ }
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -526,6 +539,7 @@
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -635,6 +649,14 @@
return mIWindowManager;
}
+ private NotificationManager getNotificationManager() {
+ if (mNotificationManager == null) {
+ mNotificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+ return mNotificationManager;
+ }
+
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
if (admin != null
@@ -1053,6 +1075,63 @@
}
}
+ private void manageMonitoringCertificateNotification(Intent intent) {
+ final NotificationManager notificationManager = getNotificationManager();
+
+ final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
+ if (! hasCert) {
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.cancelAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
+ }
+ }
+ return;
+ }
+ final boolean isManaged = getDeviceOwner() != null;
+ int smallIconId;
+ String contentText;
+ if (isManaged) {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
+ getDeviceOwnerName());
+ smallIconId = R.drawable.stat_sys_certificate_info;
+ } else {
+ contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
+ smallIconId = android.R.drawable.stat_sys_warning;
+ }
+
+ Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
+ dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.setPackage("com.android.settings");
+ // Notification will be sent individually to all users. The activity should start as
+ // whichever user is current when it starts.
+ PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
+
+ Notification noti = new Notification.Builder(mContext)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setShowWhen(false)
+ .build();
+
+ // If this is a boot intent, this will fire for each user. But if this is a storage changed
+ // intent, it will fire once, so we need to notify all users.
+ if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ for (UserInfo user : um.getUsers()) {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
+ }
+ } else {
+ notificationManager.notifyAsUser(
+ null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
+ }
+ }
+
/**
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error