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

Commit 19d19048 authored by Eran Messeri's avatar Eran Messeri
Browse files

DevicePolicyManager: Make installed keys user-selectable by default.

After Change-Id: Ibaba2ddd4f94fced1a2a7bfcfb91189302ec7f3a was merged,
KeyChain, by default, made keys installed in it not user-selectable,
which means users could not choose those keys in the Certificate
Selection prompt.
This is the correct behaviour (secure by default), but means the
DevicePolicyManager has to explicitly set keys as user-selectable
to be compatible with the previous behaviour.

This CL does the following:
* Adding an installKeyPair variant to the DevicePolicyManager to
  allow specifying user-selectability of the key.
* Make old installKeyPair variants delegate to the new variant,
  with the default of setting installed keys user-selectable.
* Modify the DevicePolicyManager service definition and service to
  take the extra user-selectability parameter and set the value
  in KeyChain.

Note that the reason the CTS test started failing is not related to
this change but a CTS Verifier test should catch the problem this
CL is solving.

Part of the fix for b/69337278

Bug: 69337278
Test: cts-tradefed run commandAndExit cts-dev -a armeabi-v7a -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement
Change-Id: Ifc240ed4a20a9d00bc6140dfb45bd1140e1f8260
parent 5f52b4df
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6371,6 +6371,7 @@ package android.app.admin {
    method public boolean installCaCert(android.content.ComponentName, byte[]);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean);
    method public boolean isActivePasswordSufficient();
    method public boolean isAdminActive(android.content.ComponentName);
    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+1 −0
Original line number Diff line number Diff line
@@ -6599,6 +6599,7 @@ package android.app.admin {
    method public boolean installCaCert(android.content.ComponentName, byte[]);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean);
    method public boolean isActivePasswordSufficient();
    method public boolean isAdminActive(android.content.ComponentName);
    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+1 −0
Original line number Diff line number Diff line
@@ -6440,6 +6440,7 @@ package android.app.admin {
    method public boolean installCaCert(android.content.ComponentName, byte[]);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean);
    method public boolean isActivePasswordSufficient();
    method public boolean isAdminActive(android.content.ComponentName);
    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+42 −1
Original line number Diff line number Diff line
@@ -3858,6 +3858,47 @@ public class DevicePolicyManager {
     */
    public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
            @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
        return installKeyPair(admin, privKey, certs, alias, requestAccess, true);
    }

    /**
     * Called by a device or profile owner, or delegated certificate installer, to install a
     * certificate chain and corresponding private key for the leaf certificate. All apps within the
     * profile will be able to access the certificate chain and use the private key, given direct
     * user approval (if the user is allowed to select the private key).
     *
     * <p>The caller of this API may grant itself access to the certificate and private key
     * immediately, without user approval. It is a best practice not to request this unless strictly
     * necessary since it opens up additional security vulnerabilities.
     *
     * <p>Whether this key is offered to the user for approval at all or not depends on the
     * {@code isUserSelectable} parameter.
     *
     * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
     *        {@code null} if calling from a delegated certificate installer.
     * @param privKey The private key to install.
     * @param certs The certificate chain to install. The chain should start with the leaf
     *        certificate and include the chain of trust in order. This will be returned by
     *        {@link android.security.KeyChain#getCertificateChain}.
     * @param alias The private key alias under which to install the certificate. If a certificate
     *        with that alias already exists, it will be overwritten.
     * @param requestAccess {@code true} to request that the calling app be granted access to the
     *        credentials immediately. Otherwise, access to the credentials will be gated by user
     *        approval.
     * @param isUserSelectable {@code true} to indicate that a user can select this key via the
     *        Certificate Selection prompt, false to indicate that this key can only be granted
     *        access by implementing
     *        {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}.
     * @return {@code true} if the keys were installed, {@code false} otherwise.
     * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
     *         owner.
     * @see android.security.KeyChain#getCertificateChain
     * @see #setDelegatedScopes
     * @see #DELEGATION_CERT_INSTALL
     */
    public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
            @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess,
            boolean isUserSelectable) {
        throwIfParentInstance("installKeyPair");
        try {
            final byte[] pemCert = Credentials.convertToPem(certs[0]);
@@ -3868,7 +3909,7 @@ public class DevicePolicyManager {
            final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
                    .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
            return mService.installKeyPair(admin, mContext.getPackageName(), pkcs8Key, pemCert,
                    pemChain, alias, requestAccess);
                    pemChain, alias, requestAccess, isUserSelectable);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+2 −1
Original line number Diff line number Diff line
@@ -162,7 +162,8 @@ interface IDevicePolicyManager {
    boolean isCaCertApproved(in String alias, int userHandle);

    boolean installKeyPair(in ComponentName who, in String callerPackage, in byte[] privKeyBuffer,
            in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess);
            in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess,
            boolean isUserSelectable);
    boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias);
    void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback);

Loading