Grant cert installer access to installKeyPair()

Bug: 20041977
Change-Id: Id0dc0bce8461c71d7220c1802dcca82933805996
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index cf6619f..d2842af 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2156,7 +2156,8 @@
      * Called by a device or profile owner to install a certificate and private key pair. The
      * keypair will be visible to all apps within the profile.
      *
-     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with. Use
+     * <code>null</code> if calling from a delegated certificate installer.
      * @param privKey The private key to install.
      * @param cert The certificate to install.
      * @param alias The private key alias under which to install the certificate. If a certificate
@@ -2193,9 +2194,9 @@
 
     /**
      * Called by a profile owner or device owner to grant access to privileged certificate
-     * manipulation APIs to a third-party CA certificate installer app. Granted APIs include
+     * manipulation APIs to a third-party certificate installer app. Granted APIs include
      * {@link #getInstalledCaCerts}, {@link #hasCaCertInstalled}, {@link #installCaCert},
-     * {@link #uninstallCaCert} and {@link #uninstallAllUserCaCerts}.
+     * {@link #uninstallCaCert}, {@link #uninstallAllUserCaCerts} and {@link #installKeyPair}.
      * <p>
      * Delegated certificate installer is a per-user state. The delegated access is persistent until
      * it is later cleared by calling this method with a null value or uninstallling the certificate
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 73b5de1..9637f41 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3016,9 +3016,14 @@
 
     @Override
     public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
-        Preconditions.checkNotNull(who, "ComponentName is null");
-        synchronized (this) {
-            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        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);
+            }
         }
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
         final long id = Binder.clearCallingIdentity();