1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.trust;
18
19import android.annotation.TargetApi;
20import android.app.AlarmManager;
21import android.app.PendingIntent;
22import android.app.admin.DevicePolicyManager;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.ServiceConnection;
29import android.net.Uri;
30import android.os.Binder;
31import android.os.Build;
32import android.os.Handler;
33import android.os.IBinder;
34import android.os.Message;
35import android.os.PatternMatcher;
36import android.os.PersistableBundle;
37import android.os.RemoteException;
38import android.os.SystemClock;
39import android.os.UserHandle;
40import android.service.trust.ITrustAgentService;
41import android.service.trust.ITrustAgentServiceCallback;
42import android.service.trust.TrustAgentService;
43import android.util.Log;
44import android.util.Slog;
45import java.util.Collections;
46import java.util.List;
47
48/**
49 * A wrapper around a TrustAgentService interface. Coordinates communication between
50 * TrustManager and the actual TrustAgent.
51 */
52@TargetApi(Build.VERSION_CODES.LOLLIPOP)
53public class TrustAgentWrapper {
54    private static final String EXTRA_COMPONENT_NAME = "componentName";
55    private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
56    private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT;
57    private static final boolean DEBUG = TrustManagerService.DEBUG;
58    private static final String TAG = "TrustAgentWrapper";
59
60    private static final int MSG_GRANT_TRUST = 1;
61    private static final int MSG_REVOKE_TRUST = 2;
62    private static final int MSG_TRUST_TIMEOUT = 3;
63    private static final int MSG_RESTART_TIMEOUT = 4;
64    private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5;
65    private static final int MSG_MANAGING_TRUST = 6;
66    private static final int MSG_ADD_ESCROW_TOKEN = 7;
67    private static final int MSG_REMOVE_ESCROW_TOKEN = 8;
68    private static final int MSG_ESCROW_TOKEN_STATE = 9;
69    private static final int MSG_UNLOCK_USER = 10;
70
71    /**
72     * Time in uptime millis that we wait for the service connection, both when starting
73     * and when the service disconnects.
74     */
75    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
76
77    /**
78     * Long extra for {@link #MSG_GRANT_TRUST}
79     */
80    private static final String DATA_DURATION = "duration";
81    private static final String DATA_ESCROW_TOKEN = "escrow_token";
82    private static final String DATA_HANDLE = "handle";
83    private static final String DATA_USER_ID = "user_id";
84
85    private final TrustManagerService mTrustManagerService;
86    private final int mUserId;
87    private final Context mContext;
88    private final ComponentName mName;
89
90    private ITrustAgentService mTrustAgentService;
91    private boolean mBound;
92    private long mScheduledRestartUptimeMillis;
93    private long mMaximumTimeToLock; // from DevicePolicyManager
94    private boolean mPendingSuccessfulUnlock = false;
95
96    // Trust state
97    private boolean mTrusted;
98    private CharSequence mMessage;
99    private boolean mTrustDisabledByDpm;
100    private boolean mManagingTrust;
101    private IBinder mSetTrustAgentFeaturesToken;
102    private AlarmManager mAlarmManager;
103    private final Intent mAlarmIntent;
104    private PendingIntent mAlarmPendingIntent;
105
106    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
107        @Override
108        public void onReceive(Context context, Intent intent) {
109            ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
110            if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
111                    && mName.equals(component)) {
112                mHandler.removeMessages(MSG_TRUST_TIMEOUT);
113                mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
114            }
115        }
116    };
117
118    private final Handler mHandler = new Handler() {
119        @Override
120        public void handleMessage(Message msg) {
121            switch (msg.what) {
122                case MSG_GRANT_TRUST:
123                    if (!isConnected()) {
124                        Log.w(TAG, "Agent is not connected, cannot grant trust: "
125                                + mName.flattenToShortString());
126                        return;
127                    }
128                    mTrusted = true;
129                    mMessage = (CharSequence) msg.obj;
130                    int flags = msg.arg1;
131                    long durationMs = msg.getData().getLong(DATA_DURATION);
132                    if (durationMs > 0) {
133                        final long duration;
134                        if (mMaximumTimeToLock != 0) {
135                            // Enforce DevicePolicyManager timeout.  This is here as a safeguard to
136                            // ensure trust agents are evaluating trust state at least as often as
137                            // the policy dictates. Admins that want more guarantees should be using
138                            // DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS.
139                            duration = Math.min(durationMs, mMaximumTimeToLock);
140                            if (DEBUG) {
141                                Slog.d(TAG, "DPM lock timeout in effect. Timeout adjusted from "
142                                    + durationMs + " to " + duration);
143                            }
144                        } else {
145                            duration = durationMs;
146                        }
147                        long expiration = SystemClock.elapsedRealtime() + duration;
148                        mAlarmPendingIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
149                                PendingIntent.FLAG_CANCEL_CURRENT);
150                        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration,
151                                mAlarmPendingIntent);
152                    }
153                    mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
154                            (mMessage != null ? mMessage.toString() : null),
155                            durationMs, flags);
156                    mTrustManagerService.updateTrust(mUserId, flags);
157                    break;
158                case MSG_TRUST_TIMEOUT:
159                    if (DEBUG) Slog.d(TAG, "Trust timed out : " + mName.flattenToShortString());
160                    mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
161                    onTrustTimeout();
162                    // Fall through.
163                case MSG_REVOKE_TRUST:
164                    mTrusted = false;
165                    mMessage = null;
166                    mHandler.removeMessages(MSG_TRUST_TIMEOUT);
167                    if (msg.what == MSG_REVOKE_TRUST) {
168                        mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
169                    }
170                    mTrustManagerService.updateTrust(mUserId, 0);
171                    break;
172                case MSG_RESTART_TIMEOUT:
173                    Slog.w(TAG, "Connection attempt to agent " + mName.flattenToShortString()
174                            + " timed out, rebinding");
175                    destroy();
176                    mTrustManagerService.resetAgent(mName, mUserId);
177                    break;
178                case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
179                    IBinder token = (IBinder) msg.obj;
180                    boolean result = msg.arg1 != 0;
181                    if (mSetTrustAgentFeaturesToken == token) {
182                        mSetTrustAgentFeaturesToken = null;
183                        if (mTrustDisabledByDpm && result) {
184                            if (DEBUG) Slog.d(TAG, "Re-enabling agent because it acknowledged "
185                                    + "enabled features: " + mName.flattenToShortString());
186                            mTrustDisabledByDpm = false;
187                            mTrustManagerService.updateTrust(mUserId, 0);
188                        }
189                    } else {
190                        if (DEBUG) Slog.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
191                                + "with obsolete token: " + mName.flattenToShortString());
192                    }
193                    break;
194                case MSG_MANAGING_TRUST:
195                    mManagingTrust = msg.arg1 != 0;
196                    if (!mManagingTrust) {
197                        mTrusted = false;
198                        mMessage = null;
199                    }
200                    mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
201                    mTrustManagerService.updateTrust(mUserId, 0);
202                    break;
203                case MSG_ADD_ESCROW_TOKEN: {
204                    byte[] eToken = msg.getData().getByteArray(DATA_ESCROW_TOKEN);
205                    int userId = msg.getData().getInt(DATA_USER_ID);
206                    long handle = mTrustManagerService.addEscrowToken(eToken, userId);
207                    boolean resultDeliverred = false;
208                    try {
209                        if (mTrustAgentService != null) {
210                            mTrustAgentService.onEscrowTokenAdded(
211                                    eToken, handle, UserHandle.of(userId));
212                            resultDeliverred = true;
213                        }
214                    } catch (RemoteException e) {
215                        onError(e);
216                    }
217
218                    if (!resultDeliverred) {
219                        mTrustManagerService.removeEscrowToken(handle, userId);
220                    }
221                    break;
222                }
223                case MSG_ESCROW_TOKEN_STATE: {
224                    long handle = msg.getData().getLong(DATA_HANDLE);
225                    int userId = msg.getData().getInt(DATA_USER_ID);
226                    boolean active = mTrustManagerService.isEscrowTokenActive(handle, userId);
227                    try {
228                        if (mTrustAgentService != null) {
229                            mTrustAgentService.onTokenStateReceived(handle,
230                                    active ? TrustAgentService.TOKEN_STATE_ACTIVE
231                                            : TrustAgentService.TOKEN_STATE_INACTIVE);
232                        }
233                    } catch (RemoteException e) {
234                        onError(e);
235                    }
236                    break;
237                }
238                case MSG_REMOVE_ESCROW_TOKEN: {
239                    long handle = msg.getData().getLong(DATA_HANDLE);
240                    int userId = msg.getData().getInt(DATA_USER_ID);
241                    boolean success = mTrustManagerService.removeEscrowToken(handle, userId);
242                    try {
243                        if (mTrustAgentService != null) {
244                            mTrustAgentService.onEscrowTokenRemoved(handle, success);
245                        }
246                    } catch (RemoteException e) {
247                        onError(e);
248                    }
249                    break;
250                }
251                case MSG_UNLOCK_USER: {
252                    long handle = msg.getData().getLong(DATA_HANDLE);
253                    int userId = msg.getData().getInt(DATA_USER_ID);
254                    byte[] eToken = msg.getData().getByteArray(DATA_ESCROW_TOKEN);
255                    mTrustManagerService.unlockUserWithToken(handle, eToken, userId);
256                    break;
257                }
258            }
259        }
260    };
261
262    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
263
264        @Override
265        public void grantTrust(CharSequence userMessage, long durationMs, int flags) {
266            if (DEBUG) Slog.d(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
267                        + ", flags = " + flags + ")");
268
269            Message msg = mHandler.obtainMessage(
270                    MSG_GRANT_TRUST, flags, 0, userMessage);
271            msg.getData().putLong(DATA_DURATION, durationMs);
272            msg.sendToTarget();
273        }
274
275        @Override
276        public void revokeTrust() {
277            if (DEBUG) Slog.d(TAG, "revokeTrust()");
278            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
279        }
280
281        @Override
282        public void setManagingTrust(boolean managingTrust) {
283            if (DEBUG) Slog.d(TAG, "managingTrust()");
284            mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
285        }
286
287        @Override
288        public void onConfigureCompleted(boolean result, IBinder token) {
289            if (DEBUG) Slog.d(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
290            mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
291                    result ? 1 : 0, 0, token).sendToTarget();
292        }
293
294        @Override
295        public void addEscrowToken(byte[] token, int userId) {
296            if (mContext.getResources()
297                    .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
298                throw  new SecurityException("Escrow token API is not allowed.");
299            }
300
301            if (DEBUG) Slog.d(TAG, "adding escrow token for user " + userId);
302            Message msg = mHandler.obtainMessage(MSG_ADD_ESCROW_TOKEN);
303            msg.getData().putByteArray(DATA_ESCROW_TOKEN, token);
304            msg.getData().putInt(DATA_USER_ID, userId);
305            msg.sendToTarget();
306        }
307
308        @Override
309        public void isEscrowTokenActive(long handle, int userId) {
310            if (mContext.getResources()
311                    .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
312                throw new SecurityException("Escrow token API is not allowed.");
313            }
314
315            if (DEBUG) Slog.d(TAG, "checking the state of escrow token on user " + userId);
316            Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_STATE);
317            msg.getData().putLong(DATA_HANDLE, handle);
318            msg.getData().putInt(DATA_USER_ID, userId);
319            msg.sendToTarget();
320        }
321
322        @Override
323        public void removeEscrowToken(long handle, int userId) {
324            if (mContext.getResources()
325                    .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
326                throw new SecurityException("Escrow token API is not allowed.");
327            }
328
329            if (DEBUG) Slog.d(TAG, "removing escrow token on user " + userId);
330            Message msg = mHandler.obtainMessage(MSG_REMOVE_ESCROW_TOKEN);
331            msg.getData().putLong(DATA_HANDLE, handle);
332            msg.getData().putInt(DATA_USER_ID, userId);
333            msg.sendToTarget();
334        }
335
336        @Override
337        public void unlockUserWithToken(long handle, byte[] token, int userId) {
338            if (mContext.getResources()
339                    .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
340                throw new SecurityException("Escrow token API is not allowed.");
341            }
342
343            if (DEBUG) Slog.d(TAG, "unlocking user " + userId);
344            Message msg = mHandler.obtainMessage(MSG_UNLOCK_USER);
345            msg.getData().putInt(DATA_USER_ID, userId);
346            msg.getData().putLong(DATA_HANDLE, handle);
347            msg.getData().putByteArray(DATA_ESCROW_TOKEN, token);
348            msg.sendToTarget();
349        }
350    };
351
352    private final ServiceConnection mConnection = new ServiceConnection() {
353        @Override
354        public void onServiceConnected(ComponentName name, IBinder service) {
355            if (DEBUG) Slog.d(TAG, "TrustAgent started : " + name.flattenToString());
356            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
357            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
358            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
359            setCallback(mCallback);
360            updateDevicePolicyFeatures();
361
362            if (mPendingSuccessfulUnlock) {
363                onUnlockAttempt(true);
364                mPendingSuccessfulUnlock = false;
365            }
366
367            if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
368                onDeviceLocked();
369            } else {
370                onDeviceUnlocked();
371            }
372        }
373
374        @Override
375        public void onServiceDisconnected(ComponentName name) {
376            if (DEBUG) Slog.d(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
377            mTrustAgentService = null;
378            mManagingTrust = false;
379            mSetTrustAgentFeaturesToken = null;
380            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
381            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
382            if (mBound) {
383                scheduleRestart();
384            }
385            // mTrustDisabledByDpm maintains state
386        }
387    };
388
389    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
390            Intent intent, UserHandle user) {
391        mContext = context;
392        mTrustManagerService = trustManagerService;
393        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
394        mUserId = user.getIdentifier();
395        mName = intent.getComponent();
396
397        mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
398        mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
399        mAlarmIntent.setPackage(context.getPackageName());
400
401        final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
402        alarmFilter.addDataScheme(mAlarmIntent.getScheme());
403        final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
404        alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
405
406        // Schedules a restart for when connecting times out. If the connection succeeds,
407        // the restart is canceled in mCallback's onConnected.
408        scheduleRestart();
409        mBound = context.bindServiceAsUser(intent, mConnection,
410                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, user);
411        if (mBound) {
412            mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
413        } else {
414            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
415        }
416    }
417
418    private void onError(Exception e) {
419        Slog.w(TAG , "Exception ", e);
420    }
421
422    private void onTrustTimeout() {
423        try {
424            if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
425        } catch (RemoteException e) {
426            onError(e);
427        }
428    }
429
430    /**
431     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
432     */
433    public void onUnlockAttempt(boolean successful) {
434        try {
435            if (mTrustAgentService != null) {
436                mTrustAgentService.onUnlockAttempt(successful);
437            } else {
438                mPendingSuccessfulUnlock = successful;
439            }
440        } catch (RemoteException e) {
441            onError(e);
442        }
443    }
444
445    /**
446     * @see android.service.trust.TrustAgentService#onUnlockLockout(int)
447     */
448    public void onUnlockLockout(int timeoutMs) {
449        try {
450            if (mTrustAgentService != null) {
451                mTrustAgentService.onUnlockLockout(timeoutMs);
452            }
453        } catch (RemoteException e) {
454            onError(e);
455        }
456    }
457
458    /**
459     * @see android.service.trust.TrustAgentService#onDeviceLocked()
460     */
461    public void onDeviceLocked() {
462        try {
463            if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
464        } catch (RemoteException e) {
465            onError(e);
466        }
467    }
468
469    /**
470     * @see android.service.trust.TrustAgentService#onDeviceUnlocked()
471     */
472    public void onDeviceUnlocked() {
473        try {
474            if (mTrustAgentService != null) mTrustAgentService.onDeviceUnlocked();
475        } catch (RemoteException e) {
476            onError(e);
477        }
478    }
479
480    private void setCallback(ITrustAgentServiceCallback callback) {
481        try {
482            if (mTrustAgentService != null) {
483                mTrustAgentService.setCallback(callback);
484            }
485        } catch (RemoteException e) {
486            onError(e);
487        }
488    }
489
490    boolean updateDevicePolicyFeatures() {
491        boolean trustDisabled = false;
492        if (DEBUG) Slog.d(TAG, "updateDevicePolicyFeatures(" + mName + ")");
493        try {
494            if (mTrustAgentService != null) {
495                DevicePolicyManager dpm =
496                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
497
498                if ((dpm.getKeyguardDisabledFeatures(null, mUserId)
499                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
500                    List<PersistableBundle> config = dpm.getTrustAgentConfiguration(
501                            null, mName, mUserId);
502                    trustDisabled = true;
503                    if (DEBUG) Slog.d(TAG, "Detected trust agents disabled. Config = " + config);
504                    if (config != null && config.size() > 0) {
505                        if (DEBUG) {
506                            Slog.d(TAG, "TrustAgent " + mName.flattenToShortString()
507                                    + " disabled until it acknowledges "+ config);
508                        }
509                        mSetTrustAgentFeaturesToken = new Binder();
510                        mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
511                    }
512                } else {
513                    mTrustAgentService.onConfigure(Collections.EMPTY_LIST, null);
514                }
515                final long maxTimeToLock = dpm.getMaximumTimeToLockForUserAndProfiles(mUserId);
516                if (maxTimeToLock != mMaximumTimeToLock) {
517                    // If the timeout changes, cancel the alarm and send a timeout event to have
518                    // the agent re-evaluate trust.
519                    mMaximumTimeToLock = maxTimeToLock;
520                    if (mAlarmPendingIntent != null) {
521                        mAlarmManager.cancel(mAlarmPendingIntent);
522                        mAlarmPendingIntent = null;
523                        mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
524                    }
525                }
526            }
527        } catch (RemoteException e) {
528            onError(e);
529        }
530        if (mTrustDisabledByDpm != trustDisabled) {
531            mTrustDisabledByDpm = trustDisabled;
532            mTrustManagerService.updateTrust(mUserId, 0);
533        }
534        return trustDisabled;
535    }
536
537    public boolean isTrusted() {
538        return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
539    }
540
541    public boolean isManagingTrust() {
542        return mManagingTrust && !mTrustDisabledByDpm;
543    }
544
545    public CharSequence getMessage() {
546        return mMessage;
547    }
548
549    public void destroy() {
550        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
551
552        if (!mBound) {
553            return;
554        }
555        if (DEBUG) Slog.d(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
556        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
557        mContext.unbindService(mConnection);
558        mBound = false;
559        mContext.unregisterReceiver(mBroadcastReceiver);
560        mTrustAgentService = null;
561        mSetTrustAgentFeaturesToken = null;
562        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
563    }
564
565    public boolean isConnected() {
566        return mTrustAgentService != null;
567    }
568
569    public boolean isBound() {
570        return mBound;
571    }
572
573    /**
574     * If not connected, returns the time at which the agent is restarted.
575     *
576     * @return restart time in uptime millis.
577     */
578    public long getScheduledRestartUptimeMillis() {
579        return mScheduledRestartUptimeMillis;
580    }
581
582    private void scheduleRestart() {
583        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
584        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
585        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
586    }
587}
588