diff options
| author | 2016-03-21 10:50:01 +0000 | |
|---|---|---|
| committer | 2016-03-31 18:06:44 +0100 | |
| commit | 2f7e1e487c8ef486a16ad2398ffee413b53da04e (patch) | |
| tree | 718e2a6749b7cbe24f869140aaacffc1d0b6f014 | |
| parent | 36e480cf8cec07a9204c2f50d7268c39e1c0aeae (diff) | |
API to approve CA certificates
Bug: 18224038
Change-Id: Id928872cd70dac5a5ecfdcd52150fe6dea544e3b
3 files changed, 126 insertions, 22 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index e7427bfabe01..b06350411944 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2654,6 +2654,43 @@ public class DevicePolicyManager { } /** + * Mark a CA certificate as approved by the device user. This means that they have been notified + * of the installation, were made aware of the risks, viewed the certificate and still wanted to + * keep the certificate on the device. + * + * Calling with {@param approval} as {@code true} will cancel any ongoing warnings related to + * this certificate. + * + * @hide + */ + public boolean approveCaCert(String alias, int userHandle, boolean approval) { + if (mService != null) { + try { + return mService.approveCaCert(alias, userHandle, approval); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Check whether a CA certificate has been approved by the device user. + * + * @hide + */ + public boolean isCaCertApproved(String alias, int userHandle) { + if (mService != null) { + try { + return mService.isCaCertApproved(alias, userHandle); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** * Installs the given certificate as a user CA. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index aed220dd5705..b6174f1b6ee2 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -144,6 +144,8 @@ interface IDevicePolicyManager { boolean installCaCert(in ComponentName admin, in byte[] certBuffer); void uninstallCaCerts(in ComponentName admin, in String[] aliases); void enforceCanManageCaCerts(in ComponentName admin); + boolean approveCaCert(in String alias, int userHandle, boolean approval); + boolean isCaCertApproved(in String alias, int userHandle); boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias, boolean requestAccess); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d8b856b9b753..9203e9982c04 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -136,6 +136,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; +import com.android.internal.util.ParcelableString; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; @@ -184,12 +185,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String DEVICE_POLICIES_XML = "device_policies.xml"; + private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate"; + private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; private static final String TAG_STATUS_BAR = "statusbar"; private static final String ATTR_DISABLED = "disabled"; + private static final String ATTR_NAME = "name"; + private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML = "do-not-ask-credentials-on-boot"; @@ -420,6 +425,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); + final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>(); + // This is the list of component allowed to start lock task mode. List<String> mLockTaskPackages = new ArrayList<>(); @@ -483,7 +490,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (Intent.ACTION_BOOT_COMPLETED.equals(action) || KeyChain.ACTION_STORAGE_CHANGED.equals(action)) { - new MonitoringCertNotificationTask().execute(intent); + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); + new MonitoringCertNotificationTask().execute(userId); } if (Intent.ACTION_USER_ADDED.equals(action)) { disableSecurityLoggingIfNotCompliant(); @@ -2215,6 +2223,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, "active-password"); } + for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) { + out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i)); + out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + } + for (int i=0; i<policy.mLockTaskPackages.size(); i++) { String component = policy.mLockTaskPackages.get(i); out.startTag(null, TAG_LOCK_TASK_COMPONENTS); @@ -2381,6 +2395,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { parser.getAttributeValue(null, "symbols")); policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); + } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { + policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); } else if (TAG_STATUS_BAR.equals(tag)) { @@ -2632,17 +2648,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private class MonitoringCertNotificationTask extends AsyncTask<Intent, Void, Void> { + private class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Void> { @Override - protected Void doInBackground(Intent... params) { - int userHandle = params[0].getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); + protected Void doInBackground(Integer... params) { + int userHandle = params[0]; if (userHandle == UserHandle.USER_ALL) { for (UserInfo userInfo : mUserManager.getUsers()) { manageNotification(userInfo.getUserHandle()); } } else { - manageNotification(new UserHandle(userHandle)); + manageNotification(UserHandle.of(userHandle)); } return null; } @@ -2652,25 +2668,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } - // Call out to KeyChain to check for user-added CAs - boolean hasCert = false; + // Call out to KeyChain to check for CAs which are waiting for approval. + final List<String> pendingCertificates; try { - KeyChainConnection kcs = KeyChain.bindAsUser(mContext, userHandle); - try { - if (!kcs.getService().getUserCaAliases().getList().isEmpty()) { - hasCert = true; - } - } catch (RemoteException e) { - Log.e(LOG_TAG, "Could not connect to KeyChain service", e); - } finally { - kcs.close(); + pendingCertificates = getInstalledCaCertificates(userHandle); + } catch (RemoteException | RuntimeException e) { + Log.e(LOG_TAG, "Could not retrieve certificates from KeyChain service", e); + return; + } + + synchronized (DevicePolicyManagerService.this) { + final DevicePolicyData policy = getUserData(userHandle.getIdentifier()); + + // Remove deleted certificates. Flush xml if necessary. + if (policy.mAcceptedCaCertificates.retainAll(pendingCertificates)) { + saveSettingsLocked(userHandle.getIdentifier()); } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (RuntimeException | AssertionError e) { - Log.e(LOG_TAG, "Could not connect to KeyChain service", e); + // Trim to approved certificates. + pendingCertificates.removeAll(policy.mAcceptedCaCertificates); } - if (!hasCert) { + + if (pendingCertificates.isEmpty()) { mInjector.getNotificationManager().cancelAsUser( null, MONITORING_CERT_NOTIFICATION_ID, userHandle); return; @@ -2701,7 +2719,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final Context userContext; try { - userContext = mContext.createPackageContextAsUser("android", 0, userHandle); + final String packageName = mContext.getPackageName(); + userContext = mContext.createPackageContextAsUser(packageName, 0, userHandle); } catch (PackageManager.NameNotFoundException e) { Log.e(LOG_TAG, "Create context as " + userHandle + " failed", e); return; @@ -2720,6 +2739,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mInjector.getNotificationManager().notifyAsUser( null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle); } + + private List<String> getInstalledCaCertificates(UserHandle userHandle) + throws RemoteException, RuntimeException { + KeyChainConnection conn = null; + try { + conn = KeyChain.bindAsUser(mContext, userHandle); + List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList(); + List<String> result = new ArrayList<>(aliases.size()); + for (int i = 0; i < aliases.size(); i++) { + result.add(aliases.get(i).string); + } + return result; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } catch (AssertionError e) { + throw new RuntimeException(e); + } finally { + if (conn != null) { + conn.close(); + } + } + } } /** @@ -4070,6 +4112,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override + public boolean approveCaCert(String alias, int userId, boolean approval) { + enforceManageUsers(); + synchronized (this) { + Set<String> certs = getUserData(userId).mAcceptedCaCertificates; + boolean changed = (approval ? certs.add(alias) : certs.remove(alias)); + if (!changed) { + return false; + } + saveSettingsLocked(userId); + } + new MonitoringCertNotificationTask().execute(userId); + return true; + } + + @Override + public boolean isCaCertApproved(String alias, int userId) { + enforceManageUsers(); + synchronized (this) { + return getUserData(userId).mAcceptedCaCertificates.contains(alias); + } + } + + @Override public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException { enforceCanManageCaCerts(admin); |