2/n: Add setRequestGatekeeperPassword to ChooseLockSettingsHelper

This change adds the plumbing on Settings side for ConfirmLock*.
ChooseLock* will be done in a follow-up CL. The changes in this CL
are not invoked by any code path yet. This will also be integrated
in a follow-up CL.

Bug: 161765592

Perform the following with a local change to use
ChooseLockSettingsHelper#setRequestGatekeeperPassword(true)

Test: GK PW is received when setRequestGatekeeperPassword(true)
Test: GK PW + Challenge sent to GK, GK verifies and caller receives
      GK HAT successfully

Change-Id: Ibd809784b5599343f34836bc5f3e709627b7f22a
This commit is contained in:
Kevin Chyn
2020-07-22 15:17:11 -07:00
parent c8b21a36e2
commit fbc2ec831f
6 changed files with 126 additions and 69 deletions

View File

@@ -77,6 +77,7 @@ import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.EncryptionInterstitial;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -967,19 +968,24 @@ public class ChooseLockPassword extends SettingsActivity {
}
Intent result = null;
if (success && mHasChallenge) {
byte[] token;
VerifyCredentialResponse response;
try {
token = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId);
response = mUtils.verifyCredential(mChosenPassword, mChallenge, mUserId,
0 /* flags */);
} catch (RequestThrottledException e) {
token = null;
response = null;
}
if (token == null) {
Log.e(TAG, "critical: no token returned for known good password.");
if (response == null) {
Log.e(TAG, "critical: null response for known good password");
} else if (!response.isMatched() || response.getGatekeeperHAT() == null) {
Log.e(TAG, "critical: bad response or missing GK HAT for known good password: "
+ response.toString());
}
result = new Intent();
result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
response.getGatekeeperHAT());
}
return Pair.create(success, result);
}

View File

@@ -47,6 +47,7 @@ import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockPatternView.DisplayMode;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.EncryptionInterstitial;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -913,19 +914,24 @@ public class ChooseLockPattern extends SettingsActivity {
}
Intent result = null;
if (success && mHasChallenge) {
byte[] token;
VerifyCredentialResponse response;
try {
token = mUtils.verifyCredential(mChosenPattern, mChallenge, userId);
response = mUtils.verifyCredential(mChosenPattern, mChallenge, userId,
0 /* flags */);
} catch (RequestThrottledException e) {
token = null;
response = null;
}
if (token == null) {
Log.e(TAG, "critical: no token returned for known good pattern");
if (response == null) {
Log.e(TAG, "critial: null response for known good pattern");
} else if (!response.isMatched() || response.getGatekeeperHAT() == null) {
Log.e(TAG, "critical: bad response or missing GK HAT for known good pattern: "
+ response.toString());
}
result = new Intent();
result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
result.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
response.getGatekeeperHAT());
}
return Pair.create(success, result);
}

View File

@@ -47,11 +47,16 @@ public final class ChooseLockSettingsHelper {
public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials";
public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge";
public static final String EXTRA_KEY_CHALLENGE = "challenge";
// Gatekeeper HardwareAuthToken
public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
public static final String EXTRA_KEY_FOR_FACE = "for_face";
public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only";
public static final String EXTRA_KEY_REQUEST_GK_PW = "request_gk_pw";
// Gatekeeper password, which can subsequently be used to generate Gatekeeper
// HardwareAuthToken(s) via LockSettingsService#verifyGatekeeperPassword
public static final String EXTRA_KEY_GK_PW = "gk_pw";
/**
* When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are
@@ -119,6 +124,7 @@ public final class ChooseLockSettingsHelper {
private boolean mAllowAnyUserId;
// The challenge can be 0, which is different than "no challenge"
@Nullable Long mChallenge;
boolean mRequestGatekeeperPassword;
public Builder(@NonNull Activity activity) {
mActivity = activity;
@@ -174,7 +180,7 @@ public final class ChooseLockSettingsHelper {
* @param returnCredentials if true, puts the following credentials into intent for
* onActivityResult with the following keys:
* {@link #EXTRA_KEY_TYPE}, {@link #EXTRA_KEY_PASSWORD},
* {@link #EXTRA_KEY_CHALLENGE_TOKEN}.
* {@link #EXTRA_KEY_CHALLENGE_TOKEN}, {@link #EXTRA_KEY_GK_PW}
* Note that if this is true, this can only be called internally.
*/
@NonNull public Builder setReturnCredentials(boolean returnCredentials) {
@@ -231,6 +237,24 @@ public final class ChooseLockSettingsHelper {
return this;
}
/**
* Requests that LockSettingsService return the Gatekeeper Password (instead of the
* Gatekeeper HAT). This allows us to use a single entry of the user's credential
* to create multiple Gatekeeper HATs containing distinct challenges via
* {@link LockPatternUtils#verifyGatekeeperPassword(byte[], long, int)}.
*
* Upon confirmation of the user's password, the Gatekeeper Password will be returned via
* onActivityResult with the key being {@link #EXTRA_KEY_GK_PW}.
* @param requestGatekeeperPassword
*
* Note that invoking {@link #setChallenge(long)} will be treated as a no-op if Gatekeeper
* Password has been requested.
*/
@NonNull public Builder setRequestGatekeeperPassword(boolean requestGatekeeperPassword) {
mRequestGatekeeperPassword = requestGatekeeperPassword;
return this;
}
@NonNull public ChooseLockSettingsHelper build() {
if (!mAllowAnyUserId && mUserId != LockPatternUtils.USER_FRP) {
Utils.enforceSameOwner(mActivity, mUserId);
@@ -265,14 +289,15 @@ public final class ChooseLockSettingsHelper {
return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader,
mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal,
mBuilder.mChallenge != null, challenge, mBuilder.mUserId,
mBuilder.mAlternateButton, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly);
mBuilder.mAlternateButton, mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly,
mBuilder.mRequestGatekeeperPassword);
}
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
@Nullable CharSequence header, @Nullable CharSequence description,
boolean returnCredentials, boolean external, boolean hasChallenge,
long challenge, int userId, @Nullable CharSequence alternateButton,
boolean allowAnyUser, boolean foregroundOnly) {
boolean allowAnyUser, boolean foregroundOnly, boolean requestGatekeeperPassword) {
final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
boolean launched = false;
@@ -283,7 +308,7 @@ public final class ChooseLockSettingsHelper {
? ConfirmLockPattern.InternalActivity.class
: ConfirmLockPattern.class, returnCredentials, external,
hasChallenge, challenge, userId, alternateButton, allowAnyUser,
foregroundOnly);
foregroundOnly, requestGatekeeperPassword);
break;
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
@@ -296,7 +321,7 @@ public final class ChooseLockSettingsHelper {
? ConfirmLockPassword.InternalActivity.class
: ConfirmLockPassword.class, returnCredentials, external,
hasChallenge, challenge, userId, alternateButton, allowAnyUser,
foregroundOnly);
foregroundOnly, requestGatekeeperPassword);
break;
}
return launched;
@@ -306,7 +331,7 @@ public final class ChooseLockSettingsHelper {
CharSequence message, Class<?> activityClass, boolean returnCredentials,
boolean external, boolean hasChallenge, long challenge,
int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser,
boolean foregroundOnly) {
boolean foregroundOnly, boolean requestGatekeeperPassword) {
final Intent intent = new Intent();
intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
@@ -323,6 +348,8 @@ public final class ChooseLockSettingsHelper {
intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, allowAnyUser);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW,
requestGatekeeperPassword);
intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
if (external) {

View File

@@ -71,6 +71,8 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
protected static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 3000;
protected boolean mReturnCredentials = false;
protected boolean mReturnGatekeeperPassword = false;
protected boolean mVerifyChallenge = false;
protected Button mCancelButton;
/** Button allowing managed profile password reset, null when is not shown. */
@Nullable protected Button mForgotButton;
@@ -93,12 +95,18 @@ public abstract class ConfirmDeviceCredentialBaseFragment extends InstrumentedFr
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFrpAlternateButtonText = getActivity().getIntent().getCharSequenceExtra(
final Intent intent = getActivity().getIntent();
mFrpAlternateButtonText = intent.getCharSequenceExtra(
KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL);
mReturnCredentials = getActivity().getIntent().getBooleanExtra(
mReturnCredentials = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false);
mReturnGatekeeperPassword = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW, false);
mVerifyChallenge = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
// Only take this argument into account if it belongs to the current profile.
Intent intent = getActivity().getIntent();
mUserId = Utils.getUserIdFromBundle(getActivity(), intent.getExtras(),
isInternalActivity());
mFrp = (mUserId == LockPatternUtils.USER_FRP);

View File

@@ -49,6 +49,7 @@ import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
@@ -380,13 +381,18 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
: LockscreenCredential.createPin(passwordText);
mPasswordEntryInputDisabler.setInputEnabled(false);
final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
Intent intent = new Intent();
if (verifyChallenge) {
// TODO(b/161956762): Sanitize this
if (mReturnGatekeeperPassword) {
if (isInternalActivity()) {
startVerifyPassword(credential, intent);
startVerifyPassword(credential, intent,
LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW);
return;
}
} else if (mVerifyChallenge) {
if (isInternalActivity()) {
startVerifyPassword(credential, intent, 0 /* flags */);
return;
}
} else {
@@ -401,34 +407,34 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
return getActivity() instanceof ConfirmLockPassword.InternalActivity;
}
private void startVerifyPassword(LockscreenCredential credential, final Intent intent) {
private void startVerifyPassword(LockscreenCredential credential, final Intent intent,
@LockPatternUtils.VerifyFlag int flags) {
long challenge = getActivity().getIntent().getLongExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
final int localEffectiveUserId = mEffectiveUserId;
final int localUserId = mUserId;
final LockPatternChecker.OnVerifyCallback onVerifyCallback =
new LockPatternChecker.OnVerifyCallback() {
@Override
public void onVerified(byte[] token, int timeoutMs) {
final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
mPendingLockCheck = null;
boolean matched = false;
if (token != null) {
matched = true;
if (mReturnCredentials) {
final boolean matched = response.isMatched();
if (matched && mReturnCredentials) {
if ((flags & LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW) != 0) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW,
response.getGatekeeperPw());
} else {
intent.putExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
token);
response.getGatekeeperHAT());
}
}
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
}
};
mPendingLockCheck = (localEffectiveUserId == localUserId)
? LockPatternChecker.verifyCredential(
mLockPatternUtils, credential, challenge, localUserId, onVerifyCallback)
mLockPatternUtils, credential, challenge, localUserId, flags,
onVerifyCallback)
: LockPatternChecker.verifyTiedProfileChallenge(
mLockPatternUtils, credential, challenge, localUserId,
mLockPatternUtils, credential, challenge, localUserId, flags,
onVerifyCallback);
}

View File

@@ -40,6 +40,7 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.settings.R;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
@@ -422,14 +423,18 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
mLockPatternView.setEnabled(false);
final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
final LockscreenCredential credential = LockscreenCredential.createPattern(pattern);
//TODO: how to sanitize this?
// TODO(b/161956762): Sanitize this
Intent intent = new Intent();
if (verifyChallenge) {
if (mReturnGatekeeperPassword) {
if (isInternalActivity()) {
startVerifyPattern(credential, intent);
startVerifyPattern(credential, intent,
LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW);
return;
}
} else if (mVerifyChallenge) {
if (isInternalActivity()) {
startVerifyPattern(credential, intent, 0 /* flags */);
return;
}
} else {
@@ -445,36 +450,35 @@ public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
}
private void startVerifyPattern(final LockscreenCredential pattern,
final Intent intent) {
final Intent intent, @LockPatternUtils.VerifyFlag int flags) {
final int localEffectiveUserId = mEffectiveUserId;
final int localUserId = mUserId;
long challenge = getActivity().getIntent().getLongExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
final LockPatternChecker.OnVerifyCallback onVerifyCallback =
new LockPatternChecker.OnVerifyCallback() {
@Override
public void onVerified(byte[] token, int timeoutMs) {
(response, timeoutMs) -> {
mPendingLockCheck = null;
boolean matched = false;
if (token != null) {
matched = true;
if (mReturnCredentials) {
final boolean matched = response.isMatched();
if (matched && mReturnCredentials) {
if ((flags & LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW) != 0) {
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW,
response.getGatekeeperPw());
} else {
intent.putExtra(
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
token);
response.getGatekeeperHAT());
}
}
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
}
};
mPendingLockCheck = (localEffectiveUserId == localUserId)
? LockPatternChecker.verifyCredential(
mLockPatternUtils, pattern, challenge, localUserId,
mLockPatternUtils, pattern, challenge, localUserId, flags,
onVerifyCallback)
: LockPatternChecker.verifyTiedProfileChallenge(
mLockPatternUtils, pattern,
challenge, localUserId, onVerifyCallback);
mLockPatternUtils, pattern, challenge, localUserId, flags,
onVerifyCallback);
}
private void startCheckPattern(final LockscreenCredential pattern,