summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorAndres Morales <anmorales@google.com>2015-03-31 09:19:50 -0700
committerAndres Morales <anmorales@google.com>2015-04-13 18:38:45 -0700
commit8fa5665f0e757cec0063fb4cf1354f1596f93a91 (patch)
tree01fe5264f4151e15432fc8047fdde712c8434974 /services
parent832017963d1d74ba41348deed5eb747b45b441fb (diff)
downloadframeworks_base-8fa5665f0e757cec0063fb4cf1354f1596f93a91.zip
frameworks_base-8fa5665f0e757cec0063fb4cf1354f1596f93a91.tar.gz
frameworks_base-8fa5665f0e757cec0063fb4cf1354f1596f93a91.tar.bz2
Wire up GateKeeper to LockSettingsService
Adds: - Communication to GKService - password upgrade flow - enroll takes previous credential Change-Id: I0161b64642be3d0e34ff4a9e6e3ca8569f2d7c0a
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java163
-rw-r--r--services/core/java/com/android/server/LockSettingsStorage.java101
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java44
4 files changed, 259 insertions, 51 deletions
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 2e6d1c1..48f4120 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -44,12 +44,14 @@ import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.security.KeyStore;
+import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LockSettingsStorage.CredentialHash;
import java.util.Arrays;
import java.util.List;
@@ -72,6 +74,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
+ private IGateKeeperService mGateKeeperService;
public LockSettingsService(Context context) {
mContext = context;
@@ -131,6 +134,7 @@ public class LockSettingsService extends ILockSettings.Stub {
public void systemReady() {
migrateOldData();
+ getGateKeeperService();
mStorage.prefetchUser(UserHandle.USER_OWNER);
}
@@ -277,7 +281,6 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
checkReadPermission(key, userId);
-
String value = getStringUnchecked(key, null, userId);
return TextUtils.isEmpty(value) ?
defaultValue : (value.equals("1") || value.equals("true"));
@@ -345,40 +348,133 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+
+ private byte[] getCurrentHandle(int userId) {
+ CredentialHash credential;
+ byte[] currentHandle;
+
+ int currentHandleType = mStorage.getStoredCredentialType(userId);
+ switch (currentHandleType) {
+ case CredentialHash.TYPE_PATTERN:
+ credential = mStorage.readPatternHash(userId);
+ currentHandle = credential != null
+ ? credential.hash
+ : null;
+ break;
+ case CredentialHash.TYPE_PASSWORD:
+ credential = mStorage.readPasswordHash(userId);
+ currentHandle = credential != null
+ ? credential.hash
+ : null;
+ break;
+ case CredentialHash.TYPE_NONE:
+ default:
+ currentHandle = null;
+ break;
+ }
+
+ // sanity check
+ if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
+ Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
+ }
+
+ return currentHandle;
+ }
+
+
@Override
- public void setLockPattern(String pattern, int userId) throws RemoteException {
- checkWritePermission(userId);
+ public void setLockPattern(String pattern, String savedCredential, int userId)
+ throws RemoteException {
+ byte[] currentHandle = getCurrentHandle(userId);
- maybeUpdateKeystore(pattern, userId);
+ if (currentHandle == null) {
+ if (savedCredential != null) {
+ Slog.w(TAG, "Saved credential provided, but none stored");
+ }
+ savedCredential = null;
+ }
- final byte[] hash = LockPatternUtils.patternToHash(
- LockPatternUtils.stringToPattern(pattern));
- mStorage.writePatternHash(hash, userId);
+ byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
+ if (enrolledHandle != null) {
+ mStorage.writePatternHash(enrolledHandle, userId);
+ } else {
+ Slog.e(TAG, "Failed to enroll pattern");
+ }
}
+
@Override
- public void setLockPassword(String password, int userId) throws RemoteException {
- checkWritePermission(userId);
+ public void setLockPassword(String password, String savedCredential, int userId)
+ throws RemoteException {
- maybeUpdateKeystore(password, userId);
+ byte[] currentHandle = getCurrentHandle(userId);
+
+ if (currentHandle == null) {
+ if (savedCredential != null) {
+ Slog.w(TAG, "Saved credential provided, but none stored");
+ }
+ savedCredential = null;
+ }
+
+ byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
+ if (enrolledHandle != null) {
+ mStorage.writePasswordHash(enrolledHandle, userId);
+ } else {
+ Slog.e(TAG, "Failed to enroll password");
+ }
+ }
+
+ private byte[] enrollCredential(byte[] enrolledHandle,
+ String enrolledCredential, String toEnroll, int userId)
+ throws RemoteException {
+ checkWritePermission(userId);
+ byte[] enrolledCredentialBytes = enrolledCredential == null
+ ? null
+ : enrolledCredential.getBytes();
+ byte[] toEnrollBytes = toEnroll == null
+ ? null
+ : toEnroll.getBytes();
+ byte[] hash = getGateKeeperService().enroll(userId, enrolledHandle, enrolledCredentialBytes,
+ toEnrollBytes);
+
+ if (hash != null) {
+ maybeUpdateKeystore(toEnroll, userId);
+ }
- mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
+ return hash;
}
@Override
public boolean checkPattern(String pattern, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
- byte[] storedHash = mStorage.readPatternHash(userId);
+
+ CredentialHash storedHash = mStorage.readPatternHash(userId);
if (storedHash == null) {
return true;
}
- boolean matched = Arrays.equals(hash, storedHash);
+ if (storedHash.version == CredentialHash.VERSION_LEGACY) {
+ // Try the old backend and upgrade if a match is found
+ byte[] hash = LockPatternUtils.patternToHash(
+ LockPatternUtils.stringToPattern(pattern));
+ boolean matched = Arrays.equals(hash, storedHash.hash);
+ if (matched && !TextUtils.isEmpty(pattern)) {
+ maybeUpdateKeystore(pattern, userId);
+ // migrate pattern to GateKeeper
+ setLockPattern(pattern, null, userId);
+ }
+
+ return matched;
+ }
+
+ boolean matched = getGateKeeperService()
+ .verify(userId, storedHash.hash, pattern.getBytes());
if (matched && !TextUtils.isEmpty(pattern)) {
maybeUpdateKeystore(pattern, userId);
+ return true;
}
+
return matched;
}
@@ -386,17 +482,31 @@ public class LockSettingsService extends ILockSettings.Stub {
public boolean checkPassword(String password, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
- byte[] storedHash = mStorage.readPasswordHash(userId);
+ CredentialHash storedHash = mStorage.readPasswordHash(userId);
if (storedHash == null) {
return true;
}
- boolean matched = Arrays.equals(hash, storedHash);
- if (matched && !TextUtils.isEmpty(password)) {
+ if (storedHash.version == CredentialHash.VERSION_LEGACY) {
+ byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
+ boolean matched = Arrays.equals(hash, storedHash.hash);
+ if (matched && !TextUtils.isEmpty(password)) {
+ maybeUpdateKeystore(password, userId);
+ // migrate password to GateKeeper
+ setLockPassword(password, null, userId);
+ }
+ return matched;
+ }
+
+
+
+ boolean matched = getGateKeeperService()
+ .verify(userId, storedHash.hash, password.getBytes());
+ if (!TextUtils.isEmpty(password) && matched) {
maybeUpdateKeystore(password, userId);
}
+
return matched;
}
@@ -497,4 +607,21 @@ public class LockSettingsService extends ILockSettings.Stub {
}
return null;
}
+
+ private synchronized IGateKeeperService getGateKeeperService() {
+ if (mGateKeeperService != null) {
+ return mGateKeeperService;
+ }
+
+ final IBinder service =
+ ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
+ if (service != null) {
+ mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
+ return mGateKeeperService;
+ }
+
+ Slog.e(TAG, "Unable to acquire GateKeeperService");
+ return null;
+ }
+
}
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index d81daa9..f202c36 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -56,8 +56,10 @@ class LockSettingsStorage {
};
private static final String SYSTEM_DIRECTORY = "/system/";
- private static final String LOCK_PATTERN_FILE = "gesture.key";
- private static final String LOCK_PASSWORD_FILE = "password.key";
+ private static final String 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 Object DEFAULT = new Object();
@@ -66,6 +68,25 @@ class LockSettingsStorage {
private final Cache mCache = new Cache();
private final Object mFileWriteLock = new Object();
+ private int mStoredCredentialType;
+
+ class CredentialHash {
+ static final int TYPE_NONE = -1;
+ static final int TYPE_PATTERN = 1;
+ static final int TYPE_PASSWORD = 2;
+
+ static final int VERSION_LEGACY = 0;
+ static final int VERSION_GATEKEEPER = 1;
+
+ CredentialHash(byte[] hash, int version) {
+ this.hash = hash;
+ this.version = version;
+ }
+
+ byte[] hash;
+ int version;
+ }
+
public LockSettingsStorage(Context context, Callback callback) {
mContext = context;
mOpenHelper = new DatabaseHelper(context, callback);
@@ -148,28 +169,72 @@ class LockSettingsStorage {
readPatternHash(userId);
}
- public byte[] readPasswordHash(int userId) {
- final byte[] stored = readFile(getLockPasswordFilename(userId));
+ public int getStoredCredentialType(int userId) {
+ if (mStoredCredentialType != 0) {
+ return mStoredCredentialType;
+ }
+
+ CredentialHash pattern = readPatternHash(userId);
+ if (pattern == null) {
+ if (readPasswordHash(userId) != null) {
+ mStoredCredentialType = CredentialHash.TYPE_PASSWORD;
+ } else {
+ mStoredCredentialType = CredentialHash.TYPE_NONE;
+ }
+ } else {
+ CredentialHash password = readPasswordHash(userId);
+ if (password != null) {
+ // Both will never be GateKeeper
+ if (password.version == CredentialHash.VERSION_GATEKEEPER) {
+ mStoredCredentialType = CredentialHash.TYPE_PASSWORD;
+ } else {
+ mStoredCredentialType = CredentialHash.TYPE_PATTERN;
+ }
+ } else {
+ mStoredCredentialType = CredentialHash.TYPE_PATTERN;
+ }
+ }
+
+ return mStoredCredentialType;
+ }
+
+
+ public CredentialHash readPasswordHash(int userId) {
+ byte[] stored = readFile(getLockPasswordFilename(userId));
if (stored != null && stored.length > 0) {
- return stored;
+ return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
}
+
+ stored = readFile(getLegacyLockPasswordFilename(userId));
+ if (stored != null && stored.length > 0) {
+ return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
+ }
+
return null;
}
- public byte[] readPatternHash(int userId) {
- final byte[] stored = readFile(getLockPatternFilename(userId));
+ public CredentialHash readPatternHash(int userId) {
+ byte[] stored = readFile(getLockPatternFilename(userId));
if (stored != null && stored.length > 0) {
- return stored;
+ return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
}
+
+ stored = readFile(getLegacyLockPatternFilename(userId));
+ if (stored != null && stored.length > 0) {
+ return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
+ }
+
return null;
}
public boolean hasPassword(int userId) {
- return hasFile(getLockPasswordFilename(userId));
+ return hasFile(getLockPasswordFilename(userId)) ||
+ hasFile(getLegacyLockPasswordFilename(userId));
}
public boolean hasPattern(int userId) {
- return hasFile(getLockPatternFilename(userId));
+ return hasFile(getLockPatternFilename(userId)) ||
+ hasFile(getLegacyLockPatternFilename(userId));
}
private boolean hasFile(String name) {
@@ -237,6 +302,9 @@ class LockSettingsStorage {
}
public void writePatternHash(byte[] hash, int userId) {
+ mStoredCredentialType = hash == null
+ ? CredentialHash.TYPE_NONE
+ : CredentialHash.TYPE_PATTERN;
writeFile(getLockPatternFilename(userId), hash);
clearPasswordHash(userId);
}
@@ -246,6 +314,9 @@ class LockSettingsStorage {
}
public void writePasswordHash(byte[] hash, int userId) {
+ mStoredCredentialType = hash == null
+ ? CredentialHash.TYPE_NONE
+ : CredentialHash.TYPE_PASSWORD;
writeFile(getLockPasswordFilename(userId), hash);
clearPatternHash(userId);
}
@@ -264,6 +335,16 @@ 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 getLockCredentialFilePathForUser(int userId, String basename) {
userId = getUserParentOrSelfId(userId);
String dataSystemDirectory =
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3677132..2ff80c6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2799,7 +2799,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
if (!TextUtils.isEmpty(password)) {
- utils.saveLockPassword(password, quality, userHandle);
+ utils.saveLockPassword(password, null, quality, userHandle);
} else {
utils.clearLock(userHandle);
}
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
index bf0e75d..dae8447 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
@@ -219,31 +219,31 @@ public class LockSettingsStorageTests extends AndroidTestCase {
public void testPassword_Write() {
mStorage.writePasswordHash("thepassword".getBytes(), 0);
- assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+ assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
mStorage.clearCache();
- assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+ assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
}
public void testPassword_WriteProfileWritesParent() {
mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
mStorage.writePasswordHash("profilepassword".getBytes(), 2);
- assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
- assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+ assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
+ assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
mStorage.clearCache();
- assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
- assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+ assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
+ assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
}
public void testPassword_WriteParentWritesProfile() {
mStorage.writePasswordHash("profilepassword".getBytes(), 2);
mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
- assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
- assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+ assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
+ assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
mStorage.clearCache();
- assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
- assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+ assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
+ assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
}
public void testPattern_Default() {
@@ -253,31 +253,31 @@ public class LockSettingsStorageTests extends AndroidTestCase {
public void testPattern_Write() {
mStorage.writePatternHash("thepattern".getBytes(), 0);
- assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+ assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
mStorage.clearCache();
- assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+ assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
}
public void testPattern_WriteProfileWritesParent() {
mStorage.writePatternHash("parentpatternn".getBytes(), 1);
mStorage.writePatternHash("profilepattern".getBytes(), 2);
- assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
- assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+ assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
+ assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
mStorage.clearCache();
- assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
- assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+ assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
+ assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
}
public void testPattern_WriteParentWritesProfile() {
mStorage.writePatternHash("profilepattern".getBytes(), 2);
mStorage.writePatternHash("parentpatternn".getBytes(), 1);
- assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
- assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+ assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
+ assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
mStorage.clearCache();
- assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
- assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+ assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
+ assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
}
public void testPrefetch() {
@@ -289,8 +289,8 @@ public class LockSettingsStorageTests extends AndroidTestCase {
mStorage.prefetchUser(0);
assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
- assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0));
- assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0));
+ assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0).hash);
+ assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0).hash);
}
public void testFileLocation_Owner() {