diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index efbbfc23736fb342094331d8c9a986af63e9cb06..24aea371c094ab5537db80c61994ce3b9f3f8cf4 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -229,4 +229,24 @@ public class AndroidKeyStoreMaintenance { "Keystore error while trying to get apps affected by SID."); } } + + /** + * Deletes all keys in all KeyMint devices. + * Called by RecoverySystem before rebooting to recovery in order to delete all KeyMint keys, + * including synthetic password protector keys (used by LockSettingsService), as well as keys + * protecting DE and metadata encryption keys (used by vold). This ensures that FBE-encrypted + * data is unrecoverable even if the data wipe in recovery is interrupted or skipped. + */ + public static void deleteAllKeys() throws KeyStoreException { + StrictMode.noteDiskWrite(); + try { + getService().deleteAllKeys(); + } catch (RemoteException | NullPointerException e) { + throw new KeyStoreException(SYSTEM_ERROR, + "Failure to connect to Keystore while trying to delete all keys."); + } catch (ServiceSpecificException e) { + throw new KeyStoreException(e.errorCode, + "Keystore error while trying to delete all keys."); + } + } } diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index c2e2dadde857f12dc0a8b1b41885a611fa34bacc..9b3f991f722490bcab4d0ba32156f433e38d8c45 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -52,6 +52,7 @@ import android.os.ServiceManager; import android.os.ShellCallback; import android.os.SystemProperties; import android.provider.DeviceConfig; +import android.security.AndroidKeyStoreMaintenance; import android.util.ArrayMap; import android.util.ArraySet; import android.util.FastImmutableArraySet; @@ -67,6 +68,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.ApexManager; import com.android.server.recoverysystem.hal.BootControlHIDL; +import com.android.server.utils.Slogf; import libcore.io.IoUtils; @@ -118,6 +120,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp"; static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count"; + static final String RECOVERY_WIPE_DATA_COMMAND = "--wipe_data"; + private final Injector mInjector; private final Context mContext; @@ -521,18 +525,35 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo @Override // Binder call public void rebootRecoveryWithCommand(String command) { if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]"); + + boolean isForcedWipe = command != null && command.contains(RECOVERY_WIPE_DATA_COMMAND); synchronized (sRequestLock) { if (!setupOrClearBcb(true, command)) { Slog.e(TAG, "rebootRecoveryWithCommand failed to setup BCB"); return; } + if (isForcedWipe) { + deleteSecrets(); + // TODO: consider adding a dedicated forced-wipe-reboot method to PowerManager and + // calling here. + } + // Having set up the BCB, go ahead and reboot. PowerManager pm = mInjector.getPowerManager(); pm.reboot(PowerManager.REBOOT_RECOVERY); } } + private static void deleteSecrets() { + Slogf.w(TAG, "deleteSecrets"); + try { + AndroidKeyStoreMaintenance.deleteAllKeys(); + } catch (android.security.KeyStoreException e) { + Log.wtf(TAG, "Failed to delete all keys from keystore.", e); + } + } + private void enforcePermissionForResumeOnReboot() { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY) != PackageManager.PERMISSION_GRANTED