diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index a2ac3d5d130..bcf82125d4d 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -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); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 2c2d7bbe11a..8a51d5a7ae2 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -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); } diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 962294b100c..04046553651 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -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) { diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java index b5f512dfa99..23320902059 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseFragment.java @@ -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); diff --git a/src/com/android/settings/password/ConfirmLockPassword.java b/src/com/android/settings/password/ConfirmLockPassword.java index 8aa44e9780f..85f44fd5c69 100644 --- a/src/com/android/settings/password/ConfirmLockPassword.java +++ b/src/com/android/settings/password/ConfirmLockPassword.java @@ -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) { - mPendingLockCheck = null; - boolean matched = false; - if (token != null) { - matched = true; - if (mReturnCredentials) { - intent.putExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - token); - } - } - mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, - localEffectiveUserId); - } + final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> { + mPendingLockCheck = null; + 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, + 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); } diff --git a/src/com/android/settings/password/ConfirmLockPattern.java b/src/com/android/settings/password/ConfirmLockPattern.java index 48014cba3c8..5b11bfedc0d 100644 --- a/src/com/android/settings/password/ConfirmLockPattern.java +++ b/src/com/android/settings/password/ConfirmLockPattern.java @@ -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) { - mPendingLockCheck = null; - boolean matched = false; - if (token != null) { - matched = true; - if (mReturnCredentials) { - intent.putExtra( - ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, - token); - } + (response, timeoutMs) -> { + mPendingLockCheck = null; + 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, + response.getGatekeeperHAT()); } - mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs, - localEffectiveUserId); } - }; + 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,