Merge changes from topic "remove-auth-token"
* changes: Remove HardwareAuthToken parameter from unlockUserKey Remove HardwareAuthToken parameter from clearUserKeyAuth Remove HardwareAuthToken parameter from addUserKeyAuth Don't pass HardwareAuthToken to unlockUser() in non-SP verifyCredential Remove non-SP based setLockCredentialInternal() Remove HardwareAuthToken support from FakeStorageManager
This commit is contained in:
@@ -120,13 +120,13 @@ interface IStorageManager {
|
||||
void setDebugFlags(int flags, int mask) = 60;
|
||||
void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61;
|
||||
void destroyUserKey(int userId) = 62;
|
||||
void unlockUserKey(int userId, int serialNumber, in byte[] token, in byte[] secret) = 63;
|
||||
void unlockUserKey(int userId, int serialNumber, in byte[] secret) = 63;
|
||||
void lockUserKey(int userId) = 64;
|
||||
boolean isUserKeyUnlocked(int userId) = 65;
|
||||
void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
|
||||
void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
|
||||
boolean isConvertibleToFBE() = 68;
|
||||
void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
|
||||
void addUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 70;
|
||||
void fixateNewestUserKeyAuth(int userId) = 71;
|
||||
void fstrim(int flags, IVoldTaskListener listener) = 72;
|
||||
AppFuseMount mountProxyFileDescriptorBridge() = 73;
|
||||
@@ -142,7 +142,7 @@ interface IStorageManager {
|
||||
void startCheckpoint(int numTries) = 85;
|
||||
boolean needsCheckpoint() = 86;
|
||||
void abortChanges(in String message, boolean retry) = 87;
|
||||
void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
|
||||
void clearUserKeyAuth(int userId, int serialNumber, in byte[] secret) = 88;
|
||||
void fixupAppDir(in String path) = 89;
|
||||
void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90;
|
||||
void notifyAppIoBlocked(in String volumeUuid, int uid, int tid, int reason) = 91;
|
||||
|
||||
@@ -1528,9 +1528,9 @@ public class StorageManager {
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
public void unlockUserKey(int userId, int serialNumber, byte[] secret) {
|
||||
try {
|
||||
mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
|
||||
mStorageManager.unlockUserKey(userId, serialNumber, secret);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
@@ -1120,8 +1120,7 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
if (initLocked) {
|
||||
mVold.lockUserKey(user.id);
|
||||
} else {
|
||||
mVold.unlockUserKey(user.id, user.serialNumber, encodeBytes(null),
|
||||
encodeBytes(null));
|
||||
mVold.unlockUserKey(user.id, user.serialNumber, encodeBytes(null));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, e);
|
||||
@@ -3184,43 +3183,45 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
}
|
||||
|
||||
/*
|
||||
* Add this token/secret pair to the set of ways we can recover a disk encryption key.
|
||||
* Changing the token/secret for a disk encryption key is done in two phases: first, adding
|
||||
* a new token/secret pair with this call, then delting all other pairs with
|
||||
* fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
|
||||
* Gatekeeper, to be updated between the two calls.
|
||||
* Add this secret to the set of ways we can recover a user's disk
|
||||
* encryption key. Changing the secret for a disk encryption key is done in
|
||||
* two phases. First, this method is called to add the new secret binding.
|
||||
* Second, fixateNewestUserKeyAuth is called to delete all other bindings.
|
||||
* This allows other places where a credential is used, such as Gatekeeper,
|
||||
* to be updated between the two calls.
|
||||
*/
|
||||
@Override
|
||||
public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
public void addUserKeyAuth(int userId, int serialNumber, byte[] secret) {
|
||||
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
|
||||
|
||||
try {
|
||||
mVold.addUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
|
||||
mVold.addUserKeyAuth(userId, serialNumber, encodeBytes(secret));
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear disk encryption key bound to the associated token / secret pair. Removing the user
|
||||
* binding of the Disk encryption key is done in two phases: first, this call will retrieve
|
||||
* the disk encryption key using the provided token / secret pair and store it by
|
||||
* encrypting it with a keymaster key not bound to the user, then fixateNewestUserKeyAuth
|
||||
* is called to delete all other bindings of the disk encryption key.
|
||||
* Store a user's disk encryption key without secret binding. Removing the
|
||||
* secret for a disk encryption key is done in two phases. First, this
|
||||
* method is called to retrieve the key using the provided secret and store
|
||||
* it encrypted with a keystore key not bound to the user. Second,
|
||||
* fixateNewestUserKeyAuth is called to delete the key's other bindings.
|
||||
*/
|
||||
@Override
|
||||
public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
public void clearUserKeyAuth(int userId, int serialNumber, byte[] secret) {
|
||||
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
|
||||
|
||||
try {
|
||||
mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
|
||||
mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(secret));
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete all disk encryption token/secret pairs except the most recently added one
|
||||
* Delete all bindings of a user's disk encryption key except the most
|
||||
* recently added one.
|
||||
*/
|
||||
@Override
|
||||
public void fixateNewestUserKeyAuth(int userId) {
|
||||
@@ -3234,11 +3235,10 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
public void unlockUserKey(int userId, int serialNumber, byte[] secret) {
|
||||
boolean isFsEncrypted = StorageManager.isFileEncryptedNativeOrEmulated();
|
||||
Slog.d(TAG, "unlockUserKey: " + userId
|
||||
+ " isFileEncryptedNativeOrEmulated: " + isFsEncrypted
|
||||
+ " hasToken: " + (token != null)
|
||||
+ " hasSecret: " + (secret != null));
|
||||
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
|
||||
|
||||
@@ -3258,8 +3258,7 @@ class StorageManagerService extends IStorageManager.Stub
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
|
||||
encodeBytes(secret));
|
||||
mVold.unlockUserKey(userId, serialNumber, encodeBytes(secret));
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, e);
|
||||
return;
|
||||
|
||||
@@ -15108,9 +15108,23 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
return mUserController.startUser(userId, /* foreground */ true, unlockListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the given user.
|
||||
*
|
||||
* @param userId The ID of the user to unlock.
|
||||
* @param token No longer used. (This parameter cannot be removed because
|
||||
* this method is marked with UnsupportedAppUsage, so its
|
||||
* signature might not be safe to change.)
|
||||
* @param secret The secret needed to unlock the user's credential-encrypted
|
||||
* storage, or null if no secret is needed.
|
||||
* @param listener An optional progress listener.
|
||||
*
|
||||
* @return true if the user was successfully unlocked, otherwise false.
|
||||
*/
|
||||
@Override
|
||||
public boolean unlockUser(int userId, byte[] token, byte[] secret, IProgressListener listener) {
|
||||
return mUserController.unlockUser(userId, token, secret, listener);
|
||||
public boolean unlockUser(int userId, @Nullable byte[] token, @Nullable byte[] secret,
|
||||
@Nullable IProgressListener listener) {
|
||||
return mUserController.unlockUser(userId, secret, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -714,15 +714,9 @@ class UserController implements Handler.Callback {
|
||||
if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)
|
||||
|| SystemProperties.getBoolean("persist.pm.mock-upgrade", false)) {
|
||||
// Suppress double notifications for managed profiles that
|
||||
// were unlocked automatically as part of their parent user
|
||||
// being unlocked.
|
||||
final boolean quiet;
|
||||
if (info.isManagedProfile()) {
|
||||
quiet = !uss.tokenProvided
|
||||
|| !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
|
||||
} else {
|
||||
quiet = false;
|
||||
}
|
||||
// were unlocked automatically as part of their parent user being
|
||||
// unlocked. TODO(b/217442918): this code doesn't work correctly.
|
||||
final boolean quiet = info.isManagedProfile();
|
||||
mInjector.sendPreBootBroadcast(userId, quiet,
|
||||
() -> finishUserUnlockedCompleted(uss));
|
||||
} else {
|
||||
@@ -1658,27 +1652,25 @@ class UserController implements Handler.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
boolean unlockUser(final @UserIdInt int userId, byte[] token, byte[] secret,
|
||||
IProgressListener listener) {
|
||||
boolean unlockUser(final @UserIdInt int userId, byte[] secret, IProgressListener listener) {
|
||||
checkCallingPermission(INTERACT_ACROSS_USERS_FULL, "unlockUser");
|
||||
EventLog.writeEvent(EventLogTags.UC_UNLOCK_USER, userId);
|
||||
final long binderToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return unlockUserCleared(userId, token, secret, listener);
|
||||
return unlockUserCleared(userId, secret, listener);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(binderToken);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to unlock user without a credential token. This typically
|
||||
* succeeds when the device doesn't have credential-encrypted storage, or
|
||||
* when the credential-encrypted storage isn't tied to a user-provided
|
||||
* PIN or pattern.
|
||||
* Attempt to unlock user without a secret. This typically succeeds when the
|
||||
* device doesn't have credential-encrypted storage, or when the
|
||||
* credential-encrypted storage isn't tied to a user-provided PIN or
|
||||
* pattern.
|
||||
*/
|
||||
private boolean maybeUnlockUser(final @UserIdInt int userId) {
|
||||
// Try unlocking storage using empty token
|
||||
return unlockUserCleared(userId, null, null, null);
|
||||
return unlockUserCleared(userId, null, null);
|
||||
}
|
||||
|
||||
private static void notifyFinished(@UserIdInt int userId, IProgressListener listener) {
|
||||
@@ -1689,7 +1681,7 @@ class UserController implements Handler.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean unlockUserCleared(final @UserIdInt int userId, byte[] token, byte[] secret,
|
||||
private boolean unlockUserCleared(final @UserIdInt int userId, byte[] secret,
|
||||
IProgressListener listener) {
|
||||
UserState uss;
|
||||
if (!StorageManager.isUserKeyUnlocked(userId)) {
|
||||
@@ -1697,7 +1689,7 @@ class UserController implements Handler.Callback {
|
||||
final IStorageManager storageManager = mInjector.getStorageManager();
|
||||
try {
|
||||
// We always want to unlock user storage, even user is not started yet
|
||||
storageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
|
||||
storageManager.unlockUserKey(userId, userInfo.serialNumber, secret);
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Slogf.w(TAG, "Failed to unlock: " + e.getMessage());
|
||||
}
|
||||
@@ -1707,7 +1699,6 @@ class UserController implements Handler.Callback {
|
||||
uss = mStartedUsers.get(userId);
|
||||
if (uss != null) {
|
||||
uss.mUnlockProgress.addListener(listener);
|
||||
uss.tokenProvided = (token != null);
|
||||
}
|
||||
}
|
||||
// Bail if user isn't actually running
|
||||
|
||||
@@ -56,7 +56,6 @@ public final class UserState {
|
||||
public int state = STATE_BOOTING;
|
||||
public int lastState = STATE_BOOTING;
|
||||
public boolean switching;
|
||||
public boolean tokenProvided;
|
||||
|
||||
/** Callback for key eviction. */
|
||||
public interface KeyEvictedCallback {
|
||||
@@ -149,7 +148,6 @@ public final class UserState {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[UserState: id=" + mHandle.getIdentifier() + ", state=" + stateToString(state)
|
||||
+ ", lastState=" + stateToString(lastState) + ", switching=" + switching
|
||||
+ ", tokenProvided=" + tokenProvided + "]";
|
||||
+ ", lastState=" + stateToString(lastState) + ", switching=" + switching + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,7 +1366,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
* can end up calling into other system services to process user unlock request (via
|
||||
* {@link com.android.server.SystemServiceManager#unlockUser} </em>
|
||||
*/
|
||||
private void unlockUser(int userId, byte[] token, byte[] secret) {
|
||||
private void unlockUser(int userId, byte[] secret) {
|
||||
Slog.i(TAG, "Unlocking user " + userId + " with secret only, length "
|
||||
+ (secret != null ? secret.length : 0));
|
||||
// TODO: make this method fully async so we can update UI with progress strings
|
||||
@@ -1391,7 +1391,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
};
|
||||
|
||||
try {
|
||||
mActivityManager.unlockUser(userId, token, secret, listener);
|
||||
mActivityManager.unlockUser(userId, null, secret, listener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
@@ -1718,42 +1718,10 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
synchronized (mSpManager) {
|
||||
if (shouldMigrateToSyntheticPasswordLocked(userId)) {
|
||||
initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
|
||||
return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
|
||||
isLockTiedToParent);
|
||||
}
|
||||
initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential, userId);
|
||||
return spBasedSetLockCredentialInternalLocked(credential, savedCredential, userId,
|
||||
isLockTiedToParent);
|
||||
}
|
||||
if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
|
||||
byte[] enrolledHandle = enrollCredential(currentHandle.hash,
|
||||
savedCredential.getCredential(), credential.getCredential(), userId);
|
||||
if (enrolledHandle == null) {
|
||||
Slog.w(TAG, String.format("Failed to enroll %s: incorrect credential",
|
||||
credential.isPattern() ? "pattern" : "password"));
|
||||
return false;
|
||||
}
|
||||
CredentialHash willStore = CredentialHash.create(enrolledHandle, credential.getType());
|
||||
mStorage.writeCredentialHash(willStore, 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(
|
||||
LockPatternUtils.credentialTypeToPasswordQuality(credential.getType()), userId);
|
||||
// push new secret and auth token to vold
|
||||
GateKeeperResponse gkResponse;
|
||||
try {
|
||||
gkResponse = getGateKeeperService().verifyChallenge(userId, 0, willStore.hash,
|
||||
credential.getCredential());
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to verify current credential", e);
|
||||
}
|
||||
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
// Refresh the auth token
|
||||
doVerifyCredential(credential, userId, null /* progressCallback */, 0 /* flags */);
|
||||
synchronizeUnifiedWorkChallengeForProfiles(userId, null);
|
||||
sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
|
||||
@@ -1919,52 +1887,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
|
||||
}
|
||||
|
||||
private byte[] enrollCredential(byte[] enrolledHandle,
|
||||
byte[] enrolledCredential, byte[] toEnroll, int userId) {
|
||||
checkWritePermission(userId);
|
||||
GateKeeperResponse response;
|
||||
try {
|
||||
response = getGateKeeperService().enroll(userId, enrolledHandle,
|
||||
enrolledCredential, toEnroll);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to enroll credential", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] hash = response.getPayload();
|
||||
if (hash != null) {
|
||||
setKeystorePassword(toEnroll, userId);
|
||||
} else {
|
||||
// Should not happen
|
||||
Slog.e(TAG, "Throttled while enrolling a password");
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
private void setAuthlessUserKeyProtection(int userId, byte[] key) {
|
||||
if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
|
||||
addUserKeyAuth(userId, null, key);
|
||||
}
|
||||
|
||||
private void setUserKeyProtection(int userId, LockscreenCredential credential,
|
||||
VerifyCredentialResponse vcr) {
|
||||
private void setUserKeyProtection(int userId, byte[] key) {
|
||||
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
|
||||
if (vcr == null) {
|
||||
throw new IllegalArgumentException("Null response verifying a credential we just set");
|
||||
}
|
||||
if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
|
||||
throw new IllegalArgumentException("Non-OK response verifying a credential we just set "
|
||||
+ vcr.getResponseCode());
|
||||
}
|
||||
byte[] token = vcr.getGatekeeperHAT();
|
||||
if (token == null) {
|
||||
throw new IllegalArgumentException("Empty payload verifying a credential we just set");
|
||||
}
|
||||
addUserKeyAuth(userId, token, secretFromCredential(credential));
|
||||
addUserKeyAuth(userId, key);
|
||||
}
|
||||
|
||||
private void clearUserKeyProtection(int userId, byte[] secret) {
|
||||
@@ -1972,7 +1897,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
final UserInfo userInfo = mUserManager.getUserInfo(userId);
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, null, secret);
|
||||
mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, secret);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("clearUserKeyAuth failed user=" + userId);
|
||||
} finally {
|
||||
@@ -2005,21 +1930,21 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
/** Unlock disk encryption */
|
||||
private void unlockUserKey(int userId, byte[] token, byte[] secret) {
|
||||
private void unlockUserKey(int userId, byte[] secret) {
|
||||
final UserInfo userInfo = mUserManager.getUserInfo(userId);
|
||||
try {
|
||||
mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
|
||||
mStorageManager.unlockUserKey(userId, userInfo.serialNumber, secret);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to unlock user key " + userId, e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void addUserKeyAuth(int userId, byte[] token, byte[] secret) {
|
||||
private void addUserKeyAuth(int userId, byte[] secret) {
|
||||
final UserInfo userInfo = mUserManager.getUserInfo(userId);
|
||||
final long callingId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
|
||||
mStorageManager.addUserKeyAuth(userId, userInfo.serialNumber, secret);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to add new key to vold " + userId, e);
|
||||
} finally {
|
||||
@@ -2287,9 +2212,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
setUserPasswordMetrics(credential, userId);
|
||||
unlockKeystore(credential.getCredential(), userId);
|
||||
|
||||
Slog.i(TAG, "Unlocking user " + userId + " with token length "
|
||||
+ response.getGatekeeperHAT().length);
|
||||
unlockUser(userId, response.getGatekeeperHAT(), secretFromCredential(credential));
|
||||
Slog.i(TAG, "Unlocking user " + userId);
|
||||
unlockUser(userId, secretFromCredential(credential));
|
||||
|
||||
if (isManagedProfileWithSeparatedLock(userId)) {
|
||||
setDeviceUnlockedForUser(userId);
|
||||
@@ -2726,7 +2650,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
|
||||
}
|
||||
mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
|
||||
setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
setUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
setKeystorePassword(auth.deriveKeyStorePassword(), userId);
|
||||
} else {
|
||||
clearUserKeyProtection(userId, null);
|
||||
@@ -2878,7 +2802,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
{
|
||||
final byte[] secret = authToken.deriveDiskEncryptionKey();
|
||||
unlockUser(userId, null, secret);
|
||||
unlockUser(userId, secret);
|
||||
Arrays.fill(secret, (byte) 0);
|
||||
}
|
||||
activateEscrowTokens(authToken, userId);
|
||||
@@ -2928,7 +2852,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// a new SID, and re-add keys to vold and keystore.
|
||||
mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
|
||||
mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
|
||||
setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
setUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
setKeystorePassword(auth.deriveKeyStorePassword(), userId);
|
||||
}
|
||||
@@ -2943,7 +2867,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// Clear key from vold so ActivityManager can just unlock the user with empty secret
|
||||
// during boot. Vold storage needs to be unlocked before manipulation of the keys can
|
||||
// succeed.
|
||||
unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
|
||||
unlockUserKey(userId, auth.deriveDiskEncryptionKey());
|
||||
clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
|
||||
fixateNewestUserKeyAuth(userId);
|
||||
unlockKeystore(auth.deriveKeyStorePassword(), userId);
|
||||
@@ -3213,7 +3137,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// If clearing credential, unlock the user manually in order to progress user start
|
||||
// Call unlockUser() on a handler thread so no lock is held (either by LSS or by
|
||||
// the caller like DPMS), otherwise it can lead to deadlock.
|
||||
mHandler.post(() -> unlockUser(userId, null, null));
|
||||
mHandler.post(() -> unlockUser(userId, null));
|
||||
}
|
||||
notifyPasswordChanged(userId);
|
||||
notifySeparateProfileChallengeChanged(userId);
|
||||
|
||||
@@ -589,8 +589,7 @@ public class UserControllerTest {
|
||||
setUpUser(userId, 0);
|
||||
mUserController.startUser(userId, /* foreground= */ false);
|
||||
verify(mInjector.mStorageManagerMock, times(1))
|
||||
.unlockUserKey(userId, /* serialNumber= */ 0, /* token= */ null, /* secret= */
|
||||
null);
|
||||
.unlockUserKey(userId, /* serialNumber= */ 0, /* secret= */ null);
|
||||
mUserStates.put(userId, mUserController.getStartedUserState(userId));
|
||||
}
|
||||
|
||||
@@ -599,8 +598,7 @@ public class UserControllerTest {
|
||||
assertThat(mUserController.startProfile(userId)).isTrue();
|
||||
|
||||
verify(mInjector.mStorageManagerMock, times(1))
|
||||
.unlockUserKey(userId, /* serialNumber= */ 0, /* token= */ null, /* secret= */
|
||||
null);
|
||||
.unlockUserKey(userId, /* serialNumber= */ 0, /* secret= */ null);
|
||||
mUserStates.put(userId, mUserController.getStartedUserState(userId));
|
||||
}
|
||||
|
||||
|
||||
@@ -221,11 +221,10 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
Object[] args = invocation.getArguments();
|
||||
mStorageManager.addUserKeyAuth((int) args[0] /* userId */,
|
||||
(int) args[1] /* serialNumber */,
|
||||
(byte[]) args[2] /* token */,
|
||||
(byte[]) args[3] /* secret */);
|
||||
(byte[]) args[2] /* secret */);
|
||||
return null;
|
||||
}
|
||||
}).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any());
|
||||
}).when(sm).addUserKeyAuth(anyInt(), anyInt(), any());
|
||||
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
@@ -233,11 +232,10 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
Object[] args = invocation.getArguments();
|
||||
mStorageManager.clearUserKeyAuth((int) args[0] /* userId */,
|
||||
(int) args[1] /* serialNumber */,
|
||||
(byte[]) args[2] /* token */,
|
||||
(byte[]) args[3] /* secret */);
|
||||
(byte[]) args[2] /* secret */);
|
||||
return null;
|
||||
}
|
||||
}).when(sm).clearUserKeyAuth(anyInt(), anyInt(), any(), any());
|
||||
}).when(sm).clearUserKeyAuth(anyInt(), anyInt(), any());
|
||||
|
||||
doAnswer(
|
||||
new Answer<Void>() {
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.server.locksettings;
|
||||
import android.os.IProgressListener;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
@@ -29,56 +28,56 @@ import java.util.Arrays;
|
||||
|
||||
public class FakeStorageManager {
|
||||
|
||||
private ArrayMap<Integer, ArrayList<Pair<byte[], byte[]>>> mAuth = new ArrayMap<>();
|
||||
private ArrayMap<Integer, ArrayList<byte[]>> mAuth = new ArrayMap<>();
|
||||
private boolean mIgnoreBadUnlock;
|
||||
|
||||
public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
getUserAuth(userId).add(new Pair<>(token, secret));
|
||||
public void addUserKeyAuth(int userId, int serialNumber, byte[] secret) {
|
||||
getUserAuth(userId).add(secret);
|
||||
}
|
||||
|
||||
public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
|
||||
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
|
||||
if (token == null && secret == null) {
|
||||
public void clearUserKeyAuth(int userId, int serialNumber, byte[] secret) {
|
||||
ArrayList<byte[]> auths = getUserAuth(userId);
|
||||
if (secret == null) {
|
||||
return;
|
||||
}
|
||||
auths.remove(new Pair<>(token, secret));
|
||||
auths.add(new Pair<>(null, null));
|
||||
auths.remove(secret);
|
||||
auths.add(null);
|
||||
}
|
||||
|
||||
public void fixateNewestUserKeyAuth(int userId) {
|
||||
ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
|
||||
Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
|
||||
ArrayList<byte[]> auths = mAuth.get(userId);
|
||||
byte[] latest = auths.get(auths.size() - 1);
|
||||
auths.clear();
|
||||
auths.add(latest);
|
||||
}
|
||||
|
||||
private ArrayList<Pair<byte[], byte[]>> getUserAuth(int userId) {
|
||||
private ArrayList<byte[]> getUserAuth(int userId) {
|
||||
if (!mAuth.containsKey(userId)) {
|
||||
ArrayList<Pair<byte[], byte[]>> auths = new ArrayList<Pair<byte[], byte[]>>();
|
||||
auths.add(new Pair(null, null));
|
||||
mAuth.put(userId, auths);
|
||||
ArrayList<byte[]> auths = new ArrayList<>();
|
||||
auths.add(null);
|
||||
mAuth.put(userId, auths);
|
||||
}
|
||||
return mAuth.get(userId);
|
||||
}
|
||||
|
||||
public byte[] getUserUnlockToken(int userId) {
|
||||
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
|
||||
ArrayList<byte[]> auths = getUserAuth(userId);
|
||||
if (auths.size() != 1) {
|
||||
throw new AssertionFailedError("More than one secret exists");
|
||||
}
|
||||
return auths.get(0).second;
|
||||
return auths.get(0);
|
||||
}
|
||||
|
||||
public void unlockUser(int userId, byte[] secret, IProgressListener listener)
|
||||
throws RemoteException {
|
||||
listener.onStarted(userId, null);
|
||||
listener.onFinished(userId, null);
|
||||
ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
|
||||
ArrayList<byte[]> auths = getUserAuth(userId);
|
||||
if (auths.size() > 1) {
|
||||
throw new AssertionFailedError("More than one secret exists");
|
||||
}
|
||||
Pair<byte[], byte[]> auth = auths.get(0);
|
||||
if (!Arrays.equals(secret, auth.second)) {
|
||||
byte[] auth = auths.get(0);
|
||||
if (!Arrays.equals(secret, auth)) {
|
||||
if (!mIgnoreBadUnlock) {
|
||||
throw new AssertionFailedError("Invalid secret to unlock user " + userId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user