From efdfbeaff41140e8628ae3a01a69c31eefbb099c Mon Sep 17 00:00:00 2001 From: Irina Dumitrescu Date: Thu, 10 May 2018 18:06:53 +0100 Subject: [PATCH] Credential storage triggers unlock when keystore is locked. If the phone is in the unlocked state and keystore is locked, storing credentials asks for a password that does not exist to the user. Replace this workflow with a key guard confirmation, asking the user to unlock the screen in the same way they would normally unlock their phone. Bug: 68298609 Test: adb push sample_credentials.p12 /sdcard/ Test: adb shell su 1000 service call android.security.keystore 9 i32 0 Test: adb shell am start -a android.credentials.INSTALL --user 10 Test: adb shell su 1000 service call android.security.keystore 9 i32 10 Change-Id: I8a3068a5d7de508fb417016acdf41b1712a2e7cc --- res/layout/credentials_dialog.xml | 53 ------- res/values/strings.xml | 15 -- .../android/settings/CredentialStorage.java | 144 ++---------------- 3 files changed, 12 insertions(+), 200 deletions(-) delete mode 100644 res/layout/credentials_dialog.xml diff --git a/res/layout/credentials_dialog.xml b/res/layout/credentials_dialog.xml deleted file mode 100644 index 9eacd5405c0..00000000000 --- a/res/layout/credentials_dialog.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 9e5db226670..9e333ab0961 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5613,27 +5613,12 @@ Installed for VPN and apps Installed for Wi-Fi - - - - - Type the password for credential storage. - - Current password: Remove all the contents? - - Incorrect password. - - Incorrect password. You have one more chance before credential storage is erased. - - Incorrect password. You have %1$d more chances before credential storage is erased. Credential storage is erased. Credential storage couldn\u2019t be erased. - - Credential storage is enabled. Before you can use credential storage, your device need to have a secure lock screen diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java index c037c9f0a2c..47027d78209 100644 --- a/src/com/android/settings/CredentialStorage.java +++ b/src/com/android/settings/CredentialStorage.java @@ -35,25 +35,17 @@ import android.security.Credentials; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; import android.security.KeyStore; -import android.text.Editable; import android.text.TextUtils; -import android.text.TextWatcher; import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; import android.widget.Toast; - import com.android.internal.widget.LockPatternUtils; import com.android.org.bouncycastle.asn1.ASN1InputStream; import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.security.ConfigureKeyGuardDialog; import com.android.settings.vpn2.VpnUtils; - import java.io.ByteArrayInputStream; import java.io.IOException; - import sun.security.util.ObjectIdentifier; import sun.security.x509.AlgorithmId; @@ -78,8 +70,8 @@ import sun.security.x509.AlgorithmId; * * KeyStore: LOCKED * KeyGuard: OFF/ON - * Action: old unlock dialog - * Notes: assume old password, need to use it to unlock. + * Action: confirm key guard + * Notes: request normal unlock to unlock the keystore. * if unlock, ensure key guard before install. * if reset, treat as UNINITALIZED/OFF * @@ -115,14 +107,6 @@ public final class CredentialStorage extends Activity { */ private Bundle mInstallBundle; - /** - * After unsuccessful KeyStore.unlock, the number of unlock - * attempts remaining before the KeyStore will reset itself. - * - * Reset to -1 on successful unlock or reset. - */ - private int mRetriesRemaining = -1; - @Override protected void onResume() { super.onResume(); @@ -166,11 +150,12 @@ public final class CredentialStorage extends Activity { return; } case LOCKED: { - new UnlockDialog(); + // Force key guard confirmation + confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST); return; } case UNLOCKED: { - if (!checkKeyGuardQuality()) { + if (isActivePasswordQualityInsufficient()) { final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog(); dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG); return; @@ -189,7 +174,7 @@ public final class CredentialStorage extends Activity { * case after unlocking with an old-style password). */ private void ensureKeyGuard() { - if (!checkKeyGuardQuality()) { + if (isActivePasswordQualityInsufficient()) { // key guard not setup, doing so will initialize keystore final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog(); dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG); @@ -205,9 +190,9 @@ public final class CredentialStorage extends Activity { } /** - * Returns true if the currently set key guard matches our minimum quality requirements. + * Returns true if the currently set key guard violates our minimum quality requirements. */ - private boolean checkKeyGuardQuality() { + private boolean isActivePasswordQualityInsufficient() { final int credentialOwner = UserManager.get(this).getCredentialOwnerProfile(UserHandle.myUserId()); final int quality = new LockPatternUtils(this).getActivePasswordQuality(credentialOwner); @@ -457,11 +442,8 @@ public final class CredentialStorage extends Activity { final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); final UserInfo parentInfo = userManager.getProfileParent(launchedFromUserId); - if (parentInfo == null || parentInfo.id != UserHandle.myUserId()) { - // Caller is not running in a profile of this user - return false; - } - return true; + // Caller is running in a profile of this user + return ((parentInfo != null) && (parentInfo.id == UserHandle.myUserId())); } /** @@ -469,19 +451,15 @@ public final class CredentialStorage extends Activity { */ private boolean confirmKeyGuard(int requestCode) { final Resources res = getResources(); - boolean launched = new ChooseLockSettingsHelper(this) + return new ChooseLockSettingsHelper(this) .launchConfirmationActivity(requestCode, res.getText(R.string.credentials_title), true); - return launched; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - - /** - * Receive key guard password initiated by confirmKeyGuard. - */ + // Receive key guard password initiated by confirmKeyGuard. if (requestCode == CONFIRM_KEY_GUARD_REQUEST) { if (resultCode == Activity.RESULT_OK) { final String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); @@ -503,102 +481,4 @@ public final class CredentialStorage extends Activity { finish(); } } - - /** - * Prompt for unlock with old-style password. - * - * On successful unlock, ensure migration to key guard before continuing. - * On unsuccessful unlock, retry by calling handleUnlockOrInstall. - */ - private class UnlockDialog implements TextWatcher, - DialogInterface.OnClickListener, DialogInterface.OnDismissListener { - private boolean mUnlockConfirmed; - - private final Button mButton; - private final TextView mOldPassword; - private final TextView mError; - - private UnlockDialog() { - final View view = View.inflate( - CredentialStorage.this, R.layout.credentials_dialog, null); - - final CharSequence text; - if (mRetriesRemaining == -1) { - text = getResources().getText(R.string.credentials_unlock_hint); - } else if (mRetriesRemaining > 3) { - text = getResources().getText(R.string.credentials_wrong_password); - } else if (mRetriesRemaining == 1) { - text = getResources().getText(R.string.credentials_reset_warning); - } else { - text = getString(R.string.credentials_reset_warning_plural, mRetriesRemaining); - } - - ((TextView) view.findViewById(R.id.hint)).setText(text); - mOldPassword = (TextView) view.findViewById(R.id.old_password); - mOldPassword.setVisibility(View.VISIBLE); - mOldPassword.addTextChangedListener(this); - mError = (TextView) view.findViewById(R.id.error); - - final AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) - .setView(view) - .setTitle(R.string.credentials_unlock) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, this) - .create(); - dialog.setOnDismissListener(this); - dialog.show(); - mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); - mButton.setEnabled(false); - } - - @Override - public void afterTextChanged(Editable editable) { - mButton.setEnabled(mOldPassword == null || mOldPassword.getText().length() > 0); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - } - - @Override - public void onClick(DialogInterface dialog, int button) { - mUnlockConfirmed = (button == DialogInterface.BUTTON_POSITIVE); - } - - @Override - public void onDismiss(DialogInterface dialog) { - if (mUnlockConfirmed) { - mUnlockConfirmed = false; - mError.setVisibility(View.VISIBLE); - mKeyStore.unlock(mOldPassword.getText().toString()); - final int error = mKeyStore.getLastError(); - if (error == KeyStore.NO_ERROR) { - mRetriesRemaining = -1; - Toast.makeText(CredentialStorage.this, - R.string.credentials_enabled, - Toast.LENGTH_SHORT).show(); - // aha, now we are unlocked, switch to key guard. - // we'll end up back in onResume to install - ensureKeyGuard(); - } else if (error == KeyStore.UNINITIALIZED) { - mRetriesRemaining = -1; - Toast.makeText(CredentialStorage.this, - R.string.credentials_erased, - Toast.LENGTH_SHORT).show(); - // we are reset, we can now set new password with key guard - handleUnlockOrInstall(); - } else if (error >= KeyStore.WRONG_PASSWORD) { - // we need to try again - mRetriesRemaining = error - KeyStore.WRONG_PASSWORD + 1; - handleUnlockOrInstall(); - } - return; - } - finish(); - } - } }