Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +82 −29 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.android.internal.widget.LockPatternUtils.USER_FRP; import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled; import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled; import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential; import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.UserIdInt; Loading Loading @@ -169,6 +170,20 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; // No challenge provided private static final int CHALLENGE_NONE = 0; // Challenge was provided from the external caller (non-LockSettingsService) private static final int CHALLENGE_FROM_CALLER = 1; // Challenge was generated from within LockSettingsService, for resetLockout. When challenge // type is set to internal, LSS will revokeChallenge after all profiles for that user are // unlocked. private static final int CHALLENGE_INTERNAL = 2; @IntDef({CHALLENGE_NONE, CHALLENGE_FROM_CALLER, CHALLENGE_INTERNAL}) @interface ChallengeType {}; // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. // Do not call into ActivityManager while holding mSpManager lock. private final Object mSeparateChallengeLock = new Object(); private final Object mSeparateChallengeLock = new Object(); Loading Loading @@ -276,6 +291,15 @@ public class LockSettingsService extends ILockSettings.Stub { } } } } private class PendingResetLockout { final int mUserId; final byte[] mHAT; PendingResetLockout(int userId, byte[] hat) { mUserId = userId; mHAT = hat; } } /** /** * Tie managed profile to primary profile if it is in unified mode and not tied before. * Tie managed profile to primary profile if it is in unified mode and not tied before. * * Loading Loading @@ -585,7 +609,7 @@ public class LockSettingsService extends ILockSettings.Stub { // be still locked, we ignore this case since the user will be prompted to unlock // be still locked, we ignore this case since the user will be prompted to unlock // the device after boot. // the device after boot. unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, false /* hasChallenge */, 0 /* challenge */); CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */); } catch (RemoteException e) { } catch (RemoteException e) { Slog.e(TAG, "Failed to unlock child profile"); Slog.e(TAG, "Failed to unlock child profile"); } } Loading Loading @@ -1162,12 +1186,14 @@ public class LockSettingsService extends ILockSettings.Stub { } } private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, boolean hasChallenge, long challenge) @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { throws RemoteException { try { try { doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), CREDENTIAL_TYPE_PASSWORD, CREDENTIAL_TYPE_PASSWORD, hasChallenge, challenge, profileHandle, null /* progressCallback */); challengeType, challenge, profileHandle, null /* progressCallback */, resetLockouts); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException | NoSuchAlgorithmException | NoSuchPaddingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | InvalidAlgorithmParameterException | IllegalBlockSizeException Loading @@ -1183,7 +1209,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } private void unlockUser(int userId, byte[] token, byte[] secret) { private void unlockUser(int userId, byte[] token, byte[] secret) { unlockUser(userId, token, secret, false /* hasChallenge */, 0 /* challenge */); unlockUser(userId, token, secret, CHALLENGE_NONE, 0 /* challenge */, null); } } /** /** Loading @@ -1195,7 +1221,8 @@ public class LockSettingsService extends ILockSettings.Stub { * {@link com.android.server.SystemServiceManager#unlockUser} </em> * {@link com.android.server.SystemServiceManager#unlockUser} </em> */ */ private void unlockUser(int userId, byte[] token, byte[] secret, private void unlockUser(int userId, byte[] token, byte[] secret, boolean hasChallenge, long challenge) { @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts) { // TODO: make this method fully async so we can update UI with progress strings // TODO: make this method fully async so we can update UI with progress strings final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId); final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId); final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1); Loading Loading @@ -1240,7 +1267,7 @@ public class LockSettingsService extends ILockSettings.Stub { // Must pass the challenge on for resetLockout, so it's not over-written, which // Must pass the challenge on for resetLockout, so it's not over-written, which // causes LockSettingsService to revokeChallenge inappropriately. // causes LockSettingsService to revokeChallenge inappropriately. unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, hasChallenge, challenge); challengeType, challenge, resetLockouts); } catch (RemoteException e) { } catch (RemoteException e) { Log.d(TAG, "Failed to unlock child profile", e); Log.d(TAG, "Failed to unlock child profile", e); } } Loading @@ -1257,6 +1284,20 @@ public class LockSettingsService extends ILockSettings.Stub { } } } } if (resetLockouts != null && !resetLockouts.isEmpty()) { mHandler.post(() -> { final BiometricManager bm = mContext.getSystemService(BiometricManager.class); final PackageManager pm = mContext.getPackageManager(); for (int i = 0; i < resetLockouts.size(); i++) { bm.resetLockout(resetLockouts.get(i).mHAT); } if (challengeType == CHALLENGE_INTERNAL && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { mContext.getSystemService(FaceManager.class).revokeChallenge(); } }); } } } private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) { private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) { Loading Loading @@ -1528,7 +1569,8 @@ public class LockSettingsService extends ILockSettings.Stub { setUserKeyProtection(userId, credential, convertResponse(gkResponse)); setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); fixateNewestUserKeyAuth(userId); // Refresh the auth token // Refresh the auth token doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */); doVerifyCredential(credential, credentialType, CHALLENGE_FROM_CALLER, 0, userId, null /* progressCallback */); synchronizeUnifiedWorkChallengeForProfiles(userId, null); synchronizeUnifiedWorkChallengeForProfiles(userId, null); sendCredentialsOnChangeIfRequired( sendCredentialsOnChangeIfRequired( credentialType, credential, userId, isLockTiedToParent); credentialType, credential, userId, isLockTiedToParent); Loading Loading @@ -1753,24 +1795,32 @@ public class LockSettingsService extends ILockSettings.Stub { public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback) throws RemoteException { checkPasswordReadPermission(userId); checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, false, 0, userId, progressCallback); return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback); } } @Override @Override public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, int userId) throws RemoteException { int userId) throws RemoteException { checkPasswordReadPermission(userId); checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, true, challenge, userId, return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId, null /* progressCallback */); null /* progressCallback */); } } private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { return doVerifyCredential(credential, credentialType, challengeType, challenge, userId, progressCallback, null /* resetLockouts */); } /** /** * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * format. * format. */ */ private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, boolean hasChallenge, long challenge, int userId, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { if (credential == null || credential.length == 0) { if (credential == null || credential.length == 0) { throw new IllegalArgumentException("Credential can't be null or empty"); throw new IllegalArgumentException("Credential can't be null or empty"); } } Loading @@ -1780,8 +1830,8 @@ public class LockSettingsService extends ILockSettings.Stub { return VerifyCredentialResponse.ERROR; return VerifyCredentialResponse.ERROR; } } VerifyCredentialResponse response = null; VerifyCredentialResponse response = null; response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge, response = spBasedDoVerifyCredential(credential, credentialType, challengeType, challenge, userId, progressCallback); userId, progressCallback, resetLockouts); // The user employs synthetic password based credential. // The user employs synthetic password based credential. if (response != null) { if (response != null) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { Loading Loading @@ -1813,7 +1863,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } response = verifyCredential(userId, storedHash, credentialToVerify, response = verifyCredential(userId, storedHash, credentialToVerify, hasChallenge, challenge, progressCallback); challengeType, challenge, progressCallback); if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); Loading @@ -1839,7 +1889,7 @@ public class LockSettingsService extends ILockSettings.Stub { final VerifyCredentialResponse parentResponse = doVerifyCredential( final VerifyCredentialResponse parentResponse = doVerifyCredential( credential, credential, type, type, true /* hasChallenge */, CHALLENGE_FROM_CALLER, challenge, challenge, parentProfileId, parentProfileId, null /* progressCallback */); null /* progressCallback */); Loading @@ -1852,7 +1902,7 @@ public class LockSettingsService extends ILockSettings.Stub { // Unlock work profile, and work profile with unified lock must use password only // Unlock work profile, and work profile with unified lock must use password only return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), CREDENTIAL_TYPE_PASSWORD, CREDENTIAL_TYPE_PASSWORD, true, CHALLENGE_FROM_CALLER, challenge, challenge, userId, null /* progressCallback */); userId, null /* progressCallback */); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException Loading @@ -1870,7 +1920,7 @@ public class LockSettingsService extends ILockSettings.Stub { * hash to GK. * hash to GK. */ */ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, byte[] credential, boolean hasChallenge, long challenge, byte[] credential, @ChallengeType int challengeType, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback) throws RemoteException { if ((storedHash == null || storedHash.hash.length == 0) if ((storedHash == null || storedHash.hash.length == 0) && (credential == null || credential.length == 0)) { && (credential == null || credential.length == 0)) { Loading Loading @@ -1913,7 +1963,7 @@ public class LockSettingsService extends ILockSettings.Stub { : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC /* TODO(roosa): keep the same password quality */, /* TODO(roosa): keep the same password quality */, userId, false, /* isLockTiedToParent= */ false); userId, false, /* isLockTiedToParent= */ false); if (!hasChallenge) { if (challengeType == CHALLENGE_NONE) { notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); // Use credentials to create recoverable keystore snapshot. // Use credentials to create recoverable keystore snapshot. sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); Loading Loading @@ -2501,12 +2551,13 @@ public class LockSettingsService extends ILockSettings.Stub { } } private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, @CredentialType int credentialType, boolean hasChallenge, long challenge, int userId, @CredentialType int credentialType, @ChallengeType int challengeType, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { int userId, ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " hasChallenge=" + hasChallenge Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " challengeType=" + challengeType + " hasEnrolledBiometrics=" + hasEnrolledBiometrics); + " hasEnrolledBiometrics=" + hasEnrolledBiometrics); if (credentialType == CREDENTIAL_TYPE_NONE) { if (credentialType == CREDENTIAL_TYPE_NONE) { userCredential = null; userCredential = null; Loading @@ -2516,8 +2567,11 @@ public class LockSettingsService extends ILockSettings.Stub { // TODO: When lockout is handled under the HAL for all biometrics (fingerprint), // TODO: When lockout is handled under the HAL for all biometrics (fingerprint), // we need to generate challenge for each one, have it signed by GK and reset lockout // we need to generate challenge for each one, have it signed by GK and reset lockout // for each modality. // for each modality. if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE) if (challengeType == CHALLENGE_NONE && pm.hasSystemFeature(PackageManager.FEATURE_FACE) && hasEnrolledBiometrics) { && hasEnrolledBiometrics) { // If there are multiple profiles in the same account, ensure we only generate the // challenge once. challengeType = CHALLENGE_INTERNAL; challenge = mContext.getSystemService(FaceManager.class).generateChallenge(); challenge = mContext.getSystemService(FaceManager.class).generateChallenge(); } } Loading Loading @@ -2559,19 +2613,18 @@ public class LockSettingsService extends ILockSettings.Stub { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId); notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId); unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); // Reset lockout only if user has enrolled templates if (hasEnrolledBiometrics) { BiometricManager bm = mContext.getSystemService(BiometricManager.class); bm.resetLockout(response.getPayload()); if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { // Do resetLockout / revokeChallenge when all profiles are unlocked mContext.getSystemService(FaceManager.class).revokeChallenge(); if (hasEnrolledBiometrics) { if (resetLockouts == null) { resetLockouts = new ArrayList<>(); } } resetLockouts.add(new PendingResetLockout(userId, response.getPayload())); } } final byte[] secret = authResult.authToken.deriveDiskEncryptionKey(); final byte[] secret = authResult.authToken.deriveDiskEncryptionKey(); Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length); Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length); unlockUser(userId, null, secret, hasChallenge, challenge); unlockUser(userId, null, secret, challengeType, challenge, resetLockouts); activateEscrowTokens(authResult.authToken, userId); activateEscrowTokens(authResult.authToken, userId); Loading Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +82 −29 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import static com.android.internal.widget.LockPatternUtils.USER_FRP; import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled; import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled; import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential; import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.annotation.UserIdInt; Loading Loading @@ -169,6 +170,20 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge"; private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; private static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; // No challenge provided private static final int CHALLENGE_NONE = 0; // Challenge was provided from the external caller (non-LockSettingsService) private static final int CHALLENGE_FROM_CALLER = 1; // Challenge was generated from within LockSettingsService, for resetLockout. When challenge // type is set to internal, LSS will revokeChallenge after all profiles for that user are // unlocked. private static final int CHALLENGE_INTERNAL = 2; @IntDef({CHALLENGE_NONE, CHALLENGE_FROM_CALLER, CHALLENGE_INTERNAL}) @interface ChallengeType {}; // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. // Do not call into ActivityManager while holding mSpManager lock. private final Object mSeparateChallengeLock = new Object(); private final Object mSeparateChallengeLock = new Object(); Loading Loading @@ -276,6 +291,15 @@ public class LockSettingsService extends ILockSettings.Stub { } } } } private class PendingResetLockout { final int mUserId; final byte[] mHAT; PendingResetLockout(int userId, byte[] hat) { mUserId = userId; mHAT = hat; } } /** /** * Tie managed profile to primary profile if it is in unified mode and not tied before. * Tie managed profile to primary profile if it is in unified mode and not tied before. * * Loading Loading @@ -585,7 +609,7 @@ public class LockSettingsService extends ILockSettings.Stub { // be still locked, we ignore this case since the user will be prompted to unlock // be still locked, we ignore this case since the user will be prompted to unlock // the device after boot. // the device after boot. unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */, false /* hasChallenge */, 0 /* challenge */); CHALLENGE_NONE, 0 /* challenge */, null /* resetLockouts */); } catch (RemoteException e) { } catch (RemoteException e) { Slog.e(TAG, "Failed to unlock child profile"); Slog.e(TAG, "Failed to unlock child profile"); } } Loading Loading @@ -1162,12 +1186,14 @@ public class LockSettingsService extends ILockSettings.Stub { } } private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated, boolean hasChallenge, long challenge) @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { throws RemoteException { try { try { doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), CREDENTIAL_TYPE_PASSWORD, CREDENTIAL_TYPE_PASSWORD, hasChallenge, challenge, profileHandle, null /* progressCallback */); challengeType, challenge, profileHandle, null /* progressCallback */, resetLockouts); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException | NoSuchAlgorithmException | NoSuchPaddingException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException | InvalidAlgorithmParameterException | IllegalBlockSizeException Loading @@ -1183,7 +1209,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } private void unlockUser(int userId, byte[] token, byte[] secret) { private void unlockUser(int userId, byte[] token, byte[] secret) { unlockUser(userId, token, secret, false /* hasChallenge */, 0 /* challenge */); unlockUser(userId, token, secret, CHALLENGE_NONE, 0 /* challenge */, null); } } /** /** Loading @@ -1195,7 +1221,8 @@ public class LockSettingsService extends ILockSettings.Stub { * {@link com.android.server.SystemServiceManager#unlockUser} </em> * {@link com.android.server.SystemServiceManager#unlockUser} </em> */ */ private void unlockUser(int userId, byte[] token, byte[] secret, private void unlockUser(int userId, byte[] token, byte[] secret, boolean hasChallenge, long challenge) { @ChallengeType int challengeType, long challenge, @Nullable ArrayList<PendingResetLockout> resetLockouts) { // TODO: make this method fully async so we can update UI with progress strings // TODO: make this method fully async so we can update UI with progress strings final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId); final boolean alreadyUnlocked = mUserManager.isUserUnlockingOrUnlocked(userId); final CountDownLatch latch = new CountDownLatch(1); final CountDownLatch latch = new CountDownLatch(1); Loading Loading @@ -1240,7 +1267,7 @@ public class LockSettingsService extends ILockSettings.Stub { // Must pass the challenge on for resetLockout, so it's not over-written, which // Must pass the challenge on for resetLockout, so it's not over-written, which // causes LockSettingsService to revokeChallenge inappropriately. // causes LockSettingsService to revokeChallenge inappropriately. unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */, hasChallenge, challenge); challengeType, challenge, resetLockouts); } catch (RemoteException e) { } catch (RemoteException e) { Log.d(TAG, "Failed to unlock child profile", e); Log.d(TAG, "Failed to unlock child profile", e); } } Loading @@ -1257,6 +1284,20 @@ public class LockSettingsService extends ILockSettings.Stub { } } } } if (resetLockouts != null && !resetLockouts.isEmpty()) { mHandler.post(() -> { final BiometricManager bm = mContext.getSystemService(BiometricManager.class); final PackageManager pm = mContext.getPackageManager(); for (int i = 0; i < resetLockouts.size(); i++) { bm.resetLockout(resetLockouts.get(i).mHAT); } if (challengeType == CHALLENGE_INTERNAL && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { mContext.getSystemService(FaceManager.class).revokeChallenge(); } }); } } } private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) { private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) { Loading Loading @@ -1528,7 +1569,8 @@ public class LockSettingsService extends ILockSettings.Stub { setUserKeyProtection(userId, credential, convertResponse(gkResponse)); setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); fixateNewestUserKeyAuth(userId); // Refresh the auth token // Refresh the auth token doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */); doVerifyCredential(credential, credentialType, CHALLENGE_FROM_CALLER, 0, userId, null /* progressCallback */); synchronizeUnifiedWorkChallengeForProfiles(userId, null); synchronizeUnifiedWorkChallengeForProfiles(userId, null); sendCredentialsOnChangeIfRequired( sendCredentialsOnChangeIfRequired( credentialType, credential, userId, isLockTiedToParent); credentialType, credential, userId, isLockTiedToParent); Loading Loading @@ -1753,24 +1795,32 @@ public class LockSettingsService extends ILockSettings.Stub { public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback) throws RemoteException { checkPasswordReadPermission(userId); checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, false, 0, userId, progressCallback); return doVerifyCredential(credential, type, CHALLENGE_NONE, 0, userId, progressCallback); } } @Override @Override public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, int userId) throws RemoteException { int userId) throws RemoteException { checkPasswordReadPermission(userId); checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, true, challenge, userId, return doVerifyCredential(credential, type, CHALLENGE_FROM_CALLER, challenge, userId, null /* progressCallback */); null /* progressCallback */); } } private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { return doVerifyCredential(credential, credentialType, challengeType, challenge, userId, progressCallback, null /* resetLockouts */); } /** /** * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * format. * format. */ */ private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, boolean hasChallenge, long challenge, int userId, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { if (credential == null || credential.length == 0) { if (credential == null || credential.length == 0) { throw new IllegalArgumentException("Credential can't be null or empty"); throw new IllegalArgumentException("Credential can't be null or empty"); } } Loading @@ -1780,8 +1830,8 @@ public class LockSettingsService extends ILockSettings.Stub { return VerifyCredentialResponse.ERROR; return VerifyCredentialResponse.ERROR; } } VerifyCredentialResponse response = null; VerifyCredentialResponse response = null; response = spBasedDoVerifyCredential(credential, credentialType, hasChallenge, challenge, response = spBasedDoVerifyCredential(credential, credentialType, challengeType, challenge, userId, progressCallback); userId, progressCallback, resetLockouts); // The user employs synthetic password based credential. // The user employs synthetic password based credential. if (response != null) { if (response != null) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { Loading Loading @@ -1813,7 +1863,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } response = verifyCredential(userId, storedHash, credentialToVerify, response = verifyCredential(userId, storedHash, credentialToVerify, hasChallenge, challenge, progressCallback); challengeType, challenge, progressCallback); if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); mStrongAuth.reportSuccessfulStrongAuthUnlock(userId); Loading @@ -1839,7 +1889,7 @@ public class LockSettingsService extends ILockSettings.Stub { final VerifyCredentialResponse parentResponse = doVerifyCredential( final VerifyCredentialResponse parentResponse = doVerifyCredential( credential, credential, type, type, true /* hasChallenge */, CHALLENGE_FROM_CALLER, challenge, challenge, parentProfileId, parentProfileId, null /* progressCallback */); null /* progressCallback */); Loading @@ -1852,7 +1902,7 @@ public class LockSettingsService extends ILockSettings.Stub { // Unlock work profile, and work profile with unified lock must use password only // Unlock work profile, and work profile with unified lock must use password only return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), CREDENTIAL_TYPE_PASSWORD, CREDENTIAL_TYPE_PASSWORD, true, CHALLENGE_FROM_CALLER, challenge, challenge, userId, null /* progressCallback */); userId, null /* progressCallback */); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException Loading @@ -1870,7 +1920,7 @@ public class LockSettingsService extends ILockSettings.Stub { * hash to GK. * hash to GK. */ */ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, byte[] credential, boolean hasChallenge, long challenge, byte[] credential, @ChallengeType int challengeType, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { ICheckCredentialProgressCallback progressCallback) throws RemoteException { if ((storedHash == null || storedHash.hash.length == 0) if ((storedHash == null || storedHash.hash.length == 0) && (credential == null || credential.length == 0)) { && (credential == null || credential.length == 0)) { Loading Loading @@ -1913,7 +1963,7 @@ public class LockSettingsService extends ILockSettings.Stub { : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC /* TODO(roosa): keep the same password quality */, /* TODO(roosa): keep the same password quality */, userId, false, /* isLockTiedToParent= */ false); userId, false, /* isLockTiedToParent= */ false); if (!hasChallenge) { if (challengeType == CHALLENGE_NONE) { notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); // Use credentials to create recoverable keystore snapshot. // Use credentials to create recoverable keystore snapshot. sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); Loading Loading @@ -2501,12 +2551,13 @@ public class LockSettingsService extends ILockSettings.Stub { } } private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, @CredentialType int credentialType, boolean hasChallenge, long challenge, int userId, @CredentialType int credentialType, @ChallengeType int challengeType, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { int userId, ICheckCredentialProgressCallback progressCallback, @Nullable ArrayList<PendingResetLockout> resetLockouts) throws RemoteException { final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " hasChallenge=" + hasChallenge Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId + " challengeType=" + challengeType + " hasEnrolledBiometrics=" + hasEnrolledBiometrics); + " hasEnrolledBiometrics=" + hasEnrolledBiometrics); if (credentialType == CREDENTIAL_TYPE_NONE) { if (credentialType == CREDENTIAL_TYPE_NONE) { userCredential = null; userCredential = null; Loading @@ -2516,8 +2567,11 @@ public class LockSettingsService extends ILockSettings.Stub { // TODO: When lockout is handled under the HAL for all biometrics (fingerprint), // TODO: When lockout is handled under the HAL for all biometrics (fingerprint), // we need to generate challenge for each one, have it signed by GK and reset lockout // we need to generate challenge for each one, have it signed by GK and reset lockout // for each modality. // for each modality. if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE) if (challengeType == CHALLENGE_NONE && pm.hasSystemFeature(PackageManager.FEATURE_FACE) && hasEnrolledBiometrics) { && hasEnrolledBiometrics) { // If there are multiple profiles in the same account, ensure we only generate the // challenge once. challengeType = CHALLENGE_INTERNAL; challenge = mContext.getSystemService(FaceManager.class).generateChallenge(); challenge = mContext.getSystemService(FaceManager.class).generateChallenge(); } } Loading Loading @@ -2559,19 +2613,18 @@ public class LockSettingsService extends ILockSettings.Stub { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId); notifyActivePasswordMetricsAvailable(credentialType, userCredential, userId); unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId); // Reset lockout only if user has enrolled templates if (hasEnrolledBiometrics) { BiometricManager bm = mContext.getSystemService(BiometricManager.class); bm.resetLockout(response.getPayload()); if (!hasChallenge && pm.hasSystemFeature(PackageManager.FEATURE_FACE)) { // Do resetLockout / revokeChallenge when all profiles are unlocked mContext.getSystemService(FaceManager.class).revokeChallenge(); if (hasEnrolledBiometrics) { if (resetLockouts == null) { resetLockouts = new ArrayList<>(); } } resetLockouts.add(new PendingResetLockout(userId, response.getPayload())); } } final byte[] secret = authResult.authToken.deriveDiskEncryptionKey(); final byte[] secret = authResult.authToken.deriveDiskEncryptionKey(); Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length); Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length); unlockUser(userId, null, secret, hasChallenge, challenge); unlockUser(userId, null, secret, challengeType, challenge, resetLockouts); activateEscrowTokens(authResult.authToken, userId); activateEscrowTokens(authResult.authToken, userId); Loading