summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java36
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java53
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: