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

Commit 8b5ca97a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add API for checking which CA certs were installed by the DO/PO"

parents dc4115ba 05dc9f76
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6266,6 +6266,7 @@ package android.app.admin {
    method public long getMaximumTimeToLock(android.content.ComponentName);
    method public int getOrganizationColor(android.content.ComponentName);
    method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
    method public java.util.List<java.lang.String> getOwnerInstalledCaCerts(android.os.UserHandle);
    method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
    method public long getPasswordExpiration(android.content.ComponentName);
    method public long getPasswordExpirationTimeout(android.content.ComponentName);
+24 −0
Original line number Diff line number Diff line
@@ -7958,4 +7958,28 @@ public class DevicePolicyManager {
            throw re.rethrowFromSystemServer();
        }
    }


    /**
     * Called by the system to get a list of CA certificates that were installed by the device or
     * profile owner.
     *
     * <p> The caller must be the target user's Device Owner/Profile owner or hold the
     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
     *
     * @param user The user for whom to retrieve information.
     * @return list of aliases identifying CA certificates installed by the device or profile owner
     * @throws SecurityException if the caller does not have permission to retrieve information
     *         about the given user's CA certificates.
     *
     * @hide
     */
    @TestApi
    public List<String> getOwnerInstalledCaCerts(@NonNull UserHandle user) {
        try {
            return mService.getOwnerInstalledCaCerts(user).getList();
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
import android.content.pm.StringParceledListSlice;
import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -349,4 +350,5 @@ interface IDevicePolicyManager {
    boolean resetPasswordWithToken(in ComponentName admin, String password, in byte[] token, int flags);

    boolean isDefaultInputMethodSetByOwner(in UserHandle user);
    StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
}
+2 −2
Original line number Diff line number Diff line
@@ -29,8 +29,8 @@ interface IKeyChainService {
    byte[] getCertificate(String alias);
    byte[] getCaCertificates(String alias);

    // APIs used by CertInstaller
    void installCaCertificate(in byte[] caCertificate);
    // APIs used by CertInstaller and DevicePolicyManager
    String installCaCertificate(in byte[] caCertificate);

    // APIs used by DevicePolicyManager
    boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
+105 −21
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.StringParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -166,6 +167,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -243,10 +245,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

    private static final String TAG_DEFAULT_INPUT_METHOD_SET = "default-ime-set";

    private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert";

    private static final String ATTR_ID = "id";

    private static final String ATTR_VALUE = "value";

    private static final String ATTR_ALIAS = "alias";

    private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle";

    private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token";
@@ -480,6 +486,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
        final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();

        // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
        final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>();

        // This is the list of component allowed to start lock task mode.
@@ -504,6 +511,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {

        boolean mDefaultInputMethodSet = false;

        // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead.
        Set<String> mOwnerInstalledCaCerts = new ArraySet<>();

        // Used for initialization of users created by createAndManageUsers.
        boolean mAdminBroadcastPending = false;
        PersistableBundle mInitBundle = null;
@@ -518,6 +528,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();

    final Handler mHandler;
    final Handler mBackgroundHandler;

    /** Listens on any device, even when mHasFeature == false. */
    final BroadcastReceiver mRootCaReceiver = new BroadcastReceiver() {
@@ -619,6 +630,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle);
            } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) {
                clearWipeProfileNotification();
            } else if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) {
                mBackgroundHandler.post(() ->  {
                    try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                            UserHandle.of(userHandle))) {
                        final List<String> caCerts =
                                keyChainConnection.getService().getUserCaAliases().getList();
                        synchronized (DevicePolicyManagerService.this) {
                            if (getUserData(userHandle).mOwnerInstalledCaCerts
                                    .retainAll(caCerts)) {
                                saveSettingsLocked(userHandle);
                            }
                        }
                    } catch (InterruptedException e) {
                        Slog.w(LOG_TAG, "error talking to IKeyChainService", e);
                        Thread.currentThread().interrupt();
                    } catch (RemoteException e) {
                        Slog.w(LOG_TAG, "error talking to IKeyChainService", e);
                    }
                });
            }
        }

@@ -1786,6 +1816,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
        mIsWatch = mInjector.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_WATCH);
        mBackgroundHandler = BackgroundThread.getHandler();

        // Broadcast filter for changes to the trusted certificate store. These changes get a
        // separate intent filter so we can listen to them even when device_admin is off.
@@ -1807,6 +1838,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        filter.addAction(Intent.ACTION_USER_ADDED);
        filter.addAction(Intent.ACTION_USER_REMOVED);
        filter.addAction(Intent.ACTION_USER_STARTED);
        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
        filter = new IntentFilter();
@@ -2580,6 +2612,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                out.endTag(null, TAG_DEFAULT_INPUT_METHOD_SET);
            }

            for (final String cert : policy.mOwnerInstalledCaCerts) {
                out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT);
                out.attribute(null, ATTR_ALIAS, cert);
                out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT);
            }

            out.endTag(null, "policies");

            out.endDocument();
@@ -2696,6 +2734,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            policy.mAdminList.clear();
            policy.mAdminMap.clear();
            policy.mAffiliationIds.clear();
            policy.mOwnerInstalledCaCerts.clear();
            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                   && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -2791,6 +2830,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                            parser.getAttributeValue(null, ATTR_VALUE));
                } else if (TAG_DEFAULT_INPUT_METHOD_SET.equals(tag)) {
                    policy.mDefaultInputMethodSet = true;
                } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) {
                    policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS));
                } else {
                    Slog.w(LOG_TAG, "Unknown tag: " + tag);
                    XmlUtils.skipCurrentTag(parser);
@@ -4691,17 +4732,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            return false;
        }

        final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
        final UserHandle userHandle = UserHandle.of(mInjector.userHandleGetCallingUserId());
        final long id = mInjector.binderClearCallingIdentity();
        String alias = null;
        try {
            final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
            try {
                keyChainConnection.getService().installCaCertificate(pemCert);
                return true;
            try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                    userHandle)) {
                alias = keyChainConnection.getService().installCaCertificate(pemCert);
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
            } finally {
                keyChainConnection.close();
            }
        } catch (InterruptedException e1) {
            Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
@@ -4709,6 +4748,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
        if (alias == null) {
            Log.w(LOG_TAG, "Problem installing cert");
        } else {
            synchronized (this) {
                final int userId = userHandle.getIdentifier();
                getUserData(userId).mOwnerInstalledCaCerts.add(alias);
                saveSettingsLocked(userId);
            }
            return true;
        }
        return false;
    }

@@ -4722,25 +4771,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    public void uninstallCaCerts(ComponentName admin, String callerPackage, String[] aliases) {
        enforceCanManageCaCerts(admin, callerPackage);

        final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
        final int userId = mInjector.userHandleGetCallingUserId();
        final UserHandle userHandle = UserHandle.of(userId);
        final long id = mInjector.binderClearCallingIdentity();
        try {
            final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
            try {
            try (final KeyChainConnection keyChainConnection = mInjector.keyChainBindAsUser(
                    userHandle)) {
                for (int i = 0 ; i < aliases.length; i++) {
                    keyChainConnection.getService().deleteCaCertificate(aliases[i]);
                }
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
            } finally {
                keyChainConnection.close();
                return;
            }
        } catch (InterruptedException ie) {
            Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
            Thread.currentThread().interrupt();
            return;
        } finally {
            mInjector.binderRestoreCallingIdentity(id);
        }
        synchronized (this) {
            if (getUserData(userId).mOwnerInstalledCaCerts.removeAll(Arrays.asList(aliases))) {
                saveSettingsLocked(userId);
            }
        }
    }

    @Override
@@ -6731,6 +6786,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        final DevicePolicyData policyData = getUserData(userId);
        policyData.mDefaultInputMethodSet = false;
        policyData.mOwnerInstalledCaCerts.clear();
        saveSettingsLocked(userId);
        clearUserPoliciesLocked(userId);
        mOwners.removeProfileOwner(userId);
@@ -7127,27 +7183,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
    }

    private void enforceFullCrossUsersPermission(int userHandle) {
        enforceSystemUserOrPermission(userHandle,
        enforceSystemUserOrPermissionIfCrossUser(userHandle,
                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
    }

    private void enforceCrossUsersPermission(int userHandle) {
        enforceSystemUserOrPermission(userHandle,
        enforceSystemUserOrPermissionIfCrossUser(userHandle,
                android.Manifest.permission.INTERACT_ACROSS_USERS);
    }

    private void enforceSystemUserOrPermission(int userHandle, String permission) {
    private void enforceSystemUserOrPermission(String permission) {
        if (!(isCallerWithSystemUid() || mInjector.binderGetCallingUid() == Process.ROOT_UID)) {
            mContext.enforceCallingOrSelfPermission(permission,
                    "Must be system or have " + permission + " permission");
        }
    }

    private void enforceSystemUserOrPermissionIfCrossUser(int userHandle, String permission) {
        if (userHandle < 0) {
            throw new IllegalArgumentException("Invalid userId " + userHandle);
        }
        final int callingUid = mInjector.binderGetCallingUid();
        if (userHandle == UserHandle.getUserId(callingUid)) {
        if (userHandle == mInjector.userHandleGetCallingUserId()) {
            return;
        }
        if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) {
            mContext.enforceCallingOrSelfPermission(permission,
                    "Must be system or have " + permission + " permission");
        }
        enforceSystemUserOrPermission(permission);
    }

    private void enforceManagedProfile(int userHandle, String message) {
@@ -7184,6 +7243,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                "Only profile owner, device owner and system may call this method.");
    }

    private void enforceProfileOwnerOrFullCrossUsersPermission(int userId) {
        if (userId == mInjector.userHandleGetCallingUserId()) {
            synchronized (this) {
                if (getActiveAdminWithPolicyForUidLocked(null,
                        DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid())
                                != null) {
                    // Device Owner/Profile Owner may access the user it runs on.
                    return;
                }
            }
        }
        // Otherwise, INTERACT_ACROSS_USERS_FULL permission, system UID or root UID is required.
        enforceSystemUserOrPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
    }

    private void ensureCallerPackage(@Nullable String packageName) {
        if (packageName == null) {
            Preconditions.checkState(isCallerWithSystemUid(),
@@ -10897,4 +10971,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        }
        return getUserData(userId).mDefaultInputMethodSet;
    }

    @Override
    public StringParceledListSlice getOwnerInstalledCaCerts(@NonNull UserHandle user) {
        final int userId = user.getIdentifier();
        enforceProfileOwnerOrFullCrossUsersPermission(userId);
        synchronized (this) {
            return new StringParceledListSlice(
                    new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts));
        }
    }
}
Loading