• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.locksettings;
18 
19 import static android.os.UserHandle.USER_SYSTEM;
20 
21 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_ESCROW_NOT_READY;
22 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
23 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;
24 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_ESCROW_KEY;
25 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NO_PROVIDER;
26 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
27 import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
28 import static com.android.internal.widget.LockSettingsInternal.ArmRebootEscrowErrorCode;
29 
30 import android.annotation.IntDef;
31 import android.annotation.NonNull;
32 import android.annotation.UserIdInt;
33 import android.content.Context;
34 import android.content.pm.PackageManager;
35 import android.content.pm.UserInfo;
36 import android.net.ConnectivityManager;
37 import android.net.Network;
38 import android.net.NetworkCapabilities;
39 import android.os.Handler;
40 import android.os.PowerManager;
41 import android.os.SystemClock;
42 import android.os.SystemProperties;
43 import android.os.UserManager;
44 import android.provider.DeviceConfig;
45 import android.provider.Settings;
46 import android.util.Slog;
47 
48 import com.android.internal.annotations.GuardedBy;
49 import com.android.internal.annotations.VisibleForTesting;
50 import com.android.internal.util.FrameworkStatsLog;
51 import com.android.internal.util.IndentingPrintWriter;
52 import com.android.internal.widget.RebootEscrowListener;
53 
54 import java.io.IOException;
55 import java.lang.annotation.Retention;
56 import java.lang.annotation.RetentionPolicy;
57 import java.text.SimpleDateFormat;
58 import java.util.ArrayList;
59 import java.util.Date;
60 import java.util.List;
61 import java.util.Locale;
62 import java.util.Objects;
63 
64 import javax.crypto.SecretKey;
65 
66 /**
67  * This class aims to persists the synthetic password(SP) across reboot in a secure way. In
68  * particular, it manages the encryption of the sp before reboot, and decryption of the sp after
69  * reboot. Here are the meaning of some terms.
70  *   SP: synthetic password
71  *   K_s: The RebootEscrowKey, i.e. AES-GCM key stored in memory
72  *   K_k: AES-GCM key in android keystore
73  *   RebootEscrowData: The synthetic password and its encrypted blob. We encrypt SP with K_s first,
74  *      then with K_k, i.e. E(K_k, E(K_s, SP))
75  */
76 class RebootEscrowManager {
77     private static final String TAG = "RebootEscrowManager";
78 
79     /**
80      * Used in the database storage to indicate the boot count at which the reboot escrow was
81      * previously armed.
82      */
83     @VisibleForTesting
84     public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
85 
86     static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp";
87     static final String REBOOT_ESCROW_KEY_PROVIDER = "reboot_escrow_key_provider";
88 
89     /**
90      * The verified boot 2.0 vbmeta digest of the current slot, the property value is always
91      * available after boot.
92      */
93     static final String VBMETA_DIGEST_PROP_NAME = "ro.boot.vbmeta.digest";
94     /**
95      * The system prop contains vbmeta digest of the inactive slot. The build property is set after
96      * an OTA update. RebootEscrowManager will store it in disk before the OTA reboot, so the value
97      * is available for vbmeta digest verification after the device reboots.
98      */
99     static final String OTHER_VBMETA_DIGEST_PROP_NAME = "ota.other.vbmeta_digest";
100     static final String REBOOT_ESCROW_KEY_VBMETA_DIGEST = "reboot_escrow_key_vbmeta_digest";
101     static final String REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST =
102             "reboot_escrow_key_other_vbmeta_digest";
103 
104     /**
105      * Number of boots until we consider the escrow data to be stale for the purposes of metrics.
106      * <p>
107      * If the delta between the current boot number and the boot number stored when the mechanism
108      * was armed is under this number and the escrow mechanism fails, we report it as a failure of
109      * the mechanism.
110      * <p>
111      * If the delta over this number and escrow fails, we will not report the metric as failed
112      * since there most likely was some other issue if the device rebooted several times before
113      * getting to the escrow restore code.
114      */
115     private static final int BOOT_COUNT_TOLERANCE = 5;
116 
117     /**
118      * The default retry specs for loading reboot escrow data. We will attempt to retry loading
119      * escrow data on temporarily errors, e.g. unavailable network.
120      */
121     private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
122     private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
123     // 3 minutes. It's enough for the default 3 retries with 30 seconds interval
124     private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS = 180_000;
125 
126     @IntDef(prefix = {"ERROR_"}, value = {
127             ERROR_NONE,
128             ERROR_UNKNOWN,
129             ERROR_NO_PROVIDER,
130             ERROR_LOAD_ESCROW_KEY,
131             ERROR_RETRY_COUNT_EXHAUSTED,
132             ERROR_UNLOCK_ALL_USERS,
133             ERROR_PROVIDER_MISMATCH,
134             ERROR_KEYSTORE_FAILURE,
135             ERROR_NO_NETWORK,
136     })
137     @Retention(RetentionPolicy.SOURCE)
138     @interface RebootEscrowErrorCode {
139     }
140 
141     static final int ERROR_NONE = 0;
142     static final int ERROR_UNKNOWN = 1;
143     static final int ERROR_NO_PROVIDER = 2;
144     static final int ERROR_LOAD_ESCROW_KEY = 3;
145     static final int ERROR_RETRY_COUNT_EXHAUSTED = 4;
146     static final int ERROR_UNLOCK_ALL_USERS = 5;
147     static final int ERROR_PROVIDER_MISMATCH = 6;
148     static final int ERROR_KEYSTORE_FAILURE = 7;
149     static final int ERROR_NO_NETWORK = 8;
150 
151     private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
152 
153     /**
154      * Logs events for later debugging in bugreports.
155      */
156     private final RebootEscrowEventLog mEventLog;
157 
158     /**
159      * Used to track when the reboot escrow is wanted. Should stay true once escrow is requested
160      * unless clearRebootEscrow is called. This will allow all the active users to be unlocked
161      * after reboot.
162      */
163     private boolean mRebootEscrowWanted;
164 
165     /** Used to track when reboot escrow is ready. */
166     private boolean mRebootEscrowReady;
167 
168     /** Notified when mRebootEscrowReady changes. */
169     private RebootEscrowListener mRebootEscrowListener;
170 
171     /**
172      * Hold this lock when checking or generating the reboot escrow key.
173      */
174     private final Object mKeyGenerationLock = new Object();
175 
176     /**
177      * Stores the reboot escrow data between when it's supplied and when
178      * {@link #armRebootEscrowIfNeeded()} is called.
179      */
180     @GuardedBy("mKeyGenerationLock")
181     private RebootEscrowKey mPendingRebootEscrowKey;
182 
183     private final UserManager mUserManager;
184 
185     private final Injector mInjector;
186 
187     private final LockSettingsStorage mStorage;
188 
189     private final Callbacks mCallbacks;
190 
191     private final RebootEscrowKeyStoreManager mKeyStoreManager;
192 
193     PowerManager.WakeLock mWakeLock;
194 
195 
196     interface Callbacks {
isUserSecure(int userId)197         boolean isUserSecure(int userId);
198 
onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId)199         void onRebootEscrowRestored(byte spVersion, byte[] syntheticPassword, int userId);
200     }
201 
202     static class Injector {
203         protected Context mContext;
204         private final RebootEscrowKeyStoreManager mKeyStoreManager;
205         private final LockSettingsStorage mStorage;
206         private RebootEscrowProviderInterface mRebootEscrowProvider;
207 
Injector(Context context, LockSettingsStorage storage)208         Injector(Context context, LockSettingsStorage storage) {
209             mContext = context;
210             mStorage = storage;
211             mKeyStoreManager = new RebootEscrowKeyStoreManager();
212         }
213 
createRebootEscrowProvider()214         private RebootEscrowProviderInterface createRebootEscrowProvider() {
215             RebootEscrowProviderInterface rebootEscrowProvider;
216             if (serverBasedResumeOnReboot()) {
217                 Slog.i(TAG, "Using server based resume on reboot");
218                 rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
219             } else {
220                 Slog.i(TAG, "Using HAL based resume on reboot");
221                 rebootEscrowProvider = new RebootEscrowProviderHalImpl();
222             }
223 
224             if (rebootEscrowProvider.hasRebootEscrowSupport()) {
225                 return rebootEscrowProvider;
226             }
227             return null;
228         }
229 
post(Handler handler, Runnable runnable)230         void post(Handler handler, Runnable runnable) {
231             handler.post(runnable);
232         }
233 
postDelayed(Handler handler, Runnable runnable, long delayMillis)234         void postDelayed(Handler handler, Runnable runnable, long delayMillis) {
235             handler.postDelayed(runnable, delayMillis);
236         }
237 
serverBasedResumeOnReboot()238         public boolean serverBasedResumeOnReboot() {
239             // Always use the server based RoR if the HAL isn't installed on device.
240             if (!mContext.getPackageManager().hasSystemFeature(
241                     PackageManager.FEATURE_REBOOT_ESCROW)) {
242                 return true;
243             }
244 
245             return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
246                     "server_based_ror_enabled", false);
247         }
248 
isNetworkConnected()249         public boolean isNetworkConnected() {
250             final ConnectivityManager connectivityManager =
251                     mContext.getSystemService(ConnectivityManager.class);
252             if (connectivityManager == null) {
253                 return false;
254             }
255 
256             Network activeNetwork = connectivityManager.getActiveNetwork();
257             NetworkCapabilities networkCapabilities =
258                     connectivityManager.getNetworkCapabilities(activeNetwork);
259             return networkCapabilities != null
260                     && networkCapabilities.hasCapability(
261                             NetworkCapabilities.NET_CAPABILITY_INTERNET)
262                     && networkCapabilities.hasCapability(
263                             NetworkCapabilities.NET_CAPABILITY_VALIDATED);
264         }
265 
getContext()266         public Context getContext() {
267             return mContext;
268         }
269 
getUserManager()270         public UserManager getUserManager() {
271             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
272         }
273 
getKeyStoreManager()274         public RebootEscrowKeyStoreManager getKeyStoreManager() {
275             return mKeyStoreManager;
276         }
277 
createRebootEscrowProviderIfNeeded()278         public RebootEscrowProviderInterface createRebootEscrowProviderIfNeeded() {
279             // Initialize for the provider lazily. Because the device_config and service
280             // implementation apps may change when system server is running.
281             if (mRebootEscrowProvider == null) {
282                 mRebootEscrowProvider = createRebootEscrowProvider();
283             }
284 
285             return mRebootEscrowProvider;
286         }
287 
getWakeLock()288         PowerManager.WakeLock getWakeLock() {
289             final PowerManager pm = mContext.getSystemService(PowerManager.class);
290             return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "RebootEscrowManager");
291         }
292 
getRebootEscrowProvider()293         public RebootEscrowProviderInterface getRebootEscrowProvider() {
294             return mRebootEscrowProvider;
295         }
296 
clearRebootEscrowProvider()297         public void clearRebootEscrowProvider() {
298             mRebootEscrowProvider = null;
299         }
300 
getBootCount()301         public int getBootCount() {
302             return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BOOT_COUNT,
303                     0);
304         }
305 
getCurrentTimeMillis()306         public long getCurrentTimeMillis() {
307             return System.currentTimeMillis();
308         }
309 
getLoadEscrowDataRetryLimit()310         public int getLoadEscrowDataRetryLimit() {
311             return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
312                     "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
313         }
314 
getLoadEscrowDataRetryIntervalSeconds()315         public int getLoadEscrowDataRetryIntervalSeconds() {
316             return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
317                     "load_escrow_data_retry_interval_seconds",
318                     DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
319         }
320 
reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootCompleteInSeconds)321         public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
322                 int escrowDurationInSeconds, int vbmetaDigestStatus,
323                 int durationSinceBootCompleteInSeconds) {
324             FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success,
325                     errorCode, serviceType, attemptCount, escrowDurationInSeconds,
326                     vbmetaDigestStatus, durationSinceBootCompleteInSeconds);
327         }
328 
getEventLog()329         public RebootEscrowEventLog getEventLog() {
330             return new RebootEscrowEventLog();
331         }
332 
getVbmetaDigest(boolean other)333         public String getVbmetaDigest(boolean other) {
334             return other ? SystemProperties.get(OTHER_VBMETA_DIGEST_PROP_NAME)
335                     : SystemProperties.get(VBMETA_DIGEST_PROP_NAME);
336         }
337     }
338 
RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage)339     RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) {
340         this(new Injector(context, storage), callbacks, storage);
341     }
342 
343     @VisibleForTesting
RebootEscrowManager(Injector injector, Callbacks callbacks, LockSettingsStorage storage)344     RebootEscrowManager(Injector injector, Callbacks callbacks,
345             LockSettingsStorage storage) {
346         mInjector = injector;
347         mCallbacks = callbacks;
348         mStorage = storage;
349         mUserManager = injector.getUserManager();
350         mEventLog = injector.getEventLog();
351         mKeyStoreManager = injector.getKeyStoreManager();
352     }
353 
onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount)354     private void onGetRebootEscrowKeyFailed(List<UserInfo> users, int attemptCount) {
355         Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
356         for (UserInfo user : users) {
357             mStorage.removeRebootEscrow(user.id);
358         }
359 
360         onEscrowRestoreComplete(false, attemptCount);
361     }
362 
loadRebootEscrowDataIfAvailable(Handler retryHandler)363     void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
364         List<UserInfo> users = mUserManager.getUsers();
365         List<UserInfo> rebootEscrowUsers = new ArrayList<>();
366         for (UserInfo user : users) {
367             if (mCallbacks.isUserSecure(user.id) && mStorage.hasRebootEscrow(user.id)) {
368                 rebootEscrowUsers.add(user);
369             }
370         }
371 
372         if (rebootEscrowUsers.isEmpty()) {
373             Slog.i(TAG, "No reboot escrow data found for users,"
374                     + " skipping loading escrow data");
375             clearMetricsStorage();
376             return;
377         }
378 
379         // Acquire the wake lock to make sure our scheduled task will run.
380         mWakeLock = mInjector.getWakeLock();
381         if (mWakeLock != null) {
382             mWakeLock.setReferenceCounted(false);
383             mWakeLock.acquire(DEFAULT_WAKE_LOCK_TIMEOUT_MILLIS);
384         }
385 
386         mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
387                 retryHandler, 0, users, rebootEscrowUsers));
388     }
389 
scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers)390     void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
391             List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
392         Objects.requireNonNull(retryHandler);
393 
394         final int retryLimit = mInjector.getLoadEscrowDataRetryLimit();
395         final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds();
396 
397         if (attemptNumber < retryLimit) {
398             Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
399             mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
400                     retryHandler, attemptNumber, users, rebootEscrowUsers),
401                     retryIntervalInSeconds * 1000);
402             return;
403         }
404 
405         Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
406         if (mInjector.serverBasedResumeOnReboot() && !mInjector.isNetworkConnected()) {
407             mLoadEscrowDataErrorCode = ERROR_NO_NETWORK;
408         } else {
409             mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
410         }
411         onGetRebootEscrowKeyFailed(users, attemptNumber);
412     }
413 
loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers)414     void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
415             List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
416         // Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
417         // generated before reboot. Note that we will clear the escrow key even if the keystore key
418         // is null.
419         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
420         if (kk == null) {
421             Slog.i(TAG, "Failed to load the key for resume on reboot from key store.");
422         }
423 
424         RebootEscrowKey escrowKey;
425         try {
426             escrowKey = getAndClearRebootEscrowKey(kk);
427         } catch (IOException e) {
428             Slog.i(TAG, "Failed to load escrow key, scheduling retry.", e);
429             scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
430                     rebootEscrowUsers);
431             return;
432         }
433 
434         if (escrowKey == null) {
435             if (mLoadEscrowDataErrorCode == ERROR_NONE) {
436                 // Specifically check if the RoR provider has changed after reboot.
437                 int providerType = mInjector.serverBasedResumeOnReboot()
438                         ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
439                         : RebootEscrowProviderInterface.TYPE_HAL;
440                 if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
441                     mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH;
442                 } else {
443                     mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY;
444                 }
445             }
446             onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
447             return;
448         }
449 
450         mEventLog.addEntry(RebootEscrowEvent.FOUND_ESCROW_DATA);
451 
452         boolean allUsersUnlocked = true;
453         for (UserInfo user : rebootEscrowUsers) {
454             allUsersUnlocked &= restoreRebootEscrowForUser(user.id, escrowKey, kk);
455         }
456 
457         if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
458             mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
459         }
460         onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
461     }
462 
clearMetricsStorage()463     private void clearMetricsStorage() {
464         mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
465         mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
466         mStorage.removeKey(REBOOT_ESCROW_KEY_VBMETA_DIGEST, USER_SYSTEM);
467         mStorage.removeKey(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, USER_SYSTEM);
468         mStorage.removeKey(REBOOT_ESCROW_KEY_PROVIDER, USER_SYSTEM);
469     }
470 
getVbmetaDigestStatusOnRestoreComplete()471     private int getVbmetaDigestStatusOnRestoreComplete() {
472         String currentVbmetaDigest = mInjector.getVbmetaDigest(false);
473         String vbmetaDigestStored = mStorage.getString(REBOOT_ESCROW_KEY_VBMETA_DIGEST,
474                 "", USER_SYSTEM);
475         String vbmetaDigestOtherStored = mStorage.getString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
476                 "", USER_SYSTEM);
477 
478         // The other vbmeta digest is never set, assume no slot switch is attempted.
479         if (vbmetaDigestOtherStored.isEmpty()) {
480             if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
481                 return FrameworkStatsLog
482                         .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
483             }
484             return FrameworkStatsLog
485                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
486         }
487 
488         // The other vbmeta digest is set, we expect to boot into the new slot.
489         if (currentVbmetaDigest.equals(vbmetaDigestOtherStored)) {
490             return FrameworkStatsLog
491                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
492         } else if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
493             return FrameworkStatsLog
494                     .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_FALLBACK_SLOT;
495         }
496         return FrameworkStatsLog
497                 .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
498     }
499 
reportMetricOnRestoreComplete(boolean success, int attemptCount)500     private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
501         int serviceType = mInjector.serverBasedResumeOnReboot()
502                 ? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
503                 : FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__HAL;
504 
505         long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
506                 USER_SYSTEM);
507         int escrowDurationInSeconds = -1;
508         long currentTimeStamp = mInjector.getCurrentTimeMillis();
509         if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) {
510             escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000;
511         }
512 
513         int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
514         if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
515             mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
516         }
517 
518         Slog.i(TAG, "Reporting RoR recovery metrics, success: " + success + ", service type: "
519                 + serviceType + ", error code: " + mLoadEscrowDataErrorCode);
520         // TODO(179105110) report the duration since boot complete.
521         mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
522                 escrowDurationInSeconds, vbmetaDigestStatus, -1);
523 
524         mLoadEscrowDataErrorCode = ERROR_NONE;
525     }
526 
onEscrowRestoreComplete(boolean success, int attemptCount)527     private void onEscrowRestoreComplete(boolean success, int attemptCount) {
528         int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
529 
530         int bootCountDelta = mInjector.getBootCount() - previousBootCount;
531         if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
532             reportMetricOnRestoreComplete(success, attemptCount);
533         }
534 
535         // Clear the old key in keystore. A new key will be generated by new RoR requests.
536         mKeyStoreManager.clearKeyStoreEncryptionKey();
537         // Clear the saved reboot escrow provider
538         mInjector.clearRebootEscrowProvider();
539         clearMetricsStorage();
540 
541         if (mWakeLock != null) {
542             mWakeLock.release();
543         }
544     }
545 
getAndClearRebootEscrowKey(SecretKey kk)546     private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
547         RebootEscrowProviderInterface rebootEscrowProvider =
548                 mInjector.createRebootEscrowProviderIfNeeded();
549         if (rebootEscrowProvider == null) {
550             Slog.w(TAG,
551                     "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
552             mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER;
553             return null;
554         }
555 
556         // Server based RoR always need the decryption key from keystore.
557         if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
558                 && kk == null) {
559             mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE;
560             return null;
561         }
562 
563         // The K_s blob maybe encrypted by K_k as well.
564         RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(kk);
565         if (key != null) {
566             mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK);
567         }
568         return key;
569     }
570 
restoreRebootEscrowForUser(@serIdInt int userId, RebootEscrowKey ks, SecretKey kk)571     private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey ks,
572             SecretKey kk) {
573         if (!mStorage.hasRebootEscrow(userId)) {
574             return false;
575         }
576 
577         try {
578             byte[] blob = mStorage.readRebootEscrow(userId);
579             mStorage.removeRebootEscrow(userId);
580 
581             RebootEscrowData escrowData = RebootEscrowData.fromEncryptedData(ks, blob, kk);
582 
583             mCallbacks.onRebootEscrowRestored(escrowData.getSpVersion(),
584                     escrowData.getSyntheticPassword(), userId);
585             Slog.i(TAG, "Restored reboot escrow data for user " + userId);
586             mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_LSKF_FOR_USER, userId);
587             return true;
588         } catch (IOException e) {
589             Slog.w(TAG, "Could not load reboot escrow data for user " + userId, e);
590             return false;
591         }
592     }
593 
callToRebootEscrowIfNeeded(@serIdInt int userId, byte spVersion, byte[] syntheticPassword)594     void callToRebootEscrowIfNeeded(@UserIdInt int userId, byte spVersion,
595             byte[] syntheticPassword) {
596         if (!mRebootEscrowWanted) {
597             return;
598         }
599 
600         if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
601             Slog.w(TAG, "Not storing escrow data, RebootEscrowProvider is unavailable");
602             return;
603         }
604 
605         RebootEscrowKey escrowKey = generateEscrowKeyIfNeeded();
606         if (escrowKey == null) {
607             Slog.e(TAG, "Could not generate escrow key");
608             return;
609         }
610 
611         SecretKey kk = mKeyStoreManager.generateKeyStoreEncryptionKeyIfNeeded();
612         if (kk == null) {
613             Slog.e(TAG, "Failed to generate encryption key from keystore.");
614             return;
615         }
616 
617         final RebootEscrowData escrowData;
618         try {
619             escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion,
620                     syntheticPassword, kk);
621         } catch (IOException e) {
622             setRebootEscrowReady(false);
623             Slog.w(TAG, "Could not escrow reboot data", e);
624             return;
625         }
626 
627         mStorage.writeRebootEscrow(userId, escrowData.getBlob());
628         mEventLog.addEntry(RebootEscrowEvent.STORED_LSKF_FOR_USER, userId);
629 
630         setRebootEscrowReady(true);
631     }
632 
generateEscrowKeyIfNeeded()633     private RebootEscrowKey generateEscrowKeyIfNeeded() {
634         synchronized (mKeyGenerationLock) {
635             if (mPendingRebootEscrowKey != null) {
636                 return mPendingRebootEscrowKey;
637             }
638 
639             RebootEscrowKey key;
640             try {
641                 key = RebootEscrowKey.generate();
642             } catch (IOException e) {
643                 Slog.w(TAG, "Could not generate reboot escrow key");
644                 return null;
645             }
646 
647             mPendingRebootEscrowKey = key;
648             return key;
649         }
650     }
651 
clearRebootEscrowIfNeeded()652     private void clearRebootEscrowIfNeeded() {
653         mRebootEscrowWanted = false;
654         setRebootEscrowReady(false);
655 
656         // We want to clear the internal data inside the provider, so always try to create the
657         // provider.
658         RebootEscrowProviderInterface rebootEscrowProvider =
659                 mInjector.createRebootEscrowProviderIfNeeded();
660         if (rebootEscrowProvider == null) {
661             Slog.w(TAG, "RebootEscrowProvider is unavailable for clear request");
662         } else {
663             rebootEscrowProvider.clearRebootEscrowKey();
664         }
665 
666         mInjector.clearRebootEscrowProvider();
667         clearMetricsStorage();
668 
669         List<UserInfo> users = mUserManager.getUsers();
670         for (UserInfo user : users) {
671             mStorage.removeRebootEscrow(user.id);
672         }
673 
674         mEventLog.addEntry(RebootEscrowEvent.CLEARED_LSKF_REQUEST);
675     }
676 
armRebootEscrowIfNeeded()677     @ArmRebootEscrowErrorCode int armRebootEscrowIfNeeded() {
678         if (!mRebootEscrowReady) {
679             return ARM_REBOOT_ERROR_ESCROW_NOT_READY;
680         }
681 
682         RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
683         if (rebootEscrowProvider == null) {
684             Slog.w(TAG, "Not storing escrow key, RebootEscrowProvider is unavailable");
685             clearRebootEscrowIfNeeded();
686             return ARM_REBOOT_ERROR_NO_PROVIDER;
687         }
688 
689         int expectedProviderType = mInjector.serverBasedResumeOnReboot()
690                 ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
691                 : RebootEscrowProviderInterface.TYPE_HAL;
692         int actualProviderType = rebootEscrowProvider.getType();
693         if (expectedProviderType != actualProviderType) {
694             Slog.w(TAG, "Expect reboot escrow provider " + expectedProviderType
695                     + ", but the RoR is prepared with " + actualProviderType
696                     + ". Please prepare the RoR again.");
697             clearRebootEscrowIfNeeded();
698             return ARM_REBOOT_ERROR_PROVIDER_MISMATCH;
699         }
700 
701         RebootEscrowKey escrowKey;
702         synchronized (mKeyGenerationLock) {
703             escrowKey = mPendingRebootEscrowKey;
704         }
705 
706         if (escrowKey == null) {
707             Slog.e(TAG, "Escrow key is null, but escrow was marked as ready");
708             clearRebootEscrowIfNeeded();
709             return ARM_REBOOT_ERROR_NO_ESCROW_KEY;
710         }
711 
712         // We will use the same key from keystore to encrypt the escrow key and escrow data blob.
713         SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
714         if (kk == null) {
715             Slog.e(TAG, "Failed to get encryption key from keystore.");
716             clearRebootEscrowIfNeeded();
717             return ARM_REBOOT_ERROR_KEYSTORE_FAILURE;
718         }
719 
720         // TODO(b/183140900) design detailed errors for store escrow key errors.
721         // We don't clear rebootEscrow here, because some errors may be recoverable, e.g. network
722         // unavailable for server based provider.
723         boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
724         if (!armedRebootEscrow) {
725             return ARM_REBOOT_ERROR_STORE_ESCROW_KEY;
726         }
727 
728         mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
729         mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
730                 USER_SYSTEM);
731         // Store the vbmeta digest of both slots.
732         mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
733                 USER_SYSTEM);
734         mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
735                 mInjector.getVbmetaDigest(true), USER_SYSTEM);
736         mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
737         mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
738 
739         return ARM_REBOOT_ERROR_NONE;
740     }
741 
setRebootEscrowReady(boolean ready)742     private void setRebootEscrowReady(boolean ready) {
743         if (mRebootEscrowReady != ready) {
744             mRebootEscrowListener.onPreparedForReboot(ready);
745         }
746         mRebootEscrowReady = ready;
747     }
748 
prepareRebootEscrow()749     boolean prepareRebootEscrow() {
750         clearRebootEscrowIfNeeded();
751         if (mInjector.createRebootEscrowProviderIfNeeded() == null) {
752             Slog.w(TAG, "No reboot escrow provider, skipping resume on reboot preparation.");
753             return false;
754         }
755 
756         mRebootEscrowWanted = true;
757         mEventLog.addEntry(RebootEscrowEvent.REQUESTED_LSKF);
758         return true;
759     }
760 
clearRebootEscrow()761     boolean clearRebootEscrow() {
762         clearRebootEscrowIfNeeded();
763         return true;
764     }
765 
setRebootEscrowListener(RebootEscrowListener listener)766     void setRebootEscrowListener(RebootEscrowListener listener) {
767         mRebootEscrowListener = listener;
768     }
769 
770     @VisibleForTesting
771     public static class RebootEscrowEvent {
772         static final int FOUND_ESCROW_DATA = 1;
773         static final int SET_ARMED_STATUS = 2;
774         static final int CLEARED_LSKF_REQUEST = 3;
775         static final int RETRIEVED_STORED_KEK = 4;
776         static final int REQUESTED_LSKF = 5;
777         static final int STORED_LSKF_FOR_USER = 6;
778         static final int RETRIEVED_LSKF_FOR_USER = 7;
779 
780         final int mEventId;
781         final Integer mUserId;
782         final long mWallTime;
783         final long mTimestamp;
784 
RebootEscrowEvent(int eventId)785         RebootEscrowEvent(int eventId) {
786             this(eventId, null);
787         }
788 
RebootEscrowEvent(int eventId, Integer userId)789         RebootEscrowEvent(int eventId, Integer userId) {
790             mEventId = eventId;
791             mUserId = userId;
792             mTimestamp = SystemClock.uptimeMillis();
793             mWallTime = System.currentTimeMillis();
794         }
795 
getEventDescription()796         String getEventDescription() {
797             switch (mEventId) {
798                 case FOUND_ESCROW_DATA:
799                     return "Found escrow data";
800                 case SET_ARMED_STATUS:
801                     return "Set armed status";
802                 case CLEARED_LSKF_REQUEST:
803                     return "Cleared request for LSKF";
804                 case RETRIEVED_STORED_KEK:
805                     return "Retrieved stored KEK";
806                 case REQUESTED_LSKF:
807                     return "Requested LSKF";
808                 case STORED_LSKF_FOR_USER:
809                     return "Stored LSKF for user";
810                 case RETRIEVED_LSKF_FOR_USER:
811                     return "Retrieved LSKF for user";
812                 default:
813                     return "Unknown event ID " + mEventId;
814             }
815         }
816     }
817 
818     @VisibleForTesting
819     public static class RebootEscrowEventLog {
820         private RebootEscrowEvent[] mEntries = new RebootEscrowEvent[16];
821         private int mNextIndex = 0;
822 
addEntry(int eventId)823         void addEntry(int eventId) {
824             addEntryInternal(new RebootEscrowEvent(eventId));
825         }
826 
addEntry(int eventId, int userId)827         void addEntry(int eventId, int userId) {
828             addEntryInternal(new RebootEscrowEvent(eventId, userId));
829         }
830 
addEntryInternal(RebootEscrowEvent event)831         private void addEntryInternal(RebootEscrowEvent event) {
832             final int index = mNextIndex;
833             mEntries[index] = event;
834             mNextIndex = (mNextIndex + 1) % mEntries.length;
835         }
836 
dump(@onNull IndentingPrintWriter pw)837         void dump(@NonNull IndentingPrintWriter pw) {
838             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
839 
840             for (int i = 0; i < mEntries.length; ++i) {
841                 RebootEscrowEvent event = mEntries[(i + mNextIndex) % mEntries.length];
842                 if (event == null) {
843                     continue;
844                 }
845 
846                 pw.print("Event #");
847                 pw.println(i);
848 
849                 pw.println(" time=" + sdf.format(new Date(event.mWallTime))
850                         + " (timestamp=" + event.mTimestamp + ")");
851 
852                 pw.print(" event=");
853                 pw.println(event.getEventDescription());
854 
855                 if (event.mUserId != null) {
856                     pw.print(" user=");
857                     pw.println(event.mUserId);
858                 }
859             }
860         }
861     }
862 
dump(@onNull IndentingPrintWriter pw)863     void dump(@NonNull IndentingPrintWriter pw) {
864         pw.print("mRebootEscrowWanted=");
865         pw.println(mRebootEscrowWanted);
866 
867         pw.print("mRebootEscrowReady=");
868         pw.println(mRebootEscrowReady);
869 
870         pw.print("mRebootEscrowListener=");
871         pw.println(mRebootEscrowListener);
872 
873         boolean keySet;
874         synchronized (mKeyGenerationLock) {
875             keySet = mPendingRebootEscrowKey != null;
876         }
877 
878         pw.print("mPendingRebootEscrowKey is ");
879         pw.println(keySet ? "set" : "not set");
880 
881         RebootEscrowProviderInterface provider = mInjector.getRebootEscrowProvider();
882         String providerType = provider == null ? "null" : String.valueOf(provider.getType());
883         pw.print("RebootEscrowProvider type is " + providerType);
884 
885         pw.println();
886         pw.println("Event log:");
887         pw.increaseIndent();
888         mEventLog.dump(pw);
889         pw.println();
890         pw.decreaseIndent();
891     }
892 }
893