Remove obsolete support for nonempty credential without SP
All users with a nonempty lockscreen credential now have a synthetic
password (SP), due to the migration logic that was enabled in
Android O MR1 (commit 7a0cc0a7fb / http://ag/2339115). For this to
not be the case, a device that launched with Android O or earlier would
have to be upgraded all the way to Android U. That's unsupported; and
even if it was supported, the migration to SP would have happened if the
user was unlocked even just once with *any* version O MR1 through T.
Therefore, there's no longer any need to support the non-SP case except
when credentialType == CREDENTIAL_TYPE_NONE.
Remove all the relevant code that is no longer needed.
Bug: 146040259
Test: atest com.android.server.locksettings
Test: Upgraded a device that has an LSKF set, then unlocked the device
and changed the LSKF.
Test: m services FrameworksServicesTests RUN_ERROR_PRONE=true
Change-Id: I08ff4d86379e3289ed8aa02b286a92b3ae431367
This commit is contained in:
@@ -73,7 +73,6 @@ import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.hardware.authsecret.V1_0.IAuthSecret;
|
||||
import android.hardware.biometrics.BiometricManager;
|
||||
import android.hardware.face.Face;
|
||||
import android.hardware.face.FaceManager;
|
||||
import android.hardware.fingerprint.Fingerprint;
|
||||
@@ -89,7 +88,6 @@ import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.StrictMode;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
@@ -110,7 +108,6 @@ import android.security.keystore.recovery.RecoveryCertPath;
|
||||
import android.security.keystore.recovery.WrappedApplicationKey;
|
||||
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
|
||||
import android.security.keystore2.AndroidKeyStoreProvider;
|
||||
import android.service.gatekeeper.GateKeeperResponse;
|
||||
import android.service.gatekeeper.IGateKeeperService;
|
||||
import android.system.keystore2.Domain;
|
||||
import android.text.TextUtils;
|
||||
@@ -141,7 +138,6 @@ import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.ServiceThread;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
|
||||
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
|
||||
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
|
||||
import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
|
||||
@@ -163,7 +159,6 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
@@ -517,11 +512,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return new RebootEscrowManager(mContext, callbacks, storage);
|
||||
}
|
||||
|
||||
public boolean hasEnrolledBiometrics(int userId) {
|
||||
BiometricManager bm = mContext.getSystemService(BiometricManager.class);
|
||||
return bm.hasEnrolledBiometrics(userId);
|
||||
}
|
||||
|
||||
public int binderGetCallingUid() {
|
||||
return Binder.getCallingUid();
|
||||
}
|
||||
@@ -1285,11 +1275,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return mStorage.getString(key, defaultValue, userId);
|
||||
}
|
||||
|
||||
private void setKeyguardStoredQuality(int quality, int userId) {
|
||||
if (DEBUG) Slog.d(TAG, "setKeyguardStoredQuality: user=" + userId + " quality=" + quality);
|
||||
mStorage.setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, userId);
|
||||
}
|
||||
|
||||
// Not relevant for new devices, but some legacy devices still have PASSWORD_TYPE_KEY around to
|
||||
// distinguish between credential types.
|
||||
private int getKeyguardStoredQuality(int userId) {
|
||||
return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
|
||||
@@ -1326,18 +1313,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return pinOrPasswordQualityToCredentialType(getKeyguardStoredQuality(userId));
|
||||
}
|
||||
}
|
||||
// Intentional duplication of the getKeyguardStoredQuality() call above since this is a
|
||||
// unlikely code path (device with pre-synthetic password credential). We want to skip
|
||||
// calling getKeyguardStoredQuality whenever possible.
|
||||
final int savedQuality = getKeyguardStoredQuality(userId);
|
||||
if (savedQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
&& mStorage.hasPattern(userId)) {
|
||||
return CREDENTIAL_TYPE_PATTERN;
|
||||
}
|
||||
if (savedQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|
||||
&& mStorage.hasPassword(userId)) {
|
||||
return pinOrPasswordQualityToCredentialType(savedQuality);
|
||||
}
|
||||
return CREDENTIAL_TYPE_NONE;
|
||||
}
|
||||
|
||||
@@ -1742,33 +1717,15 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
|
||||
Objects.requireNonNull(credential);
|
||||
Objects.requireNonNull(savedCredential);
|
||||
if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
|
||||
synchronized (mSpManager) {
|
||||
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
|
||||
isLockTiedToParent);
|
||||
}
|
||||
}
|
||||
|
||||
if (credential.isNone()) {
|
||||
clearUserKeyProtection(userId, null);
|
||||
gateKeeperClearSecureUserId(userId);
|
||||
mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
|
||||
// Still update PASSWORD_TYPE_KEY if we are running in pre-synthetic password code path,
|
||||
// since it forms part of the state that determines the credential type
|
||||
// @see getCredentialTypeInternal
|
||||
setKeyguardStoredQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
|
||||
setKeystorePassword(null, userId);
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
|
||||
setUserPasswordMetrics(LockscreenCredential.createNone(), userId);
|
||||
sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
|
||||
return true;
|
||||
}
|
||||
|
||||
CredentialHash currentHandle = mStorage.readCredentialHash(userId);
|
||||
if (isProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed/clone profile has unified lock
|
||||
if (savedCredential.isNone()) {
|
||||
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
if (!savedCredential.isNone()) {
|
||||
throw new IllegalStateException("Saved credential given, but user has no SP");
|
||||
}
|
||||
initializeSyntheticPasswordLocked(savedCredential, userId);
|
||||
} else if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when profile has unified lock
|
||||
try {
|
||||
//TODO: remove as part of b/80170828
|
||||
savedCredential = getDecryptedPasswordForTiedProfile(userId);
|
||||
@@ -1781,19 +1738,31 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
Slog.e(TAG, "Failed to decrypt child profile key", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentHandle.hash == null) {
|
||||
if (!savedCredential.isNone()) {
|
||||
Slog.w(TAG, "Saved credential provided, but none stored");
|
||||
final long origHandle = getSyntheticPasswordHandleLocked(userId);
|
||||
AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
|
||||
getGateKeeperService(), origHandle, savedCredential, userId, null);
|
||||
VerifyCredentialResponse response = authResult.gkResponse;
|
||||
AuthenticationToken auth = authResult.authToken;
|
||||
|
||||
if (auth == null) {
|
||||
if (response == null
|
||||
|| response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
|
||||
Slog.w(TAG, "Failed to enroll: incorrect credential.");
|
||||
return false;
|
||||
}
|
||||
savedCredential.close();
|
||||
savedCredential = LockscreenCredential.createNone();
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
|
||||
Slog.w(TAG, "Failed to enroll: rate limit exceeded.");
|
||||
return false;
|
||||
}
|
||||
// Should not be reachable, but just in case.
|
||||
throw new IllegalStateException("password change failed");
|
||||
}
|
||||
}
|
||||
synchronized (mSpManager) {
|
||||
initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
|
||||
return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
|
||||
isLockTiedToParent);
|
||||
|
||||
onAuthTokenKnownForUser(userId, auth);
|
||||
setLockCredentialWithAuthTokenLocked(credential, auth, userId);
|
||||
mSpManager.destroyPasswordBasedSyntheticPassword(origHandle, userId);
|
||||
sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1912,10 +1881,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return getUserManagerFromCache(userId).isCredentialSharableWithParent();
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
|
||||
return VerifyCredentialResponse.fromGateKeeperResponse(gateKeeperResponse);
|
||||
}
|
||||
|
||||
private void setCredentialRequiredToDecrypt(boolean required) {
|
||||
if (isDeviceEncryptionEnabled()) {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
@@ -2089,21 +2054,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] secretFromCredential(LockscreenCredential credential) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-512");
|
||||
// Personalize the hash
|
||||
byte[] personalization = "Android FBE credential hash".getBytes();
|
||||
// Pad it to the block size of the hash function
|
||||
personalization = Arrays.copyOf(personalization, 128);
|
||||
digest.update(personalization);
|
||||
digest.update(credential.getCredential());
|
||||
return digest.digest();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("NoSuchAlgorithmException for SHA-512");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUserKeyUnlocked(int userId) {
|
||||
try {
|
||||
return mStorageManager.isUserKeyUnlocked(userId);
|
||||
@@ -2262,9 +2212,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
|
||||
* format.
|
||||
/**
|
||||
* Verify user credential and unlock the user.
|
||||
* @param credential User's lockscreen credential
|
||||
* @param userId User to verify the credential for
|
||||
* @param progressCallback Receive progress callbacks
|
||||
@@ -2282,36 +2231,59 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
Slog.d(TAG, "doVerifyCredential: user=" + userId);
|
||||
|
||||
VerifyCredentialResponse response = spBasedDoVerifyCredential(credential, userId,
|
||||
progressCallback, flags);
|
||||
final AuthenticationResult authResult;
|
||||
VerifyCredentialResponse response;
|
||||
|
||||
// The user employs synthetic password based credential.
|
||||
if (response != null) {
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
sendCredentialsOnUnlockIfRequired(credential, userId);
|
||||
synchronized (mSpManager) {
|
||||
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
Slog.wtf(TAG, "Unexpected credential type, should be SP based.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
if (userId == USER_FRP) {
|
||||
return mSpManager.verifyFrpCredential(getGateKeeperService(), credential,
|
||||
progressCallback);
|
||||
}
|
||||
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
|
||||
getGateKeeperService(), handle, credential, userId, progressCallback);
|
||||
response = authResult.gkResponse;
|
||||
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
// credential has matched
|
||||
mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
|
||||
authResult.authToken.deriveGkPassword());
|
||||
|
||||
// perform verifyChallenge with synthetic password which generates the real GK auth
|
||||
// token and response for the current user
|
||||
response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
|
||||
0L /* challenge */, userId);
|
||||
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
|
||||
// This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
|
||||
// match the recorded GK password handle.
|
||||
Slog.wtf(TAG, "verifyChallenge with SP failed.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
if (userId == USER_FRP) {
|
||||
Slog.wtf(TAG, "Unexpected FRP credential type, should be SP based.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
|
||||
final CredentialHash storedHash = mStorage.readCredentialHash(userId);
|
||||
if (!credential.checkAgainstStoredType(storedHash.type)) {
|
||||
Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
|
||||
+ " stored: " + storedHash.type + " passed in: " + credential.getType());
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
|
||||
response = verifyCredential(userId, storedHash, credential, progressCallback);
|
||||
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
|
||||
onCredentialVerified(authResult.authToken,
|
||||
PasswordMetrics.computeForCredential(credential), userId);
|
||||
if ((flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0) {
|
||||
final long gkHandle = storeGatekeeperPasswordTemporarily(
|
||||
authResult.authToken.deriveGkPassword());
|
||||
response = new VerifyCredentialResponse.Builder()
|
||||
.setGatekeeperPasswordHandle(gkHandle)
|
||||
.build();
|
||||
}
|
||||
sendCredentialsOnUnlockIfRequired(credential, userId);
|
||||
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
|
||||
if (response.getTimeout() > 0) {
|
||||
requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -2350,83 +2322,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowest-level credential verification routine that talks to GateKeeper. If verification
|
||||
* passes, unlock the corresponding user and keystore. Also handles the migration from legacy
|
||||
* hash to GK.
|
||||
*/
|
||||
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
|
||||
LockscreenCredential credential, ICheckCredentialProgressCallback progressCallback) {
|
||||
if ((storedHash == null || storedHash.hash.length == 0) && credential.isNone()) {
|
||||
// don't need to pass empty credentials to GateKeeper
|
||||
return VerifyCredentialResponse.OK;
|
||||
}
|
||||
|
||||
if (storedHash == null || storedHash.hash.length == 0 || credential.isNone()) {
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
|
||||
// We're potentially going to be doing a bunch of disk I/O below as part
|
||||
// of unlocking the user, so yell if calling from the main thread.
|
||||
StrictMode.noteDiskRead();
|
||||
|
||||
GateKeeperResponse gateKeeperResponse;
|
||||
try {
|
||||
gateKeeperResponse = getGateKeeperService().verifyChallenge(
|
||||
userId, 0L /* challenge */, storedHash.hash, credential.getCredential());
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "gatekeeper verify failed", e);
|
||||
gateKeeperResponse = GateKeeperResponse.ERROR;
|
||||
}
|
||||
VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
|
||||
boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
|
||||
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
|
||||
// credential has matched
|
||||
|
||||
if (progressCallback != null) {
|
||||
try {
|
||||
progressCallback.onCredentialVerified();
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "progressCallback throws exception", e);
|
||||
}
|
||||
}
|
||||
setUserPasswordMetrics(credential, userId);
|
||||
unlockKeystore(credential.getCredential(), userId);
|
||||
|
||||
Slog.i(TAG, "Unlocking user " + userId);
|
||||
unlockUser(userId, secretFromCredential(credential));
|
||||
|
||||
if (isProfileWithSeparatedLock(userId)) {
|
||||
setDeviceUnlockedForUser(userId);
|
||||
}
|
||||
if (shouldReEnroll) {
|
||||
setLockCredentialInternal(credential, credential,
|
||||
userId, /* isLockTiedToParent= */ false);
|
||||
} else {
|
||||
// Now that we've cleared of all required GK migration, let's do the final
|
||||
// migration to synthetic password.
|
||||
synchronized (mSpManager) {
|
||||
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
|
||||
AuthenticationToken auth = initializeSyntheticPasswordLocked(
|
||||
storedHash.hash, credential, userId);
|
||||
activateEscrowTokens(auth, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Use credentials to create recoverable keystore snapshot.
|
||||
sendCredentialsOnUnlockIfRequired(credential, userId);
|
||||
|
||||
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
|
||||
if (response.getTimeout() > 0) {
|
||||
requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of the given user's latest password metric. This should be called
|
||||
* when the user is authenticating or when a new password is being set. In comparison,
|
||||
@@ -2779,7 +2674,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* Precondition: vold and keystore unlocked.
|
||||
*
|
||||
* Create new synthetic password, set up synthetic password blob protected by the supplied
|
||||
* user credential, and make the newly-created SP blob active.
|
||||
* user credential, and make the newly-created SP blob active. This is called just once in the
|
||||
* lifetime of the user: the first time that a user credential is set (!credential.isNone()), or
|
||||
* when an escrow token is activated on an unsecured device (credential.isNone()).
|
||||
*
|
||||
* The invariant under a synthetic password is:
|
||||
* 1. If user credential exists, then both vold and keystore and protected with keys derived
|
||||
@@ -2793,47 +2690,21 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* protected by a default PIN.
|
||||
* 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
|
||||
* clears/re-creates their lockscreen PIN.
|
||||
*
|
||||
*
|
||||
* Different cases of calling this method:
|
||||
* 1. credentialHash != null
|
||||
* This implies credential != null, a new SP blob will be provisioned, and existing SID
|
||||
* migrated to associate with the new SP.
|
||||
* This happens during a normal migration case when the user currently has password.
|
||||
*
|
||||
* 2. credentialhash == null and credential == null
|
||||
* A new SP blob and will be created, while the user has no credentials.
|
||||
* This can happens when we are activating an escrow token on a unsecured device, during
|
||||
* which we want to create the SP structure with an empty user credential.
|
||||
* This could also happen during an untrusted reset to clear password.
|
||||
*
|
||||
* 3. credentialhash == null and credential != null
|
||||
* The user sets a new lockscreen password FOR THE FIRST TIME on a SP-enabled device.
|
||||
* New credential and new SID will be created
|
||||
*/
|
||||
@GuardedBy("mSpManager")
|
||||
@VisibleForTesting
|
||||
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
|
||||
LockscreenCredential credential, int userId) {
|
||||
AuthenticationToken initializeSyntheticPasswordLocked(LockscreenCredential credential,
|
||||
int userId) {
|
||||
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
|
||||
Preconditions.checkState(
|
||||
getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE,
|
||||
"Cannot reinitialize SP");
|
||||
|
||||
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
|
||||
getGateKeeperService(), credentialHash, credential, userId);
|
||||
if (auth == null) {
|
||||
Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
|
||||
return null;
|
||||
}
|
||||
final AuthenticationToken auth = mSpManager.newSyntheticPassword(userId);
|
||||
long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
|
||||
credential, auth, userId);
|
||||
if (!credential.isNone()) {
|
||||
if (credentialHash == null) {
|
||||
// Since when initializing SP, we didn't provide an existing password handle
|
||||
// for it to migrate SID, we need to create a new SID for the user.
|
||||
mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
|
||||
}
|
||||
mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
|
||||
mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
|
||||
setUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
setKeystorePassword(auth.deriveKeyStorePassword(), userId);
|
||||
@@ -2878,73 +2749,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
|
||||
return getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE;
|
||||
}
|
||||
|
||||
private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential,
|
||||
int userId, ICheckCredentialProgressCallback progressCallback,
|
||||
@LockPatternUtils.VerifyFlag int flags) {
|
||||
final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId);
|
||||
|
||||
Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId
|
||||
+ " hasEnrolledBiometrics=" + hasEnrolledBiometrics);
|
||||
|
||||
final AuthenticationResult authResult;
|
||||
VerifyCredentialResponse response;
|
||||
final boolean requestGkPw = (flags & VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0;
|
||||
|
||||
synchronized (mSpManager) {
|
||||
if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
return null;
|
||||
}
|
||||
if (userId == USER_FRP) {
|
||||
return mSpManager.verifyFrpCredential(getGateKeeperService(),
|
||||
userCredential, progressCallback);
|
||||
}
|
||||
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
|
||||
getGateKeeperService(), handle, userCredential, userId, progressCallback);
|
||||
response = authResult.gkResponse;
|
||||
|
||||
// credential has matched
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
|
||||
authResult.authToken.deriveGkPassword());
|
||||
|
||||
// perform verifyChallenge with synthetic password which generates the real GK auth
|
||||
// token and response for the current user
|
||||
response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
|
||||
0L /* challenge */, userId);
|
||||
if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
|
||||
// This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
|
||||
// match the recorded GK password handle.
|
||||
Slog.wtf(TAG, "verifyChallenge with SP failed.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
|
||||
onCredentialVerified(authResult.authToken,
|
||||
PasswordMetrics.computeForCredential(userCredential), userId);
|
||||
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
|
||||
if (response.getTimeout() > 0) {
|
||||
requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
|
||||
}
|
||||
}
|
||||
|
||||
if (response.isMatched() && requestGkPw) {
|
||||
final long handle = storeGatekeeperPasswordTemporarily(
|
||||
authResult.authToken.deriveGkPassword());
|
||||
return new VerifyCredentialResponse.Builder().setGatekeeperPasswordHandle(handle)
|
||||
.build();
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the gatekeeper password temporarily.
|
||||
* @param gatekeeperPassword unlocked upon successful Synthetic Password
|
||||
@@ -3148,56 +2952,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param savedCredential if the user is a profile with unified challenge and
|
||||
* savedCredential is empty, LSS will try to re-derive the profile password internally.
|
||||
* TODO (b/80170828): Fix this so profile password is always passed in.
|
||||
*/
|
||||
@GuardedBy("mSpManager")
|
||||
private boolean spBasedSetLockCredentialInternalLocked(LockscreenCredential credential,
|
||||
LockscreenCredential savedCredential, int userId, boolean isLockTiedToParent) {
|
||||
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
|
||||
if (savedCredential.isNone() && isProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when profile has unified lock
|
||||
try {
|
||||
//TODO: remove as part of b/80170828
|
||||
savedCredential = getDecryptedPasswordForTiedProfile(userId);
|
||||
} catch (FileNotFoundException e) {
|
||||
Slog.i(TAG, "Child profile key not found");
|
||||
} catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
|
||||
| NoSuchAlgorithmException | NoSuchPaddingException
|
||||
| InvalidAlgorithmParameterException | IllegalBlockSizeException
|
||||
| BadPaddingException | CertificateException | IOException e) {
|
||||
Slog.e(TAG, "Failed to decrypt child profile key", e);
|
||||
}
|
||||
}
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
|
||||
getGateKeeperService(), handle, savedCredential, userId, null);
|
||||
VerifyCredentialResponse response = authResult.gkResponse;
|
||||
AuthenticationToken auth = authResult.authToken;
|
||||
|
||||
if (auth == null) {
|
||||
if (response == null
|
||||
|| response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
|
||||
Slog.w(TAG, "Failed to enroll: incorrect credential.");
|
||||
return false;
|
||||
}
|
||||
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
|
||||
Slog.w(TAG, "Failed to enroll: rate limit exceeded.");
|
||||
return false;
|
||||
}
|
||||
// Should not be reachable, but just in case.
|
||||
throw new IllegalStateException("password change failed");
|
||||
}
|
||||
|
||||
onAuthTokenKnownForUser(userId, auth);
|
||||
setLockCredentialWithAuthTokenLocked(credential, auth, userId);
|
||||
mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
|
||||
sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
|
||||
* This is used to salt the password history hash to protect the hash against offline
|
||||
@@ -3244,20 +2998,18 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// the token can then be activated immediately.
|
||||
AuthenticationToken auth = null;
|
||||
if (!isUserSecure(userId)) {
|
||||
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
|
||||
auth = initializeSyntheticPasswordLocked(
|
||||
/* credentialHash */ null, LockscreenCredential.createNone(), userId);
|
||||
} else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
|
||||
long pwdHandle = getSyntheticPasswordHandleLocked(userId);
|
||||
long handle = getSyntheticPasswordHandleLocked(userId);
|
||||
if (handle == SyntheticPasswordManager.DEFAULT_HANDLE) {
|
||||
auth = initializeSyntheticPasswordLocked(LockscreenCredential.createNone(),
|
||||
userId);
|
||||
} else {
|
||||
auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
|
||||
pwdHandle, LockscreenCredential.createNone(), userId, null).authToken;
|
||||
handle, LockscreenCredential.createNone(), userId, null).authToken;
|
||||
}
|
||||
}
|
||||
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
|
||||
if (!mSpManager.hasEscrowData(userId)) {
|
||||
throw new SecurityException("Escrow token is disabled on the current user");
|
||||
}
|
||||
disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
|
||||
if (!mSpManager.hasEscrowData(userId)) {
|
||||
throw new SecurityException("Escrow token is disabled on the current user");
|
||||
}
|
||||
long handle = mSpManager.createTokenBasedSyntheticPassword(token, type, userId,
|
||||
callback);
|
||||
|
||||
@@ -85,8 +85,6 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
};
|
||||
|
||||
private static final String SYSTEM_DIRECTORY = "/system/";
|
||||
private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key";
|
||||
private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
|
||||
private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key";
|
||||
|
||||
private static final String REBOOT_ESCROW_FILE = "reboot.escrow.key";
|
||||
@@ -248,38 +246,6 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Populate cache by reading the password and pattern files.
|
||||
readCredentialHash(userId);
|
||||
}
|
||||
|
||||
private CredentialHash readPasswordHashIfExists(int userId) {
|
||||
byte[] stored = readFile(getLockPasswordFilename(userId));
|
||||
if (!ArrayUtils.isEmpty(stored)) {
|
||||
return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private CredentialHash readPatternHashIfExists(int userId) {
|
||||
byte[] stored = readFile(getLockPatternFilename(userId));
|
||||
if (!ArrayUtils.isEmpty(stored)) {
|
||||
return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public CredentialHash readCredentialHash(int userId) {
|
||||
CredentialHash passwordHash = readPasswordHashIfExists(userId);
|
||||
if (passwordHash != null) {
|
||||
return passwordHash;
|
||||
}
|
||||
|
||||
CredentialHash patternHash = readPatternHashIfExists(userId);
|
||||
if (patternHash != null) {
|
||||
return patternHash;
|
||||
}
|
||||
return CredentialHash.createEmptyHash();
|
||||
}
|
||||
|
||||
public void removeChildProfileLock(int userId) {
|
||||
@@ -336,14 +302,6 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
deleteFile(getRebootEscrowServerBlob());
|
||||
}
|
||||
|
||||
public boolean hasPassword(int userId) {
|
||||
return hasFile(getLockPasswordFilename(userId));
|
||||
}
|
||||
|
||||
public boolean hasPattern(int userId) {
|
||||
return hasFile(getLockPatternFilename(userId));
|
||||
}
|
||||
|
||||
private boolean hasFile(String name) {
|
||||
byte[] contents = readFile(name);
|
||||
return contents != null && contents.length > 0;
|
||||
@@ -429,33 +387,6 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeCredentialHash(CredentialHash hash, int userId) {
|
||||
byte[] patternHash = null;
|
||||
byte[] passwordHash = null;
|
||||
if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN
|
||||
|| hash.type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
|
||||
|| hash.type == LockPatternUtils.CREDENTIAL_TYPE_PIN) {
|
||||
passwordHash = hash.hash;
|
||||
} else if (hash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
|
||||
patternHash = hash.hash;
|
||||
} else {
|
||||
Preconditions.checkArgument(hash.type == LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
"Unknown credential type");
|
||||
}
|
||||
writeFile(getLockPasswordFilename(userId), passwordHash);
|
||||
writeFile(getLockPatternFilename(userId), patternHash);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getLockPatternFilename(int userId) {
|
||||
return getLockCredentialFilePathForUser(userId, LOCK_PATTERN_FILE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getLockPasswordFilename(int userId) {
|
||||
return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String getChildProfileLockFile(int userId) {
|
||||
return getLockCredentialFilePathForUser(userId, CHILD_PROFILE_LOCK_FILE);
|
||||
@@ -567,12 +498,7 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
|
||||
if (parentInfo == null) {
|
||||
// This user owns its lock settings files - safe to delete them
|
||||
synchronized (mFileWriteLock) {
|
||||
deleteFilesAndRemoveCache(
|
||||
getLockPasswordFilename(userId),
|
||||
getLockPatternFilename(userId),
|
||||
getRebootEscrowFile(userId));
|
||||
}
|
||||
deleteFile(getRebootEscrowFile(userId));
|
||||
} else {
|
||||
// Managed profile
|
||||
removeChildProfileLock(userId);
|
||||
@@ -594,17 +520,6 @@ class LockSettingsStorage extends WatchableImpl {
|
||||
dispatchChange(this);
|
||||
}
|
||||
|
||||
private void deleteFilesAndRemoveCache(String... names) {
|
||||
for (String name : names) {
|
||||
File file = new File(name);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
mCache.putFile(name, null);
|
||||
dispatchChange(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setBoolean(String key, boolean value, int userId) {
|
||||
setString(key, value ? "1" : "0", userId);
|
||||
}
|
||||
|
||||
@@ -599,47 +599,19 @@ public class SyntheticPasswordManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializing a new Authentication token, possibly from an existing credential and hash.
|
||||
* Initializes a new Authentication token for the given user.
|
||||
*
|
||||
* The authentication token would bear a randomly-generated synthetic password.
|
||||
* The authentication token will bear a randomly-generated synthetic password.
|
||||
*
|
||||
* This method has the side effect of rebinding the SID of the given user to the
|
||||
* newly-generated SP.
|
||||
*
|
||||
* If the existing credential hash is non-null, the existing SID mill be migrated so
|
||||
* the synthetic password in the authentication token will produce the same SID
|
||||
* (the corresponding synthetic password handle is persisted by SyntheticPasswordManager
|
||||
* in a per-user data storage.)
|
||||
*
|
||||
* If the existing credential hash is null, it means the given user should have no SID so
|
||||
* SyntheticPasswordManager will nuke any SP handle previously persisted. In this case,
|
||||
* the supplied credential parameter is also ignored.
|
||||
* Any existing SID for the user is cleared.
|
||||
*
|
||||
* Also saves the escrow information necessary to re-generate the synthetic password under
|
||||
* an escrow scheme. This information can be removed with {@link #destroyEscrowData} if
|
||||
* password escrow should be disabled completely on the given user.
|
||||
*
|
||||
*/
|
||||
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
|
||||
byte[] hash, LockscreenCredential credential, int userId) {
|
||||
AuthenticationToken newSyntheticPassword(int userId) {
|
||||
clearSidForUser(userId);
|
||||
AuthenticationToken result = AuthenticationToken.create();
|
||||
GateKeeperResponse response;
|
||||
if (hash != null) {
|
||||
try {
|
||||
response = gatekeeper.enroll(userId, hash, credential.getCredential(),
|
||||
result.deriveGkPassword());
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to enroll credential duing SP init", e);
|
||||
}
|
||||
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
|
||||
Slog.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
|
||||
clearSidForUser(userId);
|
||||
} else {
|
||||
saveSyntheticPasswordHandle(response.getPayload(), userId);
|
||||
}
|
||||
} else {
|
||||
clearSidForUser(userId);
|
||||
}
|
||||
saveEscrowData(result, userId);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -135,11 +135,6 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
return mUserManagerInternal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEnrolledBiometrics(int userId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int binderGetCallingUid() {
|
||||
return Process.SYSTEM_UID;
|
||||
|
||||
@@ -42,11 +42,8 @@ import android.service.gatekeeper.GateKeeperResponse;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
import com.android.internal.widget.VerifyCredentialResponse;
|
||||
import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
|
||||
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -96,17 +93,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
@Test
|
||||
public void testChangePasswordFailPrimaryUser() throws RemoteException {
|
||||
final long sid = 1234;
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), sid);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"));
|
||||
|
||||
assertFalse(mService.setLockCredential(newPassword("newpwd"), newPassword("badpwd"),
|
||||
PRIMARY_USER_ID));
|
||||
assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"), sid);
|
||||
assertVerifyCredentials(PRIMARY_USER_ID, newPassword("password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearPasswordPrimaryUser() throws RemoteException {
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"), 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("password"));
|
||||
assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
|
||||
PRIMARY_USER_ID));
|
||||
assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(PRIMARY_USER_ID));
|
||||
@@ -264,10 +260,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void testSetLockCredential_forProfileWithSeparateChallenge_updatesCredentials()
|
||||
throws Exception {
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, true, null);
|
||||
initializeStorageWithCredential(
|
||||
MANAGED_PROFILE_USER_ID,
|
||||
newPattern("12345"),
|
||||
1234);
|
||||
initializeStorageWithCredential(MANAGED_PROFILE_USER_ID, newPattern("12345"));
|
||||
|
||||
assertTrue(mService.setLockCredential(
|
||||
newPassword("newPassword"),
|
||||
@@ -300,8 +293,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
throws Exception {
|
||||
final LockscreenCredential oldCredential = newPassword("oldPassword");
|
||||
final LockscreenCredential newCredential = newPassword("newPassword");
|
||||
initializeStorageWithCredential(
|
||||
PRIMARY_USER_ID, oldCredential, 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, oldCredential);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
|
||||
assertTrue(mService.setLockCredential(
|
||||
@@ -321,7 +313,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void
|
||||
testSetLockCredential_forPrimaryUserWithUnifiedChallengeProfile_removesBothCredentials()
|
||||
throws Exception {
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"), 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPassword("oldPassword"));
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
|
||||
assertTrue(mService.setLockCredential(
|
||||
@@ -337,10 +329,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
@Test
|
||||
public void testSetLockCredential_nullCredential_removeBiometrics() throws RemoteException {
|
||||
initializeStorageWithCredential(
|
||||
PRIMARY_USER_ID,
|
||||
newPattern("123654"),
|
||||
1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, newPattern("123654"));
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
|
||||
mService.setLockCredential(nonePassword(), newPattern("123654"), PRIMARY_USER_ID);
|
||||
@@ -358,7 +347,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
throws Exception {
|
||||
final LockscreenCredential parentPassword = newPassword("parentPassword");
|
||||
final LockscreenCredential profilePassword = newPassword("profilePassword");
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
|
||||
assertTrue(mService.setLockCredential(
|
||||
@@ -377,7 +366,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
throws Exception {
|
||||
final LockscreenCredential parentPassword = newPassword("parentPassword");
|
||||
final LockscreenCredential profilePassword = newPattern("12345");
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword, 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, parentPassword);
|
||||
// Create and verify separate profile credentials.
|
||||
testCreateCredential(MANAGED_PROFILE_USER_ID, profilePassword);
|
||||
|
||||
@@ -393,7 +382,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
@Test
|
||||
public void testVerifyCredential_forPrimaryUser_sendsCredentials() throws Exception {
|
||||
final LockscreenCredential password = newPassword("password");
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, password, 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, password);
|
||||
reset(mRecoverableKeyStoreManager);
|
||||
|
||||
mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */);
|
||||
@@ -424,7 +413,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
public void verifyCredential_forPrimaryUserWithUnifiedChallengeProfile_sendsCredentialsForBoth()
|
||||
throws Exception {
|
||||
final LockscreenCredential pattern = newPattern("12345");
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, pattern, 1234);
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, pattern);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
reset(mRecoverableKeyStoreManager);
|
||||
|
||||
@@ -464,7 +453,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
private void testCreateCredential(int userId, LockscreenCredential credential)
|
||||
throws RemoteException {
|
||||
assertTrue(mService.setLockCredential(credential, nonePassword(), userId));
|
||||
assertVerifyCredentials(userId, credential, -1);
|
||||
assertVerifyCredentials(userId, credential);
|
||||
}
|
||||
|
||||
private void testCreateCredentialFailsWithoutLockScreen(
|
||||
@@ -483,19 +472,17 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
private void testChangeCredentials(int userId, LockscreenCredential newCredential,
|
||||
LockscreenCredential oldCredential) throws RemoteException {
|
||||
final long sid = 1234;
|
||||
initializeStorageWithCredential(userId, oldCredential, sid);
|
||||
initializeStorageWithCredential(userId, oldCredential);
|
||||
assertTrue(mService.setLockCredential(newCredential, oldCredential, userId));
|
||||
assertVerifyCredentials(userId, newCredential, sid);
|
||||
assertVerifyCredentials(userId, newCredential);
|
||||
}
|
||||
|
||||
private void assertVerifyCredentials(int userId, LockscreenCredential credential, long sid)
|
||||
private void assertVerifyCredentials(int userId, LockscreenCredential credential)
|
||||
throws RemoteException{
|
||||
VerifyCredentialResponse response = mService.verifyCredential(credential, userId,
|
||||
0 /* flags */);
|
||||
|
||||
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
|
||||
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
|
||||
if (credential.isPassword()) {
|
||||
assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
|
||||
} else if (credential.isPin()) {
|
||||
@@ -517,19 +504,11 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
badCredential, userId, 0 /* flags */).getResponseCode());
|
||||
}
|
||||
|
||||
private void initializeStorageWithCredential(int userId, LockscreenCredential credential,
|
||||
long sid) throws RemoteException {
|
||||
byte[] oldHash = new VerifyHandle(credential.getCredential(), sid).toBytes();
|
||||
if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
|
||||
mService.initializeSyntheticPasswordLocked(oldHash, credential, userId);
|
||||
} else {
|
||||
if (credential.isPassword() || credential.isPin()) {
|
||||
mStorage.writeCredentialHash(CredentialHash.create(oldHash,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
|
||||
} else {
|
||||
mStorage.writeCredentialHash(CredentialHash.create(oldHash,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("GuardedBy") // for initializeSyntheticPasswordLocked
|
||||
private void initializeStorageWithCredential(int userId, LockscreenCredential credential)
|
||||
throws RemoteException {
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(userId));
|
||||
mService.initializeSyntheticPasswordLocked(credential, userId);
|
||||
assertNotEquals(0, mGateKeeperService.getSecureUserId(userId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,18 +63,6 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
|
||||
}).when(mPersistentDataBlockManager).getFrpCredentialHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getLockPatternFilename(int userId) {
|
||||
return makeDirs(mStorageDir,
|
||||
super.getLockPatternFilename(userId)).getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getLockPasswordFilename(int userId) {
|
||||
return makeDirs(mStorageDir,
|
||||
super.getLockPasswordFilename(userId)).getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getChildProfileLockFile(int userId) {
|
||||
return makeDirs(mStorageDir,
|
||||
|
||||
@@ -48,9 +48,7 @@ import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.server.PersistentDataBlockManagerInternal;
|
||||
import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
|
||||
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -72,10 +70,7 @@ import java.util.concurrent.CountDownLatch;
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class LockSettingsStorageTests {
|
||||
private static final int SOME_USER_ID = 1034;
|
||||
private final byte[] PASSWORD_0 = "thepassword0".getBytes();
|
||||
private final byte[] PASSWORD_1 = "password1".getBytes();
|
||||
private final byte[] PATTERN_0 = "123654".getBytes();
|
||||
private final byte[] PATTERN_1 = "147852369".getBytes();
|
||||
private final byte[] PASSWORD = "thepassword".getBytes();
|
||||
|
||||
public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 33};
|
||||
|
||||
@@ -216,161 +211,64 @@ public class LockSettingsStorageTests {
|
||||
@Test
|
||||
public void testRemoveUser() {
|
||||
mStorage.writeKeyValue("key", "value", 0);
|
||||
writePasswordBytes(PASSWORD_0, 0);
|
||||
writePatternBytes(PATTERN_0, 0);
|
||||
|
||||
mStorage.writeKeyValue("key", "value", 1);
|
||||
writePasswordBytes(PASSWORD_1, 1);
|
||||
writePatternBytes(PATTERN_1, 1);
|
||||
|
||||
mStorage.removeUser(0);
|
||||
|
||||
assertEquals("value", mStorage.readKeyValue("key", "default", 1));
|
||||
assertEquals("default", mStorage.readKeyValue("key", "default", 0));
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_NONE, mStorage.readCredentialHash(0).type);
|
||||
assertPatternBytes(PATTERN_1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCredential_Default() {
|
||||
assertEquals(mStorage.readCredentialHash(0).type, LockPatternUtils.CREDENTIAL_TYPE_NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPassword_Write() {
|
||||
writePasswordBytes(PASSWORD_0, 0);
|
||||
|
||||
assertPasswordBytes(PASSWORD_0, 0);
|
||||
mStorage.clearCache();
|
||||
assertPasswordBytes(PASSWORD_0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPassword_WriteProfileWritesParent() {
|
||||
writePasswordBytes(PASSWORD_0, 1);
|
||||
writePasswordBytes(PASSWORD_1, 2);
|
||||
|
||||
assertPasswordBytes(PASSWORD_0, 1);
|
||||
assertPasswordBytes(PASSWORD_1, 2);
|
||||
mStorage.clearCache();
|
||||
assertPasswordBytes(PASSWORD_0, 1);
|
||||
assertPasswordBytes(PASSWORD_1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockType_WriteProfileWritesParent() {
|
||||
writePasswordBytes(PASSWORD_0, 10);
|
||||
writePatternBytes(PATTERN_0, 20);
|
||||
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN,
|
||||
mStorage.readCredentialHash(10).type);
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
mStorage.readCredentialHash(20).type);
|
||||
mStorage.clearCache();
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN,
|
||||
mStorage.readCredentialHash(10).type);
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
mStorage.readCredentialHash(20).type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPassword_WriteParentWritesProfile() {
|
||||
writePasswordBytes(PASSWORD_0, 2);
|
||||
writePasswordBytes(PASSWORD_1, 1);
|
||||
|
||||
assertPasswordBytes(PASSWORD_1, 1);
|
||||
assertPasswordBytes(PASSWORD_0, 2);
|
||||
mStorage.clearCache();
|
||||
assertPasswordBytes(PASSWORD_1, 1);
|
||||
assertPasswordBytes(PASSWORD_0, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProfileLock_ReadWriteChildProfileLock() {
|
||||
assertFalse(mStorage.hasChildProfileLock(20));
|
||||
mStorage.writeChildProfileLock(20, PASSWORD_0);
|
||||
assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
|
||||
mStorage.writeChildProfileLock(20, PASSWORD);
|
||||
assertArrayEquals(PASSWORD, mStorage.readChildProfileLock(20));
|
||||
assertTrue(mStorage.hasChildProfileLock(20));
|
||||
mStorage.clearCache();
|
||||
assertArrayEquals(PASSWORD_0, mStorage.readChildProfileLock(20));
|
||||
assertArrayEquals(PASSWORD, mStorage.readChildProfileLock(20));
|
||||
assertTrue(mStorage.hasChildProfileLock(20));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPattern_Write() {
|
||||
writePatternBytes(PATTERN_0, 0);
|
||||
|
||||
assertPatternBytes(PATTERN_0, 0);
|
||||
mStorage.clearCache();
|
||||
assertPatternBytes(PATTERN_0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPattern_WriteProfileWritesParent() {
|
||||
writePatternBytes(PATTERN_0, 1);
|
||||
writePatternBytes(PATTERN_1, 2);
|
||||
|
||||
assertPatternBytes(PATTERN_0, 1);
|
||||
assertPatternBytes(PATTERN_1, 2);
|
||||
mStorage.clearCache();
|
||||
assertPatternBytes(PATTERN_0, 1);
|
||||
assertPatternBytes(PATTERN_1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPattern_WriteParentWritesProfile() {
|
||||
writePatternBytes(PATTERN_1, 2);
|
||||
writePatternBytes(PATTERN_0, 1);
|
||||
|
||||
assertPatternBytes(PATTERN_0, 1);
|
||||
assertPatternBytes(PATTERN_1, 2);
|
||||
mStorage.clearCache();
|
||||
assertPatternBytes(PATTERN_0, 1);
|
||||
assertPatternBytes(PATTERN_1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefetch() {
|
||||
mStorage.writeKeyValue("key", "toBeFetched", 0);
|
||||
writePatternBytes(PATTERN_0, 0);
|
||||
|
||||
mStorage.clearCache();
|
||||
mStorage.prefetchUser(0);
|
||||
|
||||
assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
|
||||
assertPatternBytes(PATTERN_0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileLocation_Owner() {
|
||||
LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());
|
||||
|
||||
assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0));
|
||||
assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0));
|
||||
assertEquals("/data/system/gatekeeper.profile.key", storage.getChildProfileLockFile(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileLocation_SecondaryUser() {
|
||||
LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());
|
||||
|
||||
assertEquals("/data/system/users/1/gatekeeper.pattern.key", storage.getLockPatternFilename(1));
|
||||
assertEquals("/data/system/users/1/gatekeeper.password.key", storage.getLockPasswordFilename(1));
|
||||
assertEquals("/data/system/users/1/gatekeeper.profile.key",
|
||||
storage.getChildProfileLockFile(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileLocation_ProfileToSecondary() {
|
||||
LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());
|
||||
|
||||
assertEquals("/data/system/users/2/gatekeeper.pattern.key", storage.getLockPatternFilename(2));
|
||||
assertEquals("/data/system/users/2/gatekeeper.password.key", storage.getLockPasswordFilename(2));
|
||||
assertEquals("/data/system/users/2/gatekeeper.profile.key",
|
||||
storage.getChildProfileLockFile(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileLocation_ProfileToOwner() {
|
||||
LockSettingsStorage storage = new LockSettingsStorage(InstrumentationRegistry.getContext());
|
||||
|
||||
assertEquals("/data/system/users/3/gatekeeper.pattern.key", storage.getLockPatternFilename(3));
|
||||
assertEquals("/data/system/users/3/gatekeeper.password.key", storage.getLockPasswordFilename(3));
|
||||
assertEquals("/data/system/users/3/gatekeeper.profile.key",
|
||||
storage.getChildProfileLockFile(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -483,28 +381,6 @@ public class LockSettingsStorageTests {
|
||||
}
|
||||
}
|
||||
|
||||
private void writePasswordBytes(byte[] password, int userId) {
|
||||
mStorage.writeCredentialHash(CredentialHash.create(
|
||||
password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), userId);
|
||||
}
|
||||
|
||||
private void writePatternBytes(byte[] pattern, int userId) {
|
||||
mStorage.writeCredentialHash(CredentialHash.create(
|
||||
pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN), userId);
|
||||
}
|
||||
|
||||
private void assertPasswordBytes(byte[] password, int userId) {
|
||||
CredentialHash cred = mStorage.readCredentialHash(userId);
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN, cred.type);
|
||||
assertArrayEquals(password, cred.hash);
|
||||
}
|
||||
|
||||
private void assertPatternBytes(byte[] pattern, int userId) {
|
||||
CredentialHash cred = mStorage.readCredentialHash(userId);
|
||||
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN, cred.type);
|
||||
assertArrayEquals(pattern, cred.hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppresses reporting of the WTF to system_server, so we don't pollute the dropbox with
|
||||
* intentionally caused WTFs.
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.server.locksettings;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
|
||||
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
|
||||
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -38,7 +37,6 @@ import static org.mockito.Mockito.when;
|
||||
import android.app.admin.PasswordMetrics;
|
||||
import android.app.PropertyInvalidatedCache;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
@@ -82,8 +80,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
final LockscreenCredential badPassword = newPassword("bad-password");
|
||||
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
|
||||
mGateKeeperService, mUserManager, mPasswordSlotManager);
|
||||
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
|
||||
null, USER_ID);
|
||||
AuthenticationToken authToken = manager.newSyntheticPassword(USER_ID);
|
||||
long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
|
||||
password, authToken, USER_ID);
|
||||
|
||||
@@ -97,32 +94,23 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
assertNull(result.authToken);
|
||||
}
|
||||
|
||||
private void disableSyntheticPassword() throws RemoteException {
|
||||
mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
private void enableSyntheticPassword() throws RemoteException {
|
||||
mService.setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
private boolean hasSyntheticPassword(int userId) throws RemoteException {
|
||||
return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
|
||||
}
|
||||
|
||||
protected void initializeCredentialUnderSP(LockscreenCredential password, int userId)
|
||||
private void initializeCredential(LockscreenCredential password, int userId)
|
||||
throws RemoteException {
|
||||
enableSyntheticPassword();
|
||||
assertTrue(mService.setLockCredential(password, nonePassword(), userId));
|
||||
assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(userId));
|
||||
assertTrue(mService.isSyntheticPasswordBasedCredential(userId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordChangeCredential() throws RemoteException {
|
||||
public void testChangeCredential() throws RemoteException {
|
||||
final LockscreenCredential password = newPassword("password");
|
||||
final LockscreenCredential newPassword = newPassword("newpassword");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
mService.setLockCredential(newPassword, password, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
@@ -131,11 +119,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordVerifyCredential() throws RemoteException {
|
||||
public void testVerifyCredential() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential badPassword = newPassword("badpassword");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
|
||||
@@ -144,11 +132,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordClearCredential() throws RemoteException {
|
||||
public void testClearCredential() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential badPassword = newPassword("newpassword");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// clear password
|
||||
mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID);
|
||||
@@ -162,11 +150,11 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
|
||||
public void testChangeCredentialKeepsAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential badPassword = newPassword("new");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(badPassword, password, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
@@ -178,11 +166,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
|
||||
public void testVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential newPassword = newPassword("new");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
reset(mAuthSecretService);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
@@ -193,7 +180,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
|
||||
initializeCredentialUnderSP(password, SECONDARY_USER_ID);
|
||||
initializeCredential(password, SECONDARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, SECONDARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
|
||||
@@ -207,9 +194,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("passwordForASyntheticPassword");
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
public void testCredentialDoesNotPassAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
|
||||
reset(mAuthSecretService);
|
||||
mService.onUnlockUser(PRIMARY_USER_ID);
|
||||
@@ -219,8 +206,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
@Test
|
||||
public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
|
||||
LockscreenCredential password = newPassword("getASyntheticPassword");
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
LockscreenCredential password = newPassword("password");
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(nonePassword(), password, PRIMARY_USER_ID);
|
||||
|
||||
reset(mAuthSecretService);
|
||||
@@ -234,7 +221,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential pattern = newPattern("123654");
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
// Disregard any reportPasswordChanged() invocations as part of credential setup.
|
||||
flushHandlerTasks();
|
||||
reset(mDevicePolicyManager);
|
||||
@@ -269,7 +256,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential pattern = newPattern("123654");
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
@@ -295,7 +282,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
LockscreenCredential pattern = newPattern("123654");
|
||||
LockscreenCredential newPassword = newPassword("password");
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
@@ -318,7 +305,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()
|
||||
throws RemoteException {
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
enableSyntheticPassword();
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
@@ -331,7 +317,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
final byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
// By first setting a password and then clearing it, we enter the state where SP is
|
||||
// initialized but the user currently has no password
|
||||
initializeCredentialUnderSP(newPassword("password"), PRIMARY_USER_ID);
|
||||
initializeCredential(newPassword("password"), PRIMARY_USER_ID);
|
||||
assertTrue(mService.setLockCredential(nonePassword(), newPassword("password"),
|
||||
PRIMARY_USER_ID));
|
||||
assertTrue(mService.isSyntheticPasswordBasedCredential(PRIMARY_USER_ID));
|
||||
@@ -343,19 +329,15 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
|
||||
throws RemoteException {
|
||||
public void testEscrowTokenActivatedLaterWithUserPassword() throws RemoteException {
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
LockscreenCredential password = newPassword("password");
|
||||
// Set up pre-SP user password
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(password, nonePassword(), PRIMARY_USER_ID);
|
||||
enableSyntheticPassword();
|
||||
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
// Token not activated immediately since user password exists
|
||||
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
// Activate token (password gets migrated to SP at the same time)
|
||||
// Activate token
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
// Verify token is activated
|
||||
@@ -383,7 +365,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
LockscreenCredential password = newPassword("password");
|
||||
LockscreenCredential pattern = newPattern("123654");
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
|
||||
long handle0 = mLocalService.addEscrowToken(token0, PRIMARY_USER_ID, null);
|
||||
long handle1 = mLocalService.addEscrowToken(token1, PRIMARY_USER_ID, null);
|
||||
@@ -412,7 +394,6 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
|
||||
mService.mHasSecureLockScreen = false;
|
||||
enableSyntheticPassword();
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
@@ -515,7 +496,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
LockscreenCredential password = newPassword("testGsiDisablesAuthSecret-password");
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
|
||||
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
|
||||
@@ -525,7 +506,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
public void testUnlockUserWithToken() throws Exception {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
byte[] token = "some-high-entropy-secure-token".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
// Disregard any reportPasswordChanged() invocations as part of credential setup.
|
||||
flushHandlerTasks();
|
||||
reset(mDevicePolicyManager);
|
||||
@@ -546,7 +527,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
@Test
|
||||
public void testPasswordChange_NoOrphanedFilesLeft() throws Exception {
|
||||
LockscreenCredential password = newPassword("password");
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
initializeCredential(password, PRIMARY_USER_ID);
|
||||
assertTrue(mService.setLockCredential(password, password, PRIMARY_USER_ID));
|
||||
assertNoOrphanedFilesLeft(PRIMARY_USER_ID);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user