diff options
author | Eric Biggers <ebiggers@google.com> | 2024-01-17 22:51:04 +0000 |
---|---|---|
committer | Eric Biggers <ebiggers@google.com> | 2024-01-17 22:51:04 +0000 |
commit | cd7f4fada9cd5b3e4be2518b8c6ab6fb4dd95996 (patch) | |
tree | 05bc8fe41b474fba01a79d7a333691bef317c06a /keystore | |
parent | 31fd707aed3a7fd0253905d5c8b4ca87ba5b7a57 (diff) | |
download | base-cd7f4fada9cd5b3e4be2518b8c6ab6fb4dd95996.tar.gz |
Fix UnlockedDeviceRequired with weak unlock methods
Starting in Android 12, unlocking the device with a class 1
("convenience") biometric, class 2 ("weak") biometric, or a trust agent
unexpectedly doesn't allow the use of UnlockedDeviceRequired keys. The
cause of this bug is that the cryptographic protection that Keystore now
applies to UnlockedDeviceRequired keys incorrectly assumes that the
device can only be unlocked using LSKF or via a biometric that
participates in Keystore (has a SID and uses HardwareAuthTokens).
Actually, Keyguard also allows the device to be unlocked using weaker
biometrics that do not particiate in Keystore, if they are enrolled.
Similarly, there are also cases where a trust agent can actively unlock
the device, e.g. unlocking a phone using a paired watch.
In combination with the Keystore changes in
I1b0d9ec4f9e31dc91642e865045766bd17e34cad, this CL fixes the bug by
making Keystore retain the UnlockedDeviceRequired super keys in memory
if a weak unlock method is enabled at device lock time. This does mean
that UnlockedDeviceRequired is enforced only logically when a weak
unlock method is enabled, but this is the best we can do in this case.
Note: a future CL will take into account the progressive expiration of
unlock methods while the device is locked and upgrade the security of
UnlockedDeviceRequired accordingly. The present CL focuses just on
choosing the correct protection at lock time, fixing a user-visible bug.
Test: Ran the following automated tests with and without the
fix_unlocked_device_required_keys_v2 flag enabled:
atest com.android.server.locksettings \
&& atest TrustManagerServiceTest \
&& atest TrustTests \
&& atest -p --include-subdirs system/security/keystore2 \
&& atest CtsKeystoreTestCases
Test: Manually tested each combination of biometric setup: none,
fingerprint, face, and fingerprint+face. Locked the device, then
verified via logcat that Keystore protected the
UnlockedDeviceRequired keys in the expected way, then verified
that UnlockedDeviceRequired keys cannot be used (even in the case
where the super keys were not protected). Unlocked device using
weakest method available, then verified that
UnlockedDeviceRequired keys can be used. To check whether
UnlockedDeviceRequired keys can be used or not, used the CTS
method mentioned in the Test of https://r.android.com/2878769.
Also, enabled Extend Unlock with a bluetooth device, and verified
that it's not counted as an unlock method.
Also, verified that if Lockdown mode is triggered, the
UnlockedDeviceRequired keys are fully protected.
Bug: 296464083
Change-Id: I34dc49f1338e94755e96c1cf84de0638dc70d311
Diffstat (limited to 'keystore')
-rw-r--r-- | keystore/java/android/security/Authorization.java | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index 4ec5e1b67c5d..6404c4bc33d6 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -100,12 +100,14 @@ public class Authorization { * * @param userId - the user's Android user ID * @param unlockingSids - list of biometric SIDs with which the device may be unlocked again + * @param weakUnlockEnabled - true if non-strong biometric or trust agent unlock is enabled * @return 0 if successful or a {@code ResponseCode}. */ - public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids) { + public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids, + boolean weakUnlockEnabled) { StrictMode.noteDiskWrite(); try { - getService().onDeviceLocked(userId, unlockingSids); + getService().onDeviceLocked(userId, unlockingSids, weakUnlockEnabled); return 0; } catch (RemoteException | NullPointerException e) { Log.w(TAG, "Can not connect to keystore", e); |