Merge "Implement startRemoteLockscreenValidation."

This commit is contained in:
Dmitry Dementyev
2023-02-03 15:23:40 +00:00
committed by Android (Google) Code Review
7 changed files with 515 additions and 24 deletions

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 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 android.app;
/** {@hide} */
parcelable RemoteLockscreenValidationResult;

View File

@@ -0,0 +1,150 @@
/*
* Copyright (C) 2023 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 android.app;
import android.annotation.DurationMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Result of lock screen credentials verification.
*
* @hide
*/
public final class RemoteLockscreenValidationResult implements Parcelable {
/**
* The guess was correct
*/
public static final int RESULT_GUESS_VALID = 1;
/**
* Remote device provided incorrect credentials.
*/
public static final int RESULT_GUESS_INVALID = 2;
/**
* The operation was canceled because the API is locked out due to too many attempts. It
* usually happens after 5 failed attempts and API may be called again after a short
* delay specified by {@code getTimeoutMillis}.
*/
public static final int RESULT_LOCKOUT = 3;
/**
* There were too many invalid guesses.
*/
public static final int RESULT_NO_REMAINING_ATTEMPTS = 4;
@IntDef({RESULT_GUESS_VALID,
RESULT_GUESS_INVALID,
RESULT_LOCKOUT,
RESULT_NO_REMAINING_ATTEMPTS})
@Retention(RetentionPolicy.SOURCE)
@interface ResultCode {}
private int mResultCode;
private long mTimeoutMillis;
public static final @NonNull Parcelable.Creator<RemoteLockscreenValidationResult> CREATOR =
new Parcelable.Creator<RemoteLockscreenValidationResult>() {
@Override
public RemoteLockscreenValidationResult createFromParcel(Parcel source) {
return new RemoteLockscreenValidationResult(source);
}
@Override
public RemoteLockscreenValidationResult[] newArray(int size) {
return new RemoteLockscreenValidationResult[size];
}
};
/**
* Builder for {@code RemoteLockscreenValidationResult}
*/
public static final class Builder {
private RemoteLockscreenValidationResult mInstance = new RemoteLockscreenValidationResult();
/**
* Sets the result code.
*/
public @NonNull Builder setResultCode(@ResultCode int resultCode) {
mInstance.mResultCode = resultCode;
return this;
}
/**
* Sets timeout for {@code RESULT_LOCKOUT}.
* Default value is {@code 0}.
*/
public @NonNull Builder setTimeoutMillis(@DurationMillisLong long timeoutMillis) {
mInstance.mTimeoutMillis = timeoutMillis;
return this;
}
/**
* Creates {@code RemoteLockscreenValidationResult}.
*
* @throws IllegalStateException if result code was not set.
*/
public @NonNull RemoteLockscreenValidationResult build() {
if (mInstance.mResultCode == 0) {
throw new IllegalStateException("Result code must be set");
}
return mInstance;
}
}
/**
* Gets the result code.
*/
public @ResultCode int getResultCode() {
return mResultCode;
}
/**
* Delay before next attempt to verify credentials.
*
* Default value is {@code 0}.
*/
public @DurationMillisLong long getTimeoutMillis() {
return mTimeoutMillis;
}
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mResultCode);
out.writeLong(mTimeoutMillis);
}
private RemoteLockscreenValidationResult() {
}
private RemoteLockscreenValidationResult(Parcel in) {
mResultCode = in.readInt();
mTimeoutMillis = in.readLong();
}
@Override
public int describeContents() {
return 0;
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2023 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 android.app;
/** {@hide} */
parcelable StartLockscreenValidationRequest;

View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2023 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 android.app;
import android.annotation.NonNull;
import android.app.KeyguardManager.LockTypes;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Provides information necessary to perform remote lock screen credentials check.
*
* @hide
*/
public final class StartLockscreenValidationRequest implements Parcelable {
@LockTypes
private int mLockscreenUiType;
private byte[] mSourcePublicKey;
private int mRemainingAttempts;
public static final @NonNull Parcelable.Creator<StartLockscreenValidationRequest> CREATOR = new
Parcelable.Creator<StartLockscreenValidationRequest>() {
@Override
public StartLockscreenValidationRequest createFromParcel(Parcel source) {
return new StartLockscreenValidationRequest(source);
}
@Override
public StartLockscreenValidationRequest[] newArray(int size) {
return new StartLockscreenValidationRequest[size];
}
};
/**
* Builder for {@code StartLockscreenValidationRequest}
*/
public static final class Builder {
private StartLockscreenValidationRequest mInstance = new StartLockscreenValidationRequest();
/**
* Sets UI type.
* Default value is {@code LockTypes.PASSWORD}
*
* @param lockscreenUiType The UI format
* @return This builder.
*/
public @NonNull Builder setLockscreenUiType(@LockTypes int lockscreenUiType) {
mInstance.mLockscreenUiType = lockscreenUiType;
return this;
}
/**
* Sets public key using secure box encoding
* @return This builder.
*/
public @NonNull Builder setSourcePublicKey(@NonNull byte[] publicKey) {
mInstance.mSourcePublicKey = publicKey;
return this;
}
/**
* Sets the number of remaining credentials check
* Default value is {@code 0}
*
* @return This builder.
*/
public @NonNull Builder setRemainingAttempts(int remainingAttempts) {
mInstance.mRemainingAttempts = remainingAttempts;
return this;
}
/**
* Creates {@code StartLockscreenValidationRequest}
*
* @throws NullPointerException if required fields are not set.
*/
public @NonNull StartLockscreenValidationRequest build() {
Objects.requireNonNull(mInstance.mSourcePublicKey);
return mInstance;
}
}
/**
* Specifies lock screen credential type.
*/
public @LockTypes int getLockscreenUiType() {
return mLockscreenUiType;
}
/**
* Public key used to send encrypted credentials.
*/
public @NonNull byte[] getSourcePublicKey() {
return mSourcePublicKey;
}
/**
* Number of remaining attempts to verify credentials.
*
* <p>After correct guess counter is reset to {@code 5}.
*/
public int getRemainingAttempts() {
return mRemainingAttempts;
}
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mLockscreenUiType);
out.writeByteArray(mSourcePublicKey);
out.writeInt(mRemainingAttempts);
}
private StartLockscreenValidationRequest() {
}
private StartLockscreenValidationRequest(Parcel in) {
mLockscreenUiType = in.readInt();
mSourcePublicKey = in.createByteArray();
mRemainingAttempts = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
}

View File

@@ -58,6 +58,8 @@ import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
import android.app.StartLockscreenValidationRequest;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.DeviceStateCache;
@@ -118,7 +120,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.FeatureFlagUtils;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -2553,23 +2554,18 @@ public class LockSettingsService extends ILockSettings.Stub {
/**
* Starts a session to verify lock screen credentials provided by a remote device.
*/
public void startRemoteLockscreenValidation() {
if (!FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API)) {
throw new UnsupportedOperationException("Under development");
}
mRecoverableKeyStoreManager.startRemoteLockscreenValidation();
@NonNull
public StartLockscreenValidationRequest startRemoteLockscreenValidation() {
return mRecoverableKeyStoreManager.startRemoteLockscreenValidation(this);
}
/**
* Verifies credentials guess from a remote device.
* Verifies encrypted credentials guess from a remote device.
*/
public void validateRemoteLockscreen(@NonNull byte[] encryptedCredential) {
if (!FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API)) {
throw new UnsupportedOperationException("Under development");
}
mRecoverableKeyStoreManager.validateRemoteLockscreen(encryptedCredential);
@NonNull
public RemoteLockscreenValidationResult
validateRemoteLockScreen2(@NonNull byte[] encryptedCredential) {
return mRecoverableKeyStoreManager.validateRemoteLockscreen(encryptedCredential, this);
}
// Reading these settings needs the contacts permission

View File

@@ -28,7 +28,10 @@ import static android.security.keystore.recovery.RecoveryController.ERROR_SESSIO
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.RemoteLockscreenValidationResult;
import android.app.StartLockscreenValidationRequest;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
@@ -40,11 +43,14 @@ import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.RecoveryController;
import android.security.keystore.recovery.WrappedApplicationKey;
import android.util.ArrayMap;
import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.widget.LockPatternUtils;
import com.android.security.SecureBox;
import com.android.server.locksettings.LockSettingsService;
import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException;
import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils;
import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException;
@@ -55,6 +61,8 @@ import com.android.server.locksettings.recoverablekeystore.storage.CleanupManage
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RemoteLockscreenValidationSessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RemoteLockscreenValidationSessionStorage.LockscreenVerificationSession;
import java.io.IOException;
import java.security.InvalidKeyException;
@@ -103,6 +111,9 @@ public class RecoverableKeyStoreManager {
private final ApplicationKeyStorage mApplicationKeyStorage;
private final TestOnlyInsecureCertificateHelper mTestCertHelper;
private final CleanupManager mCleanupManager;
// only set if SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API is enabled.
@Nullable private final RemoteLockscreenValidationSessionStorage
mRemoteLockscreenValidationSessionStorage;
/**
* Returns a new or existing instance.
@@ -112,7 +123,18 @@ public class RecoverableKeyStoreManager {
public static synchronized RecoverableKeyStoreManager
getInstance(Context context) {
if (mInstance == null) {
RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context);
RecoverableKeyStoreDb db;
RemoteLockscreenValidationSessionStorage lockscreenCheckSessions;
if (FeatureFlagUtils.isEnabled(context,
FeatureFlagUtils.SETTINGS_ENABLE_LOCKSCREEN_TRANSFER_API)) {
// TODO(b/254335492): Remove flag check when feature is launched.
db = RecoverableKeyStoreDb.newInstance(context, 7);
lockscreenCheckSessions = new RemoteLockscreenValidationSessionStorage();
} else {
db = RecoverableKeyStoreDb.newInstance(context);
lockscreenCheckSessions = null;
}
PlatformKeyManager platformKeyManager;
ApplicationKeyStorage applicationKeyStorage;
try {
@@ -142,7 +164,8 @@ public class RecoverableKeyStoreManager {
platformKeyManager,
applicationKeyStorage,
new TestOnlyInsecureCertificateHelper(),
cleanupManager);
cleanupManager,
lockscreenCheckSessions);
}
return mInstance;
}
@@ -158,7 +181,8 @@ public class RecoverableKeyStoreManager {
PlatformKeyManager platformKeyManager,
ApplicationKeyStorage applicationKeyStorage,
TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
CleanupManager cleanupManager) {
CleanupManager cleanupManager,
RemoteLockscreenValidationSessionStorage remoteLockscreenValidationSessionStorage) {
mContext = context;
mDatabase = recoverableKeyStoreDb;
mRecoverySessionStorage = recoverySessionStorage;
@@ -177,6 +201,7 @@ public class RecoverableKeyStoreManager {
Log.wtf(TAG, "AES keygen algorithm not available. AOSP must support this.", e);
throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage());
}
mRemoteLockscreenValidationSessionStorage = remoteLockscreenValidationSessionStorage;
}
/**
@@ -969,19 +994,50 @@ public class RecoverableKeyStoreManager {
/**
* Starts a session to verify lock screen credentials provided by a remote device.
*/
public void startRemoteLockscreenValidation() {
public StartLockscreenValidationRequest startRemoteLockscreenValidation(
LockSettingsService lockSettingService) {
if (mRemoteLockscreenValidationSessionStorage == null) {
throw new UnsupportedOperationException("Under development");
}
checkVerifyRemoteLockscreenPermission();
// TODO(b/254335492): Create session in memory
return;
int userId = UserHandle.getCallingUserId();
int savedCredentialType;
final long token = Binder.clearCallingIdentity();
try {
savedCredentialType = lockSettingService.getCredentialType(userId);
} finally {
Binder.restoreCallingIdentity(token);
}
int keyguardCredentailsType = lockPatternUtilsToKeyguardType(savedCredentialType);
LockscreenVerificationSession session =
mRemoteLockscreenValidationSessionStorage.startSession(userId);
PublicKey publicKey = session.getKeyPair().getPublic();
byte[] encodedPublicKey = SecureBox.encodePublicKey(publicKey);
int badGuesses = mDatabase.getBadRemoteGuessCounter(userId);
return new StartLockscreenValidationRequest.Builder()
.setLockscreenUiType(keyguardCredentailsType)
.setSourcePublicKey(new byte[]{})
.build();
}
/**
* Verifies encrypted credentials guess from a remote device.
*/
public void validateRemoteLockscreen(@NonNull byte[] encryptedCredential) {
public RemoteLockscreenValidationResult validateRemoteLockscreen(
@NonNull byte[] encryptedCredential,
LockSettingsService lockSettingService) {
if (mRemoteLockscreenValidationSessionStorage == null) {
throw new UnsupportedOperationException("Under development");
}
checkVerifyRemoteLockscreenPermission();
// TODO(b/254335492): Decrypt and verify credentials
return;
int userId = UserHandle.getCallingUserId();
LockscreenVerificationSession session =
mRemoteLockscreenValidationSessionStorage.get(userId);
if (session == null) {
throw new IllegalStateException("There is no active lock screen check session");
}
// TODO(b/254335492): Call lockSettingService.verifyCredential
return new RemoteLockscreenValidationResult.Builder().build();
}
private void checkVerifyRemoteLockscreenPermission() {
@@ -995,6 +1051,21 @@ public class RecoverableKeyStoreManager {
mCleanupManager.registerRecoveryAgent(userId, uid);
}
private int lockPatternUtilsToKeyguardType(int credentialsType) {
switch(credentialsType) {
case LockPatternUtils.CREDENTIAL_TYPE_NONE:
throw new IllegalStateException("Screen lock is not set");
case LockPatternUtils.CREDENTIAL_TYPE_PATTERN:
return KeyguardManager.PATTERN;
case LockPatternUtils.CREDENTIAL_TYPE_PIN:
return KeyguardManager.PIN;
case LockPatternUtils.CREDENTIAL_TYPE_PASSWORD:
return KeyguardManager.PASSWORD;
default:
throw new IllegalStateException("Screen lock is not set");
}
}
private void checkRecoverKeyStorePermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.RECOVER_KEYSTORE,

View File

@@ -40,6 +40,7 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.StartLockscreenValidationRequest;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -61,11 +62,13 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.security.SecureBox;
import com.android.server.locksettings.LockSettingsService;
import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage;
import com.android.server.locksettings.recoverablekeystore.storage.CleanupManager;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySessionStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
import com.android.server.locksettings.recoverablekeystore.storage.RemoteLockscreenValidationSessionStorage;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -160,14 +163,17 @@ public class RecoverableKeyStoreManagerTest {
@Mock private ApplicationKeyStorage mApplicationKeyStorage;
@Mock private CleanupManager mCleanupManager;
@Mock private ScheduledExecutorService mExecutorService;
@Mock private LockSettingsService mLockSettingsService;
@Spy private TestOnlyInsecureCertificateHelper mTestOnlyInsecureCertificateHelper;
private int mUserId;
private RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private File mDatabaseFile;
private RecoverableKeyStoreManager mRecoverableKeyStoreManager;
private RecoverySessionStorage mRecoverySessionStorage;
private RecoverySnapshotStorage mRecoverySnapshotStorage;
private PlatformEncryptionKey mPlatformEncryptionKey;
private RemoteLockscreenValidationSessionStorage mRemoteLockscreenValidationSessionStorage;
@Before
public void setUp() throws Exception {
@@ -177,7 +183,9 @@ public class RecoverableKeyStoreManagerTest {
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
mUserId = UserHandle.getCallingUserId();
mRecoverySessionStorage = new RecoverySessionStorage();
mRemoteLockscreenValidationSessionStorage = new RemoteLockscreenValidationSessionStorage();
when(mMockContext.getSystemService(anyString())).thenReturn(mKeyguardManager);
when(mMockContext.getSystemServiceName(any())).thenReturn("test");
@@ -198,7 +206,8 @@ public class RecoverableKeyStoreManagerTest {
mPlatformKeyManager,
mApplicationKeyStorage,
mTestOnlyInsecureCertificateHelper,
mCleanupManager);
mCleanupManager,
mRemoteLockscreenValidationSessionStorage);
}
@After
@@ -1269,6 +1278,85 @@ public class RecoverableKeyStoreManagerTest {
verify(mExecutorService).schedule(any(Runnable.class), anyLong(), any());
}
@Test
public void startRemoteLockscreenValidation_credentialsNotSet() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_NONE);
try {
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
fail("should have thrown");
} catch (IllegalStateException e) {
assertThat(e.getMessage()).contains("not set");
}
verify(mLockSettingsService).getCredentialType(mUserId);
mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
}
@Test
public void startRemoteLockscreenValidation_checksPermission() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_PIN);
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
// TODO(b/254335492): Check new system permission
verify(mMockContext, times(1))
.enforceCallingOrSelfPermission(
eq(Manifest.permission.RECOVER_KEYSTORE), any());
mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
}
@Test
public void startRemoteLockscreenValidation_returnsCredentailsType() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_PIN);
StartLockscreenValidationRequest request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
int credetialsType = request.getLockscreenUiType();
assertThat(credetialsType).isEqualTo(KeyguardManager.PIN);
verify(mLockSettingsService).getCredentialType(anyInt());
mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
}
@Test
public void startRemoteLockscreenValidation_returnsRemainingAttempts() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_PATTERN);
mRecoverableKeyStoreDb.setBadRemoteGuessCounter(mUserId, 3);
StartLockscreenValidationRequest request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
int credetialsType = request.getLockscreenUiType();
assertThat(credetialsType).isEqualTo(KeyguardManager.PATTERN);
// TODO(b/254335492): Verify returned value
mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
}
@Test
public void startRemoteLockscreenValidation_password() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD);
mRecoverableKeyStoreDb.setBadRemoteGuessCounter(mUserId, 3);
StartLockscreenValidationRequest request =
mRecoverableKeyStoreManager.startRemoteLockscreenValidation(mLockSettingsService);
int credetialsType = request.getLockscreenUiType();
assertThat(credetialsType).isEqualTo(KeyguardManager.PASSWORD);
mRemoteLockscreenValidationSessionStorage.finishSession(mUserId);
}
@Test
public void validateRemoteLockscreen_noActiveSession() throws Exception {
when(mLockSettingsService.getCredentialType(anyInt())).thenReturn(
LockPatternUtils.CREDENTIAL_TYPE_NONE);
byte[] invalidGuess = new byte[]{1, 2, 3};
try {
mRecoverableKeyStoreManager.validateRemoteLockscreen(invalidGuess,
mLockSettingsService);
fail("should have thrown");
} catch (IllegalStateException e) {
assertThat(e.getMessage()).contains("session");
}
}
private static byte[] encryptedApplicationKey(
SecretKey recoveryKey, byte[] applicationKey) throws Exception {
return KeySyncUtils.encryptKeysWithRecoveryKey(recoveryKey, ImmutableMap.of(