Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +6 −1 Original line number Diff line number Diff line Loading @@ -280,6 +280,7 @@ public class LockSettingsService extends ILockSettings.Stub { super.onBootPhase(phase); if (phase == PHASE_ACTIVITY_MANAGER_READY) { mLockSettingsService.migrateOldDataAfterSystemReady(); mLockSettingsService.loadEscrowData(); } } Loading Loading @@ -832,11 +833,15 @@ public class LockSettingsService extends ILockSettings.Stub { mSpManager.initWeaverService(); getAuthSecretHal(); mDeviceProvisionedObserver.onSystemReady(); mRebootEscrowManager.loadRebootEscrowDataIfAvailable(); // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); } private void loadEscrowData() { mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler); } private void getAuthSecretHal() { try { mAuthSecretService = IAuthSecret.getService(/* retry */ true); Loading services/core/java/com/android/server/locksettings/RebootEscrowManager.java +68 −8 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.os.SystemClock; import android.os.UserManager; import android.provider.DeviceConfig; Loading @@ -39,6 +40,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Objects; import javax.crypto.SecretKey; Loading Loading @@ -75,6 +77,13 @@ class RebootEscrowManager { */ private static final int BOOT_COUNT_TOLERANCE = 5; /** * The default retry specs for loading reboot escrow data. We will attempt to retry loading * escrow data on temporarily errors, e.g. unavailable network. */ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3; private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30; /** * Logs events for later debugging in bugreports. */ Loading Loading @@ -148,6 +157,14 @@ class RebootEscrowManager { return null; } void post(Handler handler, Runnable runnable) { handler.post(runnable); } void postDelayed(Handler handler, Runnable runnable, long delayMillis) { handler.postDelayed(runnable, delayMillis); } public Context getContext() { return mContext; } Loading Loading @@ -199,7 +216,18 @@ class RebootEscrowManager { mKeyStoreManager = injector.getKeyStoreManager(); } void loadRebootEscrowDataIfAvailable() { private void onGetRebootEscrowKeyFailed(List<UserInfo> users) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); } // Clear the old key in keystore. mKeyStoreManager.clearKeyStoreEncryptionKey(); onEscrowRestoreComplete(false); } void loadRebootEscrowDataIfAvailable(Handler retryHandler) { List<UserInfo> users = mUserManager.getUsers(); List<UserInfo> rebootEscrowUsers = new ArrayList<>(); for (UserInfo user : users) { Loading @@ -212,17 +240,49 @@ class RebootEscrowManager { return; } mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry( retryHandler, 0, users, rebootEscrowUsers)); } void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) { Objects.requireNonNull(retryHandler); final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT); final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, "load_escrow_data_retry_interval_seconds", DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS); if (attemptNumber < retryLimit) { Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber); mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry( retryHandler, attemptNumber, users, rebootEscrowUsers), retryIntervalInSeconds * 1000); return; } Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts"); onGetRebootEscrowKeyFailed(users); } void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) { // Fetch the key from keystore to decrypt the escrow data & escrow key; this key is // generated before reboot. Note that we will clear the escrow key even if the keystore key // is null. SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey(); RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(kk); if (kk == null || escrowKey == null) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); RebootEscrowKey escrowKey; try { escrowKey = getAndClearRebootEscrowKey(kk); } catch (IOException e) { scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users, rebootEscrowUsers); return; } onEscrowRestoreComplete(false); if (kk == null || escrowKey == null) { onGetRebootEscrowKeyFailed(users); return; } Loading @@ -249,7 +309,7 @@ class RebootEscrowManager { } } private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) { private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException { RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, Loading services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ import javax.crypto.SecretKey; * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL. */ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private static final String TAG = "RebootEscrowProviderHal"; private final Injector mInjector; Loading services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java +5 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.locksettings; import java.io.IOException; import javax.crypto.SecretKey; /** Loading @@ -33,9 +35,10 @@ public interface RebootEscrowProviderInterface { /** * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted, * use the input key to decrypt the RebootEscrowKey. Returns null on failure. * use the input key to decrypt the RebootEscrowKey. Returns null on failure. Throws an * IOException if the failure is non-fatal, and a retry may succeed. */ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey); RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException; /** * Clears the stored RebootEscrowKey. Loading services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java +11 −6 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import javax.crypto.SecretKey; * encrypt & decrypt the blob. */ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private static final String TAG = "RebootEscrowProviderServerBased"; // Timeout for service binding private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10; Loading @@ -50,6 +50,8 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa private final Injector mInjector; private byte[] mServerBlob; static class Injector { private ResumeOnRebootServiceConnection mServiceConnection = null; Loading Loading @@ -124,17 +126,20 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa } @Override public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) { byte[] serverBlob = mStorage.readRebootEscrowServerBlob(); public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException { if (mServerBlob == null) { mServerBlob = mStorage.readRebootEscrowServerBlob(); } // Delete the server blob in storage. mStorage.removeRebootEscrowServerBlob(); if (serverBlob == null) { if (mServerBlob == null) { Slog.w(TAG, "Failed to read reboot escrow server blob from storage"); return null; } Slog.i(TAG, "Loaded reboot escrow server blob from storage"); try { byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey); byte[] escrowKeyBytes = unwrapServerBlob(mServerBlob, decryptionKey); if (escrowKeyBytes == null) { Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null"); return null; Loading @@ -145,7 +150,7 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa } return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (TimeoutException | RemoteException | IOException e) { } catch (TimeoutException | RemoteException e) { Slog.w(TAG, "Failed to decrypt the server blob ", e); return null; } Loading Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +6 −1 Original line number Diff line number Diff line Loading @@ -280,6 +280,7 @@ public class LockSettingsService extends ILockSettings.Stub { super.onBootPhase(phase); if (phase == PHASE_ACTIVITY_MANAGER_READY) { mLockSettingsService.migrateOldDataAfterSystemReady(); mLockSettingsService.loadEscrowData(); } } Loading Loading @@ -832,11 +833,15 @@ public class LockSettingsService extends ILockSettings.Stub { mSpManager.initWeaverService(); getAuthSecretHal(); mDeviceProvisionedObserver.onSystemReady(); mRebootEscrowManager.loadRebootEscrowDataIfAvailable(); // TODO: maybe skip this for split system user mode. mStorage.prefetchUser(UserHandle.USER_SYSTEM); } private void loadEscrowData() { mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler); } private void getAuthSecretHal() { try { mAuthSecretService = IAuthSecret.getService(/* retry */ true); Loading
services/core/java/com/android/server/locksettings/RebootEscrowManager.java +68 −8 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.os.SystemClock; import android.os.UserManager; import android.provider.DeviceConfig; Loading @@ -39,6 +40,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Objects; import javax.crypto.SecretKey; Loading Loading @@ -75,6 +77,13 @@ class RebootEscrowManager { */ private static final int BOOT_COUNT_TOLERANCE = 5; /** * The default retry specs for loading reboot escrow data. We will attempt to retry loading * escrow data on temporarily errors, e.g. unavailable network. */ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3; private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30; /** * Logs events for later debugging in bugreports. */ Loading Loading @@ -148,6 +157,14 @@ class RebootEscrowManager { return null; } void post(Handler handler, Runnable runnable) { handler.post(runnable); } void postDelayed(Handler handler, Runnable runnable, long delayMillis) { handler.postDelayed(runnable, delayMillis); } public Context getContext() { return mContext; } Loading Loading @@ -199,7 +216,18 @@ class RebootEscrowManager { mKeyStoreManager = injector.getKeyStoreManager(); } void loadRebootEscrowDataIfAvailable() { private void onGetRebootEscrowKeyFailed(List<UserInfo> users) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); } // Clear the old key in keystore. mKeyStoreManager.clearKeyStoreEncryptionKey(); onEscrowRestoreComplete(false); } void loadRebootEscrowDataIfAvailable(Handler retryHandler) { List<UserInfo> users = mUserManager.getUsers(); List<UserInfo> rebootEscrowUsers = new ArrayList<>(); for (UserInfo user : users) { Loading @@ -212,17 +240,49 @@ class RebootEscrowManager { return; } mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry( retryHandler, 0, users, rebootEscrowUsers)); } void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) { Objects.requireNonNull(retryHandler); final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT); final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, "load_escrow_data_retry_interval_seconds", DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS); if (attemptNumber < retryLimit) { Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber); mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry( retryHandler, attemptNumber, users, rebootEscrowUsers), retryIntervalInSeconds * 1000); return; } Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts"); onGetRebootEscrowKeyFailed(users); } void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber, List<UserInfo> users, List<UserInfo> rebootEscrowUsers) { // Fetch the key from keystore to decrypt the escrow data & escrow key; this key is // generated before reboot. Note that we will clear the escrow key even if the keystore key // is null. SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey(); RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(kk); if (kk == null || escrowKey == null) { Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage."); for (UserInfo user : users) { mStorage.removeRebootEscrow(user.id); RebootEscrowKey escrowKey; try { escrowKey = getAndClearRebootEscrowKey(kk); } catch (IOException e) { scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users, rebootEscrowUsers); return; } onEscrowRestoreComplete(false); if (kk == null || escrowKey == null) { onGetRebootEscrowKeyFailed(users); return; } Loading @@ -249,7 +309,7 @@ class RebootEscrowManager { } } private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) { private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException { RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider(); if (rebootEscrowProvider == null) { Slog.w(TAG, Loading
services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -33,7 +33,7 @@ import javax.crypto.SecretKey; * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL. */ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private static final String TAG = "RebootEscrowProviderHal"; private final Injector mInjector; Loading
services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java +5 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.locksettings; import java.io.IOException; import javax.crypto.SecretKey; /** Loading @@ -33,9 +35,10 @@ public interface RebootEscrowProviderInterface { /** * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted, * use the input key to decrypt the RebootEscrowKey. Returns null on failure. * use the input key to decrypt the RebootEscrowKey. Returns null on failure. Throws an * IOException if the failure is non-fatal, and a retry may succeed. */ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey); RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException; /** * Clears the stored RebootEscrowKey. Loading
services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java +11 −6 Original line number Diff line number Diff line Loading @@ -35,7 +35,7 @@ import javax.crypto.SecretKey; * encrypt & decrypt the blob. */ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface { private static final String TAG = "RebootEscrowProvider"; private static final String TAG = "RebootEscrowProviderServerBased"; // Timeout for service binding private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10; Loading @@ -50,6 +50,8 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa private final Injector mInjector; private byte[] mServerBlob; static class Injector { private ResumeOnRebootServiceConnection mServiceConnection = null; Loading Loading @@ -124,17 +126,20 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa } @Override public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) { byte[] serverBlob = mStorage.readRebootEscrowServerBlob(); public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException { if (mServerBlob == null) { mServerBlob = mStorage.readRebootEscrowServerBlob(); } // Delete the server blob in storage. mStorage.removeRebootEscrowServerBlob(); if (serverBlob == null) { if (mServerBlob == null) { Slog.w(TAG, "Failed to read reboot escrow server blob from storage"); return null; } Slog.i(TAG, "Loaded reboot escrow server blob from storage"); try { byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey); byte[] escrowKeyBytes = unwrapServerBlob(mServerBlob, decryptionKey); if (escrowKeyBytes == null) { Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null"); return null; Loading @@ -145,7 +150,7 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa } return RebootEscrowKey.fromKeyBytes(escrowKeyBytes); } catch (TimeoutException | RemoteException | IOException e) { } catch (TimeoutException | RemoteException e) { Slog.w(TAG, "Failed to decrypt the server blob ", e); return null; } Loading