From 9fece1ec5a7c971d75207a193426e11b346883d7 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 26 Oct 2023 23:35:35 +0000 Subject: LockSettingsService: fix UnlockedDeviceRequired to work without LSKF The security improvements to Keystore's UnlockedDeviceRequired key protection in Android 12 regressed its behavior by making it no longer work for unsecured users, e.g. users with a Swipe lock screen. One of the things that broke it is that Keystore started superencrypting UnlockedDeviceRequired keys, yet Keystore unnecessarily ties superencryption to the existence of the user's LSKF. That is, Keystore creates a user's super keys only when an LSKF is set, and Keystore deletes all super keys and superencrypted keys when the LSKF is removed. To fix this, we're first making each user's Keystore super keys have the same lifetime as the user's synthetic password (and always be encrypted by it), which is very similar to how the CE storage key works starting in Android 14. Second, when a user's LSKF is removed, we're making Keystore delete *only* the user's auth-bound keys. This change implements the LockSettingsService side of the fix. This includes the following parts: - When initializing a user's synthetic password, LockSettingsService now initializes the user's Keystore super keys. - When upgrading to a build including this fix, LockSettingsService now does a one-time migration where it initializes the super keys for unsecured users. This is necessary to handle existing users. - When removing a user's LSKF, LockSettingsService now calls the new onUserLskfRemoved method of Keystore to delete auth-bound keys only. - Finally, when an unsecured user's CE storage is unlocked, LockSettingsService now unlocks the user's Keystore super keys too. Due to trunk-stable, these changes are actually behind a flag for now. Bug: 296464083 Test: see If12824369fbad4a90e5cd0427e792655fd233b96 Change-Id: Ib92a439c2c27cef54c28189dfb5beef68756528e --- .../security/AndroidKeyStoreMaintenance.java | 48 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'keystore/java') diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index b7ea04fdfe07..2beb434566e5 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -51,7 +51,7 @@ public class AndroidKeyStoreMaintenance { * @return 0 if successful or a {@code ResponseCode} * @hide */ - public static int onUserAdded(@NonNull int userId) { + public static int onUserAdded(int userId) { StrictMode.noteDiskWrite(); try { getService().onUserAdded(userId); @@ -65,6 +65,30 @@ public class AndroidKeyStoreMaintenance { } } + /** + * Tells Keystore to create a user's super keys and store them encrypted by the given secret. + * + * @param userId - Android user id of the user + * @param password - a secret derived from the user's synthetic password + * @param allowExisting - true if the keys already existing should not be considered an error + * @return 0 if successful or a {@code ResponseCode} + * @hide + */ + public static int initUserSuperKeys(int userId, @NonNull byte[] password, + boolean allowExisting) { + StrictMode.noteDiskWrite(); + try { + getService().initUserSuperKeys(userId, password, allowExisting); + return 0; + } catch (ServiceSpecificException e) { + Log.e(TAG, "initUserSuperKeys failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } + /** * Informs Keystore 2.0 about removing a user * @@ -109,6 +133,28 @@ public class AndroidKeyStoreMaintenance { } } + /** + * Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to + * Swipe or None. Keystore uses this notification to delete the user's auth-bound keys. + * + * @param userId - Android user id of the user + * @return 0 if successful or a {@code ResponseCode} + * @hide + */ + public static int onUserLskfRemoved(int userId) { + StrictMode.noteDiskWrite(); + try { + getService().onUserLskfRemoved(userId); + return 0; + } catch (ServiceSpecificException e) { + Log.e(TAG, "onUserLskfRemoved failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } + /** * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to * be cleared. -- cgit v1.2.3-59-g8ed1b