Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec32b56c authored by Rubin Xu's avatar Rubin Xu
Browse files

Add DelegatedCertInstaller API in DPMS

Allow device/profile owner to delegate certificate APIs to third-party
certificate installer apps.

Bug: 19551274
Change-Id: Iaf9abb5ecb1dc0975fa98ea14408fe392d52fbf4
parent f2104b11
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5564,6 +5564,7 @@ package android.app.admin {
    method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
    method public boolean getAutoTimeRequired();
    method public boolean getCameraDisabled(android.content.ComponentName);
    method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
    method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
    method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
    method public int getCurrentFailedPasswordAttempts();
@@ -5612,6 +5613,7 @@ package android.app.admin {
    method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void setAutoTimeRequired(android.content.ComponentName, boolean);
    method public void setCameraDisabled(android.content.ComponentName, boolean);
    method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
    method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+2 −0
Original line number Diff line number Diff line
@@ -5659,6 +5659,7 @@ package android.app.admin {
    method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
    method public boolean getAutoTimeRequired();
    method public boolean getCameraDisabled(android.content.ComponentName);
    method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
    method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
    method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
    method public int getCurrentFailedPasswordAttempts();
@@ -5714,6 +5715,7 @@ package android.app.admin {
    method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void setAutoTimeRequired(android.content.ComponentName, boolean);
    method public void setCameraDisabled(android.content.ComponentName, boolean);
    method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
    method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+54 −5
Original line number Diff line number Diff line
@@ -1941,7 +1941,8 @@ public class DevicePolicyManager {
    /**
     * Installs the given certificate as a user CA.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
     * <code>null</code> if calling from a delegated certificate installer.
     * @param certBuffer encoded form of the certificate to install.
     *
     * @return false if the certBuffer cannot be parsed or installation is
@@ -1961,7 +1962,8 @@ public class DevicePolicyManager {
    /**
     * Uninstalls the given certificate from trusted user CAs, if present.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
     * <code>null</code> if calling from a delegated certificate installer.
     * @param certBuffer encoded form of the certificate to remove.
     */
    public void uninstallCaCert(ComponentName admin, byte[] certBuffer) {
@@ -1982,7 +1984,8 @@ public class DevicePolicyManager {
     * If a user has installed any certificates by other means than device policy these will be
     * included too.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
     * <code>null</code> if calling from a delegated certificate installer.
     * @return a List of byte[] arrays, each encoding one user CA certificate.
     */
    public List<byte[]> getInstalledCaCerts(ComponentName admin) {
@@ -2009,7 +2012,8 @@ public class DevicePolicyManager {
     * Uninstalls all custom trusted CA certificates from the profile. Certificates installed by
     * means other than device policy will also be removed, except for system CA certificates.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
     * <code>null</code> if calling from a delegated certificate installer.
     */
    public void uninstallAllUserCaCerts(ComponentName admin) {
        if (mService != null) {
@@ -2026,7 +2030,8 @@ public class DevicePolicyManager {
    /**
     * Returns whether this certificate is installed as a trusted CA.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Use
     * <code>null</code> if calling from a delegated certificate installer.
     * @param certBuffer encoded form of the certificate to look up.
     */
    public boolean hasCaCertInstalled(ComponentName admin, byte[] certBuffer) {
@@ -2082,6 +2087,50 @@ public class DevicePolicyManager {
        return new TrustedCertificateStore().getCertificateAlias(cert);
    }

    /**
     * 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
     * {@link #getInstalledCaCerts}, {@link #hasCaCertInstalled}, {@link #installCaCert},
     * {@link #uninstallCaCert} and {@link #uninstallAllUserCaCerts}.
     * <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
     * installer.
     *
     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
     * @param installerPackage The package name of the certificate installer which will be given
     * access. If <code>null</code> is given the current package will be cleared.
     */
    public void setCertInstallerPackage(ComponentName who, String installerPackage)
            throws SecurityException {
        if (mService != null) {
            try {
                mService.setCertInstallerPackage(who, installerPackage);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed talking with device policy service", e);
            }
        }
    }

    /**
     * Called by a profile owner or device owner to retrieve the certificate installer for the
     * current user. null if none is set.
     *
     * @param who Which {@link DeviceAdminReceiver} this request is associated with.
     * @return The package name of the current delegated certificate installer. <code>null</code>
     * if none is set.
     */
    public String getCertInstallerPackage(ComponentName who) throws SecurityException {
        if (mService != null) {
            try {
                return mService.getCertInstallerPackage(who);
            } catch (RemoteException e) {
                Log.w(TAG, "Failed talking with device policy service", e);
            }
        }
        return null;
    }

    /**
     * Called by an application that is administering the device to disable all cameras
     * on the device, for this user. After setting this, no applications running as this user
+3 −0
Original line number Diff line number Diff line
@@ -132,6 +132,9 @@ interface IDevicePolicyManager {
    boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias);
    void choosePrivateKeyAlias(int uid, in String host, int port, in String url, in String alias, IBinder aliasCallback);

    void setCertInstallerPackage(in ComponentName who, String installerPackage);
    String getCertInstallerPackage(in ComponentName who);

    void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
    void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);

+70 −1
Original line number Diff line number Diff line
@@ -166,6 +166,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
    private static final String ATTR_SETUP_COMPLETE = "setup-complete";

    private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";

    private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS;
    static {
        DEVICE_OWNER_USER_RESTRICTIONS = new HashSet();
@@ -286,6 +288,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

        ComponentName mRestrictionsProvider;

        String mDelegatedCertInstallerPackage;

        public DevicePolicyData(int userHandle) {
            mUserHandle = userHandle;
        }
@@ -948,6 +952,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                syncDeviceCapabilitiesLocked(policy);
                saveSettingsLocked(policy.mUserHandle);
            }

            if (policy.mDelegatedCertInstallerPackage != null &&
                    (packageName == null
                    || packageName.equals(policy.mDelegatedCertInstallerPackage))) {
                try {
                    // Check if delegated cert installer package is removed.
                    if (pm.getPackageInfo(
                            policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) {
                        policy.mDelegatedCertInstallerPackage = null;
                        saveSettingsLocked(policy.mUserHandle);
                    }
                } catch (RemoteException e) {
                    // Shouldn't happen
                }
            }
        }
    }

@@ -1332,6 +1351,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                out.attribute(null, ATTR_SETUP_COMPLETE,
                        Boolean.toString(true));
            }
            if (policy.mDelegatedCertInstallerPackage != null) {
                out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
                        policy.mDelegatedCertInstallerPackage);
            }


            final int N = policy.mAdminList.size();
            for (int i=0; i<N; i++) {
@@ -1439,6 +1463,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
                policy.mUserSetupComplete = true;
            }
            policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
                    ATTR_DELEGATED_CERT_INSTALLER);

            type = parser.next();
            int outerDepth = parser.getDepth();
@@ -2878,7 +2904,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    @Override
    public void enforceCanManageCaCerts(ComponentName who) {
        if (who == null) {
            if (!isCallerDelegatedCertInstaller()) {
                mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
            }
        } else {
            synchronized (this) {
                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -2886,6 +2914,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
    }

    private boolean isCallerDelegatedCertInstaller() {
        final int callingUid = Binder.getCallingUid();
        final int userHandle = UserHandle.getUserId(callingUid);
        synchronized (this) {
            final DevicePolicyData policy = getUserData(userHandle);
            if (policy.mDelegatedCertInstallerPackage == null) {
                return false;
            }

            try {
                int uid = mContext.getPackageManager().getPackageUid(
                        policy.mDelegatedCertInstallerPackage, userHandle);
                return uid == callingUid;
            } catch (NameNotFoundException e) {
                return false;
            }
        }
    }

    @Override
    public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
        enforceCanManageCaCerts(admin);
@@ -3036,6 +3083,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }.execute();
    }

    @Override
    public void setCertInstallerPackage(ComponentName who, String installerPackage)
            throws SecurityException {
        int userHandle = UserHandle.getCallingUserId();
        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
            DevicePolicyData policy = getUserData(userHandle);
            policy.mDelegatedCertInstallerPackage = installerPackage;
            saveSettingsLocked(userHandle);
        }
    }

    @Override
    public String getCertInstallerPackage(ComponentName who) throws SecurityException {
        int userHandle = UserHandle.getCallingUserId();
        synchronized (this) {
            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
            DevicePolicyData policy = getUserData(userHandle);
            return policy.mDelegatedCertInstallerPackage;
        }
    }

    private void wipeDataLocked(boolean wipeExtRequested, String reason) {
        // If the SD card is encrypted and non-removable, we have to force a wipe.
        boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();