diff options
5 files changed, 98 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index afacaa8881f6..fe78138c2d80 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6794,6 +6794,7 @@ package android.app.admin { method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String); method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String); method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>); + method public boolean setKeyGrantForApp(@Nullable android.content.ComponentName, @NonNull String, @NonNull String, boolean); method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean); method public boolean setKeyguardDisabled(@NonNull android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(@NonNull android.content.ComponentName, int); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 5624ba54077a..49cfd41f1773 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4981,6 +4981,42 @@ public class DevicePolicyManager { return null; } + + /** + * Called by a device or profile owner, or delegated certificate chooser (an app that has been + * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to grant an application access + * to an already-installed (or generated) KeyChain key. + * This is useful (in combination with {@link #installKeyPair} or {@link #generateKeyPair}) to + * let an application call {@link android.security.KeyChain#getPrivateKey} without having to + * call {@link android.security.KeyChain#choosePrivateKeyAlias} first. + * + * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED} + * broadcast when access to a key is granted or revoked. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The alias of the key to grant access to. + * @param packageName The name of the (already installed) package to grant access to. + * @param hasGrant Whether to grant access to the alias or revoke it. + * @return {@code true} if the grant was set successfully, {@code false} otherwise. + * + * @throws SecurityException if the caller is not a device owner, a profile owner or + * delegated certificate chooser. + * @throws IllegalArgumentException if {@code packageName} or {@code alias} are empty, or if + * {@code packageName} is not a name of an installed package. + */ + public boolean setKeyGrantForApp(@Nullable ComponentName admin, @NonNull String alias, + @NonNull String packageName, boolean hasGrant) { + throwIfParentInstance("addKeyGrant"); + try { + return mService.setKeyGrantForApp( + admin, mContext.getPackageName(), alias, packageName, hasGrant); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return false; + } + /** * Returns {@code true} if the device supports attestation of device identifiers in addition * to key attestation. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 2b9641999019..5cdef6d39dc6 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -436,4 +436,6 @@ interface IDevicePolicyManager { boolean isUnattendedManagedKiosk(); boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags); + + boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index cfa99445f45f..59996ccd5530 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -16,6 +16,7 @@ package com.android.server.devicepolicy; import android.app.admin.IDevicePolicyManager; +import android.content.ComponentName; import com.android.server.SystemService; @@ -56,4 +57,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public void clearSystemUpdatePolicyFreezePeriodRecord() { } + + public boolean setKeyGrantForApp(ComponentName admin, String callerPackage, String alias, + String packageName, boolean hasGrant) { + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ba0636963fa2..f800cca3ab3d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5727,6 +5727,59 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } + @Override + public boolean setKeyGrantForApp( + ComponentName who, String callerPackage, String alias, String packageName, + boolean hasGrant) { + enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, + DELEGATION_CERT_SELECTION); + + if (TextUtils.isEmpty(alias)) { + throw new IllegalArgumentException("Alias to grant cannot be empty."); + } + + if (TextUtils.isEmpty(packageName)) { + throw new IllegalArgumentException("Package to grant to cannot be empty."); + } + + final int userId = mInjector.userHandleGetCallingUserId(); + final int granteeUid; + try { + ApplicationInfo ai = mInjector.getIPackageManager().getApplicationInfo( + packageName, 0, userId); + if (ai == null) { + throw new IllegalArgumentException( + String.format("Provided package %s is not installed", packageName)); + } + granteeUid = ai.uid; + } catch (RemoteException e) { + throw new IllegalStateException("Failure getting grantee uid", e); + } + + final int callingUid = mInjector.binderGetCallingUid(); + final long id = mInjector.binderClearCallingIdentity(); + try { + final KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid)); + try { + IKeyChainService keyChain = keyChainConnection.getService(); + keyChain.setGrant(granteeUid, alias, hasGrant); + return true; + } catch (RemoteException e) { + Log.e(LOG_TAG, "Setting grant for package.", e); + return false; + } finally { + keyChainConnection.close(); + } + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while setting key grant", e); + Thread.currentThread().interrupt(); + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + return false; + } + /** * Enforce one the following conditions are met: * (1) The device has a Device Owner, and one of the following holds: |