Merge "Implement startRemoteLockscreenValidation."
This commit is contained in:
committed by
Android (Google) Code Review
commit
ba2afc5b57
20
core/java/android/app/RemoteLockscreenValidationResult.aidl
Normal file
20
core/java/android/app/RemoteLockscreenValidationResult.aidl
Normal 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;
|
||||
150
core/java/android/app/RemoteLockscreenValidationResult.java
Normal file
150
core/java/android/app/RemoteLockscreenValidationResult.java
Normal 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;
|
||||
}
|
||||
}
|
||||
20
core/java/android/app/StartLockscreenValidationRequest.aidl
Normal file
20
core/java/android/app/StartLockscreenValidationRequest.aidl
Normal 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;
|
||||
146
core/java/android/app/StartLockscreenValidationRequest.java
Normal file
146
core/java/android/app/StartLockscreenValidationRequest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user