Delete keystore keys from RecoveryService.rebootRecoveryWithCommand() Adds deleteSecrets() to RecoverySystemService. This method is called from rebootRecoveryWithCommand () before the --wipe_data command is passed to recovery and the device is force-rebooted. deleteSecerts() calls IKeystoreMaintenance.deleteAllKeys() in order to quickly destroy the keys protecting the synthetic password blobs used to derive FBE encryption keys. The intent is to make FBE-encrypted data unrecoverable even if the full data wipe in recovery is interrupted or skipped. Bug: 324321147 Test: Manual - System -> Reset options -> Erase all data. Test: Hold VolDown key to interrupt reboot and stop at bootloader screen. Test: fastboot oem bcd wipe command && fastboot oem bcd wipe recovery Test: fastboot reboot Test: Device reboots into recovery and prompts to factory reset: Test: 'Cannot load Android system. Your data may be corrupt. ...' (cherry picked from https://android-review.googlesource.com/q/commit:0d00031851e9f5d8ef93947205a7e8b5257f0d8d) Ignore-AOSP-First: Security fix backport (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c85d5febdc186f7fa1af2d0a6bdf705683437a98) Merged-In: I5eb8e97f3ae1a18d5e7e7c2c7eca048ebff3440a Change-Id: I5eb8e97f3ae1a18d5e7e7c2c7eca048ebff3440a
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index 919a93b..b2d1755 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -18,8 +18,10 @@ import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; +import android.os.StrictMode; import android.security.maintenance.IKeystoreMaintenance; import android.system.keystore2.Domain; import android.system.keystore2.KeyDescriptor; @@ -183,4 +185,24 @@ return SYSTEM_ERROR; } } + + /** + * 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 9d5173a..91e2803 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -53,6 +53,7 @@ import android.os.SystemProperties; import android.provider.DeviceConfig; import android.sysprop.ApexProperties; +import android.security.AndroidKeyStoreMaintenance; import android.util.ArrayMap; import android.util.ArraySet; import android.util.FastImmutableArraySet; @@ -68,6 +69,7 @@ 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; @@ -119,6 +121,8 @@ 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; @@ -522,17 +526,32 @@ @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)) { return; } + if (isForcedWipe) { + deleteSecrets(); + } + // 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