Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +1 −41 Original line number Diff line number Diff line Loading @@ -182,7 +182,7 @@ public class LockSettingsService extends ILockSettings.Stub { @IntDef({CHALLENGE_NONE, CHALLENGE_FROM_CALLER, CHALLENGE_INTERNAL}) @interface ChallengeType {}; @interface ChallengeType {} // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. Loading Loading @@ -1937,46 +1937,6 @@ public class LockSettingsService extends ILockSettings.Stub { // of unlocking the user, so yell if calling from the main thread. StrictMode.noteDiskRead(); if (storedHash.version == CredentialHash.VERSION_LEGACY) { final byte[] hash; if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { hash = LockPatternUtils.patternToHash( LockPatternUtils.byteArrayToPattern(credential)); } else { hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes(); } if (Arrays.equals(hash, storedHash.hash)) { if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId); } else { unlockKeystore(credential, userId); } // Users with legacy credentials don't have credential-backed // FBE keys, so just pass through a fake token/secret Slog.i(TAG, "Unlocking user with fake token: " + userId); final byte[] fakeToken = String.valueOf(userId).getBytes(); unlockUser(userId, fakeToken, fakeToken); // migrate credential to GateKeeper setLockCredentialInternal(credential, storedHash.type, null, storedHash.type == CREDENTIAL_TYPE_PATTERN ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC /* TODO(roosa): keep the same password quality */, userId, false, /* isLockTiedToParent= */ false); if (challengeType == CHALLENGE_NONE) { notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); // Use credentials to create recoverable keystore snapshot. sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, // as a user that had a legacy credential would have to unlock their device // before getting to a flow with a challenge, but supporting for consistency. } else { return VerifyCredentialResponse.ERROR; } } GateKeeperResponse gateKeeperResponse = getGateKeeperService() .verifyChallenge(userId, challenge, storedHash.hash, credential); VerifyCredentialResponse response = convertResponse(gateKeeperResponse); Loading services/core/java/com/android/server/locksettings/LockSettingsStorage.java +21 −56 Original line number Diff line number Diff line Loading @@ -78,9 +78,7 @@ class LockSettingsStorage { private static final String SYSTEM_DIRECTORY = "/system/"; private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key"; private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key"; private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key"; private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key"; private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key"; private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/"; Loading @@ -96,15 +94,15 @@ class LockSettingsStorage { @VisibleForTesting public static class CredentialHash { static final int VERSION_LEGACY = 0; static final int VERSION_GATEKEEPER = 1; /** Deprecated private static final int VERSION_LEGACY = 0; */ private static final int VERSION_GATEKEEPER = 1; private CredentialHash(byte[] hash, @CredentialType int type, int version) { this(hash, type, version, false /* isBaseZeroPattern */); private CredentialHash(byte[] hash, @CredentialType int type) { this(hash, type, false /* isBaseZeroPattern */); } private CredentialHash( byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) { byte[] hash, @CredentialType int type, boolean isBaseZeroPattern) { if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) { if (hash == null) { throw new RuntimeException("Empty hash for CredentialHash"); Loading @@ -116,30 +114,27 @@ class LockSettingsStorage { } this.hash = hash; this.type = type; this.version = version; this.isBaseZeroPattern = isBaseZeroPattern; } private static CredentialHash createBaseZeroPattern(byte[] hash) { return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, VERSION_GATEKEEPER, true /* isBaseZeroPattern */); true /* isBaseZeroPattern */); } static CredentialHash create(byte[] hash, int type) { if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) { throw new RuntimeException("Bad type for CredentialHash"); } return new CredentialHash(hash, type, VERSION_GATEKEEPER); return new CredentialHash(hash, type); } static CredentialHash createEmptyHash() { return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, VERSION_GATEKEEPER); return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE); } byte[] hash; @CredentialType int type; int version; boolean isBaseZeroPattern; public byte[] toBytes() { Loading @@ -148,7 +143,7 @@ class LockSettingsStorage { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.write(version); dos.write(VERSION_GATEKEEPER); dos.write(type); if (hash != null && hash.length > 0) { dos.writeInt(hash.length); Loading @@ -166,7 +161,7 @@ class LockSettingsStorage { public static CredentialHash fromBytes(byte[] bytes) { try { DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes)); int version = is.read(); /* int version = */ is.read(); int type = is.read(); int hashSize = is.readInt(); byte[] hash = null; Loading @@ -174,7 +169,7 @@ class LockSettingsStorage { hash = new byte[hashSize]; is.readFully(hash); } return new CredentialHash(hash, type, version); return new CredentialHash(hash, type); } catch (IOException e) { throw new RuntimeException(e); } Loading Loading @@ -269,14 +264,7 @@ class LockSettingsStorage { private CredentialHash readPasswordHashIfExists(int userId) { byte[] stored = readFile(getLockPasswordFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, CredentialHash.VERSION_GATEKEEPER); } stored = readFile(getLegacyLockPasswordFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, CredentialHash.VERSION_LEGACY); return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD); } return null; } Loading @@ -284,8 +272,7 @@ class LockSettingsStorage { private CredentialHash readPatternHashIfExists(int userId) { byte[] stored = readFile(getLockPatternFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, CredentialHash.VERSION_GATEKEEPER); return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN); } stored = readFile(getBaseZeroLockPatternFilename(userId)); Loading @@ -293,30 +280,20 @@ class LockSettingsStorage { return CredentialHash.createBaseZeroPattern(stored); } stored = readFile(getLegacyLockPatternFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, CredentialHash.VERSION_LEGACY); } return null; } public CredentialHash readCredentialHash(int userId) { CredentialHash passwordHash = readPasswordHashIfExists(userId); CredentialHash patternHash = readPatternHashIfExists(userId); if (passwordHash != null && patternHash != null) { if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) { if (passwordHash != null) { return passwordHash; } else { return patternHash; } } else if (passwordHash != null) { return passwordHash; } else if (patternHash != null) { CredentialHash patternHash = readPatternHashIfExists(userId); if (patternHash != null) { return patternHash; } else { return CredentialHash.createEmptyHash(); } return CredentialHash.createEmptyHash(); } public void removeChildProfileLock(int userId) { Loading @@ -342,14 +319,12 @@ class LockSettingsStorage { } public boolean hasPassword(int userId) { return hasFile(getLockPasswordFilename(userId)) || hasFile(getLegacyLockPasswordFilename(userId)); return hasFile(getLockPasswordFilename(userId)); } public boolean hasPattern(int userId) { return hasFile(getLockPatternFilename(userId)) || hasFile(getBaseZeroLockPatternFilename(userId)) || hasFile(getLegacyLockPatternFilename(userId)); hasFile(getBaseZeroLockPatternFilename(userId)); } public boolean hasCredential(int userId) { Loading Loading @@ -469,16 +444,6 @@ class LockSettingsStorage { return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE); } @VisibleForTesting String getLegacyLockPatternFilename(int userId) { return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE); } @VisibleForTesting String getLegacyLockPasswordFilename(int userId) { return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE); } private String getBaseZeroLockPatternFilename(int userId) { return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE); } Loading services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +0 −4 Original line number Diff line number Diff line Loading @@ -311,8 +311,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { public void testFileLocation_Owner() { LockSettingsStorage storage = new LockSettingsStorage(getContext()); assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0)); assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0)); assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0)); assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0)); } Loading Loading @@ -436,7 +434,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes(); CredentialHash deserialized = CredentialHash.fromBytes(serialized); assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); assertFalse(deserialized.isBaseZeroPattern); Loading @@ -453,7 +450,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { }; CredentialHash deserialized = CredentialHash.fromBytes(serialized); assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); assertFalse(deserialized.isBaseZeroPattern); Loading Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +1 −41 Original line number Diff line number Diff line Loading @@ -182,7 +182,7 @@ public class LockSettingsService extends ILockSettings.Stub { @IntDef({CHALLENGE_NONE, CHALLENGE_FROM_CALLER, CHALLENGE_INTERNAL}) @interface ChallengeType {}; @interface ChallengeType {} // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. Loading Loading @@ -1937,46 +1937,6 @@ public class LockSettingsService extends ILockSettings.Stub { // of unlocking the user, so yell if calling from the main thread. StrictMode.noteDiskRead(); if (storedHash.version == CredentialHash.VERSION_LEGACY) { final byte[] hash; if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { hash = LockPatternUtils.patternToHash( LockPatternUtils.byteArrayToPattern(credential)); } else { hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes(); } if (Arrays.equals(hash, storedHash.hash)) { if (storedHash.type == CREDENTIAL_TYPE_PATTERN) { unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId); } else { unlockKeystore(credential, userId); } // Users with legacy credentials don't have credential-backed // FBE keys, so just pass through a fake token/secret Slog.i(TAG, "Unlocking user with fake token: " + userId); final byte[] fakeToken = String.valueOf(userId).getBytes(); unlockUser(userId, fakeToken, fakeToken); // migrate credential to GateKeeper setLockCredentialInternal(credential, storedHash.type, null, storedHash.type == CREDENTIAL_TYPE_PATTERN ? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING : DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC /* TODO(roosa): keep the same password quality */, userId, false, /* isLockTiedToParent= */ false); if (challengeType == CHALLENGE_NONE) { notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId); // Use credentials to create recoverable keystore snapshot. sendCredentialsOnUnlockIfRequired(storedHash.type, credential, userId); return VerifyCredentialResponse.OK; } // Fall through to get the auth token. Technically this should never happen, // as a user that had a legacy credential would have to unlock their device // before getting to a flow with a challenge, but supporting for consistency. } else { return VerifyCredentialResponse.ERROR; } } GateKeeperResponse gateKeeperResponse = getGateKeeperService() .verifyChallenge(userId, challenge, storedHash.hash, credential); VerifyCredentialResponse response = convertResponse(gateKeeperResponse); Loading
services/core/java/com/android/server/locksettings/LockSettingsStorage.java +21 −56 Original line number Diff line number Diff line Loading @@ -78,9 +78,7 @@ class LockSettingsStorage { private static final String SYSTEM_DIRECTORY = "/system/"; private static final String LOCK_PATTERN_FILE = "gatekeeper.pattern.key"; private static final String BASE_ZERO_LOCK_PATTERN_FILE = "gatekeeper.gesture.key"; private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key"; private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key"; private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key"; private static final String CHILD_PROFILE_LOCK_FILE = "gatekeeper.profile.key"; private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/"; Loading @@ -96,15 +94,15 @@ class LockSettingsStorage { @VisibleForTesting public static class CredentialHash { static final int VERSION_LEGACY = 0; static final int VERSION_GATEKEEPER = 1; /** Deprecated private static final int VERSION_LEGACY = 0; */ private static final int VERSION_GATEKEEPER = 1; private CredentialHash(byte[] hash, @CredentialType int type, int version) { this(hash, type, version, false /* isBaseZeroPattern */); private CredentialHash(byte[] hash, @CredentialType int type) { this(hash, type, false /* isBaseZeroPattern */); } private CredentialHash( byte[] hash, @CredentialType int type, int version, boolean isBaseZeroPattern) { byte[] hash, @CredentialType int type, boolean isBaseZeroPattern) { if (type != LockPatternUtils.CREDENTIAL_TYPE_NONE) { if (hash == null) { throw new RuntimeException("Empty hash for CredentialHash"); Loading @@ -116,30 +114,27 @@ class LockSettingsStorage { } this.hash = hash; this.type = type; this.version = version; this.isBaseZeroPattern = isBaseZeroPattern; } private static CredentialHash createBaseZeroPattern(byte[] hash) { return new CredentialHash(hash, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, VERSION_GATEKEEPER, true /* isBaseZeroPattern */); true /* isBaseZeroPattern */); } static CredentialHash create(byte[] hash, int type) { if (type == LockPatternUtils.CREDENTIAL_TYPE_NONE) { throw new RuntimeException("Bad type for CredentialHash"); } return new CredentialHash(hash, type, VERSION_GATEKEEPER); return new CredentialHash(hash, type); } static CredentialHash createEmptyHash() { return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, VERSION_GATEKEEPER); return new CredentialHash(null, LockPatternUtils.CREDENTIAL_TYPE_NONE); } byte[] hash; @CredentialType int type; int version; boolean isBaseZeroPattern; public byte[] toBytes() { Loading @@ -148,7 +143,7 @@ class LockSettingsStorage { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(os); dos.write(version); dos.write(VERSION_GATEKEEPER); dos.write(type); if (hash != null && hash.length > 0) { dos.writeInt(hash.length); Loading @@ -166,7 +161,7 @@ class LockSettingsStorage { public static CredentialHash fromBytes(byte[] bytes) { try { DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes)); int version = is.read(); /* int version = */ is.read(); int type = is.read(); int hashSize = is.readInt(); byte[] hash = null; Loading @@ -174,7 +169,7 @@ class LockSettingsStorage { hash = new byte[hashSize]; is.readFully(hash); } return new CredentialHash(hash, type, version); return new CredentialHash(hash, type); } catch (IOException e) { throw new RuntimeException(e); } Loading Loading @@ -269,14 +264,7 @@ class LockSettingsStorage { private CredentialHash readPasswordHashIfExists(int userId) { byte[] stored = readFile(getLockPasswordFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, CredentialHash.VERSION_GATEKEEPER); } stored = readFile(getLegacyLockPasswordFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, CredentialHash.VERSION_LEGACY); return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD); } return null; } Loading @@ -284,8 +272,7 @@ class LockSettingsStorage { private CredentialHash readPatternHashIfExists(int userId) { byte[] stored = readFile(getLockPatternFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, CredentialHash.VERSION_GATEKEEPER); return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN); } stored = readFile(getBaseZeroLockPatternFilename(userId)); Loading @@ -293,30 +280,20 @@ class LockSettingsStorage { return CredentialHash.createBaseZeroPattern(stored); } stored = readFile(getLegacyLockPatternFilename(userId)); if (!ArrayUtils.isEmpty(stored)) { return new CredentialHash(stored, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, CredentialHash.VERSION_LEGACY); } return null; } public CredentialHash readCredentialHash(int userId) { CredentialHash passwordHash = readPasswordHashIfExists(userId); CredentialHash patternHash = readPatternHashIfExists(userId); if (passwordHash != null && patternHash != null) { if (passwordHash.version == CredentialHash.VERSION_GATEKEEPER) { if (passwordHash != null) { return passwordHash; } else { return patternHash; } } else if (passwordHash != null) { return passwordHash; } else if (patternHash != null) { CredentialHash patternHash = readPatternHashIfExists(userId); if (patternHash != null) { return patternHash; } else { return CredentialHash.createEmptyHash(); } return CredentialHash.createEmptyHash(); } public void removeChildProfileLock(int userId) { Loading @@ -342,14 +319,12 @@ class LockSettingsStorage { } public boolean hasPassword(int userId) { return hasFile(getLockPasswordFilename(userId)) || hasFile(getLegacyLockPasswordFilename(userId)); return hasFile(getLockPasswordFilename(userId)); } public boolean hasPattern(int userId) { return hasFile(getLockPatternFilename(userId)) || hasFile(getBaseZeroLockPatternFilename(userId)) || hasFile(getLegacyLockPatternFilename(userId)); hasFile(getBaseZeroLockPatternFilename(userId)); } public boolean hasCredential(int userId) { Loading Loading @@ -469,16 +444,6 @@ class LockSettingsStorage { return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE); } @VisibleForTesting String getLegacyLockPatternFilename(int userId) { return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE); } @VisibleForTesting String getLegacyLockPasswordFilename(int userId) { return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE); } private String getBaseZeroLockPatternFilename(int userId) { return getLockCredentialFilePathForUser(userId, BASE_ZERO_LOCK_PATTERN_FILE); } Loading
services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java +0 −4 Original line number Diff line number Diff line Loading @@ -311,8 +311,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { public void testFileLocation_Owner() { LockSettingsStorage storage = new LockSettingsStorage(getContext()); assertEquals("/data/system/gesture.key", storage.getLegacyLockPatternFilename(0)); assertEquals("/data/system/password.key", storage.getLegacyLockPasswordFilename(0)); assertEquals("/data/system/gatekeeper.pattern.key", storage.getLockPatternFilename(0)); assertEquals("/data/system/gatekeeper.password.key", storage.getLockPasswordFilename(0)); } Loading Loading @@ -436,7 +434,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { PAYLOAD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD).toBytes(); CredentialHash deserialized = CredentialHash.fromBytes(serialized); assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); assertFalse(deserialized.isBaseZeroPattern); Loading @@ -453,7 +450,6 @@ public class LockSettingsStorageTests extends AndroidTestCase { }; CredentialHash deserialized = CredentialHash.fromBytes(serialized); assertEquals(CredentialHash.VERSION_GATEKEEPER, deserialized.version); assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, deserialized.type); assertArrayEquals(PAYLOAD, deserialized.hash); assertFalse(deserialized.isBaseZeroPattern); Loading