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

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

Merge "Add escrow token APIs to TrustAgentService Security review: b/31273740...

Merge "Add escrow token APIs to TrustAgentService Security review: b/31273740 Design doc: go/auto_login Test: manual Change-Id: Ib11d4146135a58f1dc451ae8e081977a8f8e6ace"
parents edb88a2b 93a145f6
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -39861,20 +39861,29 @@ package android.service.trust {
  public class TrustAgentService extends android.app.Service {
    ctor public TrustAgentService();
    method public final void addEscrowToken(byte[], android.os.UserHandle);
    method public final deprecated void grantTrust(java.lang.CharSequence, long, boolean);
    method public final void grantTrust(java.lang.CharSequence, long, int);
    method public final void isEscrowTokenActive(long, android.os.UserHandle);
    method public final android.os.IBinder onBind(android.content.Intent);
    method public boolean onConfigure(java.util.List<android.os.PersistableBundle>);
    method public void onDeviceLocked();
    method public void onDeviceUnlockLockout(long);
    method public void onDeviceUnlocked();
    method public void onEscrowTokenAdded(byte[], long, android.os.UserHandle);
    method public void onEscrowTokenRemoved(long, boolean);
    method public void onEscrowTokenStateReceived(long, int);
    method public void onTrustTimeout();
    method public void onUnlockAttempt(boolean);
    method public final void removeEscrowToken(long, android.os.UserHandle);
    method public final void revokeTrust();
    method public final void setManagingTrust(boolean);
    method public final void unlockUserWithToken(long, byte[], android.os.UserHandle);
    field public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 2; // 0x2
    field public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1; // 0x1
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
    field public static final int TOKEN_STATE_ACTIVE = 1; // 0x1
    field public static final int TOKEN_STATE_INACTIVE = 0; // 0x0
    field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
  }
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package android.service.trust;

import android.os.PersistableBundle;
import android.os.UserHandle;
import android.service.trust.ITrustAgentServiceCallback;

/**
@@ -30,4 +31,7 @@ interface ITrustAgentService {
    oneway void onDeviceUnlocked();
    oneway void onConfigure(in List<PersistableBundle> options, IBinder token);
    oneway void setCallback(ITrustAgentServiceCallback callback);
    oneway void onEscrowTokenAdded(in byte[] token, long handle, in UserHandle user);
    oneway void onTokenStateReceived(long handle, int tokenState);
    oneway void onEscrowTokenRemoved(long handle, boolean successful);
}
+4 −0
Original line number Diff line number Diff line
@@ -28,4 +28,8 @@ oneway interface ITrustAgentServiceCallback {
    void revokeTrust();
    void setManagingTrust(boolean managingTrust);
    void onConfigureCompleted(boolean result, IBinder token);
    void addEscrowToken(in byte[] token, int userId);
    void isEscrowTokenActive(long handle, int userId);
    void removeEscrowToken(long handle, int userId);
    void unlockUserWithToken(long handle, in byte[] token, int userId);
}
+217 −5
Original line number Diff line number Diff line
@@ -23,16 +23,20 @@ import android.annotation.SystemApi;
import android.app.Service;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.util.Slog;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
@@ -118,13 +122,44 @@ public class TrustAgentService extends Service {
    public @interface GrantTrustFlags {}


    /**
     * Int enum indicating that escrow token is active.
     * See {@link #onEscrowTokenStateReceived(long, int)}
     *
     */
    public static final int TOKEN_STATE_ACTIVE = 1;

    /**
     * Int enum indicating that escow token is inactive.
     * See {@link #onEscrowTokenStateReceived(long, int)}
     *
     */
    public static final int TOKEN_STATE_INACTIVE = 0;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true,
            value = {
                TOKEN_STATE_ACTIVE,
                TOKEN_STATE_INACTIVE,
            })
    public @interface TokenState {}

    private static final int MSG_UNLOCK_ATTEMPT = 1;
    private static final int MSG_CONFIGURE = 2;
    private static final int MSG_TRUST_TIMEOUT = 3;
    private static final int MSG_DEVICE_LOCKED = 4;
    private static final int MSG_DEVICE_UNLOCKED = 5;
    private static final int MSG_UNLOCK_LOCKOUT = 6;

    private static final int MSG_ESCROW_TOKEN_ADDED = 7;
    private static final int MSG_ESCROW_TOKEN_STATE_RECEIVED = 8;
    private static final int MSG_ESCROW_TOKEN_REMOVED = 9;

    private static final String EXTRA_TOKEN = "token";
    private static final String EXTRA_TOKEN_HANDLE = "token_handle";
    private static final String EXTRA_USER_HANDLE = "user_handle";
    private static final String EXTRA_TOKEN_STATE = "token_state";
    private static final String EXTRA_TOKEN_REMOVED_RESULT = "token_removed_result";
    /**
     * Class containing raw data for a given configuration request.
     */
@@ -155,7 +190,7 @@ public class TrustAgentService extends Service {
                case MSG_UNLOCK_LOCKOUT:
                    onDeviceUnlockLockout(msg.arg1);
                    break;
                case MSG_CONFIGURE:
                case MSG_CONFIGURE: {
                    ConfigurationData data = (ConfigurationData) msg.obj;
                    boolean result = onConfigure(data.options);
                    if (data.token != null) {
@@ -168,6 +203,7 @@ public class TrustAgentService extends Service {
                        }
                    }
                    break;
                }
                case MSG_TRUST_TIMEOUT:
                    onTrustTimeout();
                    break;
@@ -177,6 +213,28 @@ public class TrustAgentService extends Service {
                case MSG_DEVICE_UNLOCKED:
                    onDeviceUnlocked();
                    break;
                case MSG_ESCROW_TOKEN_ADDED: {
                    Bundle data = msg.getData();
                    byte[] token = data.getByteArray(EXTRA_TOKEN);
                    long handle = data.getLong(EXTRA_TOKEN_HANDLE);
                    UserHandle user = (UserHandle) data.getParcelable(EXTRA_USER_HANDLE);
                    onEscrowTokenAdded(token, handle, user);
                    break;
                }
                case MSG_ESCROW_TOKEN_STATE_RECEIVED: {
                    Bundle data = msg.getData();
                    long handle = data.getLong(EXTRA_TOKEN_HANDLE);
                    int tokenState = data.getInt(EXTRA_TOKEN_STATE, TOKEN_STATE_INACTIVE);
                    onEscrowTokenStateReceived(handle, tokenState);
                    break;
                }
                case MSG_ESCROW_TOKEN_REMOVED: {
                    Bundle data = msg.getData();
                    long handle = data.getLong(EXTRA_TOKEN_HANDLE);
                    boolean success = data.getBoolean(EXTRA_TOKEN_REMOVED_RESULT);
                    onEscrowTokenRemoved(handle, success);
                    break;
                }
            }
        }
    };
@@ -245,6 +303,38 @@ public class TrustAgentService extends Service {
    public void onDeviceUnlockLockout(long timeoutMs) {
    }

  /**
     * Called when an escrow token is added for user userId.
     *
     * @param token the added token
     * @param handle the handle to the corresponding internal synthetic password. A user is unlocked
     * by presenting both handle and escrow token.
     * @param user the user to which the escrow token is added.
     *
     */
    public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) {
    }

    /**
     * Called when an escrow token state is received upon request.
     *
     * @param handle the handle to the internal synthetic password.
     * @param state the state of the requested escrow token, see {@link TokenState}.
     *
     */
    public void onEscrowTokenStateReceived(long handle, @TokenState int tokenState) {
    }

    /**
     * Called when an escrow token is removed.
     *
     * @param handle the handle to the removed the synthetic password.
     * @param successful whether the removing operaiton is achieved.
     *
     */
    public void onEscrowTokenRemoved(long handle, boolean successful) {
    }

    private void onError(String msg) {
        Slog.v(TAG, "Remote exception while " + msg);
    }
@@ -257,7 +347,7 @@ public class TrustAgentService extends Service {
     * <p>Agents that support configuration options should overload this method and return 'true'.
     *
     * @param options The aggregated list of options or an empty list if no restrictions apply.
     * @return true if the {@link TrustAgentService} supports configuration options.
     * @return true if the {@link } supports configuration options.
     */
    public boolean onConfigure(List<PersistableBundle> options) {
        return false;
@@ -373,6 +463,106 @@ public class TrustAgentService extends Service {
        }
    }

    /**
     * Call to add an escrow token to derive a synthetic password. A synthetic password is an
     * alternaive to the user-set password/pin/pattern in order to unlock encrypted disk. An escrow
     * token can be taken and internally derive the synthetic password. The new added token will not
     * be acivated until the user input the correct PIN/Passcode/Password once.
     *
     * Result will be return by callback {@link #onEscrowTokenAdded(long, int)}
     *
     * @param token an escrow token of high entropy.
     * @param user the user which the escrow token will be added to.
     *
     */
    public final void addEscrowToken(byte[] token, UserHandle user) {
        synchronized (mLock) {
            if (mCallback == null) {
                Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework");
                throw new IllegalStateException("Trust agent is not connected");
            }
            try {
                mCallback.addEscrowToken(token, user.getIdentifier());
            } catch (RemoteException e) {
                onError("calling addEscrowToken");
            }
        }
    }

    /**
     * Call to check the active state of an escrow token.
     *
     * Result will be return in callback {@link #onEscrowTokenStateReceived(long, boolean)}
     *
     * @param handle the handle of escrow token to the internal synthetic password.
     * @param user the user which the escrow token is added to.
     *
     */
    public final void isEscrowTokenActive(long handle, UserHandle user) {
        synchronized (mLock) {
            if (mCallback == null) {
                Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework");
                throw new IllegalStateException("Trust agent is not connected");
            }
            try {
                mCallback.isEscrowTokenActive(handle, user.getIdentifier());
            } catch (RemoteException e) {
                onError("calling isEscrowTokenActive");
            }
        }
    }

    /**
     * Call to remove the escrow token.
     *
     * Result will be return in callback {@link #onEscrowTokenRemoved(long, boolean)}
     *
     * @param handle the handle of escrow tokent to the internal synthetic password.
     * @param user the user id which the escrow token is added to.
     *
     */
    public final void removeEscrowToken(long handle, UserHandle user) {
        synchronized (mLock) {
            if (mCallback == null) {
                Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework");
                throw new IllegalStateException("Trust agent is not connected");
            }
            try {
                mCallback.removeEscrowToken(handle, user.getIdentifier());
            } catch (RemoteException e) {
                onError("callling removeEscrowToken");
            }
        }
    }

    /**
     * Call to unlock user's FBE.
     *
     * @param handle the handle of escrow tokent to the internal synthetic password.
     * @param token the escrow token
     * @param user the user about to be unlocked.
     *
     */
    public final void unlockUserWithToken(long handle, byte[] token, UserHandle user) {
        UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
        if (um.isUserUnlocked()) {
            Slog.i(TAG, "User already unlocked");
            return;
        }

        synchronized (mLock) {
            if (mCallback == null) {
                Slog.w(TAG, "Cannot add escrow token if the agent is not connecting to framework");
                throw new IllegalStateException("Trust agent is not connected");
            }
            try {
                mCallback.unlockUserWithToken(handle, token, user.getIdentifier());
            } catch (RemoteException e) {
                onError("calling unlockUserWithToken");
            }
        }
    }

    @Override
    public final IBinder onBind(Intent intent) {
        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
@@ -430,6 +620,28 @@ public class TrustAgentService extends Service {
                }
            }
        }

        @Override
        public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) {
            Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_ADDED);
            msg.getData().putByteArray(EXTRA_TOKEN, token);
            msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle);
            msg.getData().putParcelable(EXTRA_USER_HANDLE, user);
            msg.sendToTarget();
        }

        public void onTokenStateReceived(long handle, int tokenState) {
            Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_STATE_RECEIVED);
            msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle);
            msg.getData().putInt(EXTRA_TOKEN_STATE, tokenState);
            msg.sendToTarget();
        }

        public void onEscrowTokenRemoved(long handle, boolean successful) {
            Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_REMOVED);
            msg.getData().putLong(EXTRA_TOKEN_HANDLE, handle);
            msg.getData().putBoolean(EXTRA_TOKEN_REMOVED_RESULT, successful);
            msg.sendToTarget();
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -2751,4 +2751,13 @@
         without explicit consent of the user. If no accessibility service with the specified name
         exists on the device, the accessibility shortcut will be disabled by default. -->
    <string name="config_defaultAccessibilityService" translatable="false"></string>

    <!-- Flag indicates that whether escrow token API is enabled for TrustAgent -->
    <!-- Warning: This API can be dangerous when not implemented properly. In particular,
         escrow token must NOT be retrievable from device storage. In other words, either
         escrow token is not stored on device or its ciphertext is stored on device while
         the decryption key is not. Before enabling this feature, please ensure you've read
         and followed the pertinent sections of the escrow tokens section of the CDD <link>-->
    <!-- TODO(b/35230407) complete the link field -->
    <bool name="config_allowEscrowTokenForTrustAgent">false</bool>
</resources>
Loading