summaryrefslogtreecommitdiffstats
path: root/core/java/com/android
diff options
context:
space:
mode:
authorAndres Morales <anmorales@google.com>2015-05-14 22:42:26 -0700
committerAndres Morales <anmorales@google.com>2015-05-26 19:48:51 -0700
commit2397427cb1a0bad8a42e6a342dcf29b31e40a234 (patch)
tree08695c000f77519a3698bb25044023973d0ce6f8 /core/java/com/android
parentaba3ecb976cacd7c92fe8f8afae20d112781d68e (diff)
downloadframeworks_base-2397427cb1a0bad8a42e6a342dcf29b31e40a234.zip
frameworks_base-2397427cb1a0bad8a42e6a342dcf29b31e40a234.tar.gz
frameworks_base-2397427cb1a0bad8a42e6a342dcf29b31e40a234.tar.bz2
[LockSettings] migrate password attempt throttling to hardware
leverage root protected, cryptographically secured hardware if available Bug: 21118563 Change-Id: Ifa804c5a0728bfd14466eb2a84051bace6d33d57
Diffstat (limited to 'core/java/com/android')
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl10
-rw-r--r--core/java/com/android/internal/widget/LockPatternChecker.java54
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java96
-rw-r--r--core/java/com/android/internal/widget/VerifyCredentialResponse.aidl24
-rw-r--r--core/java/com/android/internal/widget/VerifyCredentialResponse.java126
5 files changed, 273 insertions, 37 deletions
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index bfafff6..dfb7c50 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import com.android.internal.widget.VerifyCredentialResponse;
+
/** {@hide} */
interface ILockSettings {
void setBoolean(in String key, in boolean value, in int userId);
@@ -25,11 +27,11 @@ interface ILockSettings {
long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
void setLockPattern(in String pattern, in String savedPattern, int userId);
- boolean checkPattern(in String pattern, int userId);
- byte[] verifyPattern(in String pattern, long challenge, int userId);
+ VerifyCredentialResponse checkPattern(in String pattern, int userId);
+ VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId);
void setLockPassword(in String password, in String savedPassword, int userId);
- boolean checkPassword(in String password, int userId);
- byte[] verifyPassword(in String password, long challenge, int userId);
+ VerifyCredentialResponse checkPassword(in String password, int userId);
+ VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index ac0f5fe..4880664 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -2,6 +2,8 @@ package com.android.internal.widget;
import android.os.AsyncTask;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+
import java.util.List;
/**
@@ -16,8 +18,10 @@ public final class LockPatternChecker {
* Invoked when a security check is finished.
*
* @param matched Whether the PIN/Password/Pattern matches the stored one.
+ * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
+ * the call. Only non-0 if matched is false.
*/
- void onChecked(boolean matched);
+ void onChecked(boolean matched, int throttleTimeoutMs);
}
/**
@@ -28,8 +32,10 @@ public final class LockPatternChecker {
* Invoked when a security verification is finished.
*
* @param attestation The attestation that the challenge was verified, or null.
+ * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
+ * the call. Only non-0 if attestation is null.
*/
- void onVerified(byte[] attestation);
+ void onVerified(byte[] attestation, int throttleTimeoutMs);
}
/**
@@ -47,14 +53,21 @@ public final class LockPatternChecker {
final int userId,
final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
+ private int mThrottleTimeout;
+
@Override
protected byte[] doInBackground(Void... args) {
- return utils.verifyPattern(pattern, challenge, userId);
+ try {
+ return utils.verifyPattern(pattern, challenge, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return null;
+ }
}
@Override
protected void onPostExecute(byte[] result) {
- callback.onVerified(result);
+ callback.onVerified(result, mThrottleTimeout);
}
};
task.execute();
@@ -74,14 +87,21 @@ public final class LockPatternChecker {
final int userId,
final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
+ private int mThrottleTimeout;
+
@Override
protected Boolean doInBackground(Void... args) {
- return utils.checkPattern(pattern, userId);
+ try {
+ return utils.checkPattern(pattern, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return false;
+ }
}
@Override
protected void onPostExecute(Boolean result) {
- callback.onChecked(result);
+ callback.onChecked(result, mThrottleTimeout);
}
};
task.execute();
@@ -103,14 +123,21 @@ public final class LockPatternChecker {
final int userId,
final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
+ private int mThrottleTimeout;
+
@Override
protected byte[] doInBackground(Void... args) {
- return utils.verifyPassword(password, challenge, userId);
+ try {
+ return utils.verifyPassword(password, challenge, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return null;
+ }
}
@Override
protected void onPostExecute(byte[] result) {
- callback.onVerified(result);
+ callback.onVerified(result, mThrottleTimeout);
}
};
task.execute();
@@ -130,14 +157,21 @@ public final class LockPatternChecker {
final int userId,
final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
+ private int mThrottleTimeout;
+
@Override
protected Boolean doInBackground(Void... args) {
- return utils.checkPassword(password, userId);
+ try {
+ return utils.checkPassword(password, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return false;
+ }
}
@Override
protected void onPostExecute(Boolean result) {
- callback.onChecked(result);
+ callback.onChecked(result, mThrottleTimeout);
}
};
task.execute();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e5ef60c..8d85b33 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -60,24 +60,12 @@ public class LockPatternUtils {
private static final boolean DEBUG = false;
/**
- * The maximum number of incorrect attempts before the user is prevented
- * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
- */
- public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
-
- /**
* The number of incorrect attempts before which we fall back on an alternative
* method of verifying the user, and resetting their lock pattern.
*/
public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
/**
- * How long the user is prevented from trying again after entering the
- * wrong pattern too many times.
- */
- public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
-
- /**
* The interval of the countdown for showing progress of the lockout.
*/
public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
@@ -109,6 +97,7 @@ public class LockPatternUtils {
@Deprecated
public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
+ public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
@@ -144,6 +133,23 @@ public class LockPatternUtils {
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
+
+ public static final class RequestThrottledException extends Exception {
+ private int mTimeoutMs;
+ public RequestThrottledException(int timeoutMs) {
+ mTimeoutMs = timeoutMs;
+ }
+
+ /**
+ * @return The amount of time in ms before another request may
+ * be executed
+ */
+ public int getTimeoutMs() {
+ return mTimeoutMs;
+ }
+
+ }
+
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
mDevicePolicyManager =
@@ -239,9 +245,23 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the pattern
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) {
+ public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+ if (response == null) {
+ // Shouldn't happen
+ return null;
+ }
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return response.getPayload();
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return null;
+ }
} catch (RemoteException re) {
return null;
}
@@ -253,9 +273,19 @@ public class LockPatternUtils {
* @param pattern The pattern to check.
* @return Whether the pattern matches the stored one.
*/
- public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) {
+ public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().checkPattern(patternToString(pattern), userId);
+ VerifyCredentialResponse response =
+ getLockSettings().checkPattern(patternToString(pattern), userId);
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return true;
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return false;
+ }
} catch (RemoteException re) {
return true;
}
@@ -270,9 +300,19 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPassword(String password, long challenge, int userId) {
+ public byte[] verifyPassword(String password, long challenge, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().verifyPassword(password, challenge, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().verifyPassword(password, challenge, userId);
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return response.getPayload();
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return null;
+ }
} catch (RemoteException re) {
return null;
}
@@ -284,9 +324,17 @@ public class LockPatternUtils {
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
- public boolean checkPassword(String password, int userId) {
+ public boolean checkPassword(String password, int userId) throws RequestThrottledException {
try {
- return getLockSettings().checkPassword(password, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().checkPassword(password, userId);
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return true;
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return false;
+ }
} catch (RemoteException re) {
return true;
}
@@ -969,9 +1017,10 @@ public class LockPatternUtils {
* pattern until the deadline has passed.
* @return the chosen deadline.
*/
- public long setLockoutAttemptDeadline(int userId) {
- final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
+ public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
+ final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
+ setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
return deadline;
}
@@ -982,8 +1031,9 @@ public class LockPatternUtils {
*/
public long getLockoutAttemptDeadline(int userId) {
final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
+ final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
final long now = SystemClock.elapsedRealtime();
- if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
+ if (deadline < now || deadline > (now + timeoutMs)) {
return 0L;
}
return deadline;
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl
new file mode 100644
index 0000000..59a4bba
--- /dev/null
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+/**
+ * Response object for an ILockSettings verification request.
+ * @hide
+ */
+parcelable VerifyCredentialResponse;
+
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
new file mode 100644
index 0000000..48109ca
--- /dev/null
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Response object for a ILockSettings credential verification request.
+ * @hide
+ */
+public final class VerifyCredentialResponse implements Parcelable {
+
+ public static final int RESPONSE_ERROR = -1;
+ public static final int RESPONSE_OK = 0;
+ public static final int RESPONSE_RETRY = 1;
+
+ public static final VerifyCredentialResponse OK = new VerifyCredentialResponse();
+ public static final VerifyCredentialResponse ERROR
+ = new VerifyCredentialResponse(RESPONSE_ERROR, 0, null);
+
+ private int mResponseCode;
+ private byte[] mPayload;
+ private int mTimeout;
+
+ public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR
+ = new Parcelable.Creator<VerifyCredentialResponse>() {
+ @Override
+ public VerifyCredentialResponse createFromParcel(Parcel source) {
+ int responseCode = source.readInt();
+ VerifyCredentialResponse response = new VerifyCredentialResponse(responseCode, 0, null);
+ if (responseCode == RESPONSE_RETRY) {
+ response.setTimeout(source.readInt());
+ } else if (responseCode == RESPONSE_OK) {
+ int size = source.readInt();
+ if (size > 0) {
+ byte[] payload = new byte[size];
+ source.readByteArray(payload);
+ response.setPayload(payload);
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public VerifyCredentialResponse[] newArray(int size) {
+ return new VerifyCredentialResponse[size];
+ }
+
+ };
+
+ public VerifyCredentialResponse() {
+ mResponseCode = RESPONSE_OK;
+ mPayload = null;
+ }
+
+
+ public VerifyCredentialResponse(byte[] payload) {
+ mPayload = payload;
+ mResponseCode = RESPONSE_OK;
+ }
+
+ public VerifyCredentialResponse(int timeout) {
+ mTimeout = timeout;
+ mResponseCode = RESPONSE_RETRY;
+ mPayload = null;
+ }
+
+ private VerifyCredentialResponse(int responseCode, int timeout, byte[] payload) {
+ mResponseCode = responseCode;
+ mTimeout = timeout;
+ mPayload = payload;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResponseCode);
+ if (mResponseCode == RESPONSE_RETRY) {
+ dest.writeInt(mTimeout);
+ } else if (mResponseCode == RESPONSE_OK) {
+ if (mPayload != null) {
+ dest.writeInt(mPayload.length);
+ dest.writeByteArray(mPayload);
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public byte[] getPayload() {
+ return mPayload;
+ }
+
+ public int getTimeout() {
+ return mTimeout;
+ }
+
+ public int getResponseCode() {
+ return mResponseCode;
+ }
+
+ private void setTimeout(int timeout) {
+ mTimeout = timeout;
+ }
+
+ private void setPayload(byte[] payload) {
+ mPayload = payload;
+ }
+}