From fbc65644b9bda216699f5f1f883d6dfa2668e545 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Mon, 3 Aug 2015 16:21:22 +0100 Subject: [PATCH] DevicePolicy API to remove an installed KeyPair The keypair is specified by alias and removed via a call to the KeyChainService, which will have installed the pair in the first place. Bug: 22541933 Change-Id: I37317e7c22e89816156e6e9a7abf4c5a59e8440a --- api/current.txt | 1 + api/system-current.txt | 1 + .../app/admin/DevicePolicyManager.java | 22 ++++++- .../app/admin/IDevicePolicyManager.aidl | 1 + .../android/security/IKeyChainService.aidl | 1 + .../DevicePolicyManagerService.java | 66 ++++++++++++++----- 6 files changed, 72 insertions(+), 20 deletions(-) diff --git a/api/current.txt b/api/current.txt index 007ed134d9abc..2e2a604c5dff3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5802,6 +5802,7 @@ package android.app.admin { method public void lockNow(); method public void removeActiveAdmin(android.content.ComponentName); method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); + method public boolean removeKeyPair(android.content.ComponentName, java.lang.String); method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean resetPassword(java.lang.String, int); method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); diff --git a/api/system-current.txt b/api/system-current.txt index 1a05551a3fe99..30be4c714868b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5935,6 +5935,7 @@ package android.app.admin { method public void notifyPendingSystemUpdate(long); method public void removeActiveAdmin(android.content.ComponentName); method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String); + method public boolean removeKeyPair(android.content.ComponentName, java.lang.String); method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean resetPassword(java.lang.String, int); method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 471750eda0cf8..6b900a8ab36d4 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -2325,8 +2325,8 @@ public class DevicePolicyManager { * with that alias already exists, it will be overwritten. * @return {@code true} if the keys were installed, {@code false} otherwise. */ - public boolean installKeyPair(@Nullable ComponentName admin, PrivateKey privKey, Certificate cert, - String alias) { + public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, + @NonNull Certificate cert, @NonNull String alias) { try { final byte[] pemCert = Credentials.convertToPem(cert); final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm()) @@ -2342,6 +2342,24 @@ public class DevicePolicyManager { return false; } + /** + * Called by a device or profile owner to remove all user credentials installed under a given + * alias. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The private key alias under which the certificate is installed. + * @return {@code true} if the keys were both removed, {@code false} otherwise. + */ + public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) { + try { + return mService.removeKeyPair(admin, alias); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + return false; + } + /** * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 6b4567c297c53..1708ee3c73e3e 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -135,6 +135,7 @@ interface IDevicePolicyManager { void enforceCanManageCaCerts(in ComponentName admin); boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias); + boolean removeKeyPair(in ComponentName who, String alias); void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback); void setCertInstallerPackage(in ComponentName who, String installerPackage); diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index 20c94c5946d78..cfcb4e0c16e1b 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -33,6 +33,7 @@ interface IKeyChainService { // APIs used by DevicePolicyManager boolean installKeyPair(in byte[] privateKey, in byte[] userCert, String alias); + boolean removeKeyPair(String alias); // APIs used by Settings boolean deleteCaCertificate(String alias); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eed5419218ad2..5cf8ac0e2c8d0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3541,6 +3541,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void enforceCanManageInstalledKeys(ComponentName who) { + if (who == null) { + if (!isCallerDelegatedCertInstaller()) { + throw new SecurityException("who == null, but caller is not cert installer"); + } + } else { + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + } + } + } + private boolean isCallerDelegatedCertInstaller() { final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = UserHandle.getUserId(callingUid); @@ -3630,27 +3642,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) { - if (who == null) { - if (!isCallerDelegatedCertInstaller()) { - throw new SecurityException("who == null, but caller is not cert installer"); - } - } else { - synchronized (this) { - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - } - } + enforceCanManageInstalledKeys(who); + final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); final long id = mInjector.binderClearCallingIdentity(); try { - final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); - try { - IKeyChainService keyChain = keyChainConnection.getService(); - return keyChain.installKeyPair(privKey, cert, alias); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Installing certificate", e); - } finally { - keyChainConnection.close(); - } + final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); + try { + IKeyChainService keyChain = keyChainConnection.getService(); + return keyChain.installKeyPair(privKey, cert, alias); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Installing certificate", e); + } finally { + keyChainConnection.close(); + } } catch (InterruptedException e) { Log.w(LOG_TAG, "Interrupted while installing certificate", e); Thread.currentThread().interrupt(); @@ -3660,6 +3665,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } + @Override + public boolean removeKeyPair(ComponentName who, String alias) { + enforceCanManageInstalledKeys(who); + + final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); + final long id = Binder.clearCallingIdentity(); + try { + final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); + try { + IKeyChainService keyChain = keyChainConnection.getService(); + return keyChain.removeKeyPair(alias); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Removing keypair", e); + } finally { + keyChainConnection.close(); + } + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while removing keypair", e); + Thread.currentThread().interrupt(); + } finally { + Binder.restoreCallingIdentity(id); + } + return false; + } + @Override public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) {