Integrating keystore with keyguard (Part 4 of 4)
Summary: frameworks/base keystore rewrite keyguard integration with keystore on keyguard entry or keyguard change KeyStore API simplification packages/apps/Settings Removed com.android.credentials.SET_PASSWORD intent support Added keyguard requirement for keystore use packages/apps/CertInstaller Tracking KeyStore API changes Fix for NPE in CertInstaller when certificate lacks basic constraints packages/apps/KeyChain Tracking KeyStore API changes Details: frameworks/base Move keystore from C to C++ while rewriting password implementation. Removed global variables. Added many comments. cmds/keystore/Android.mk cmds/keystore/keystore.h cmds/keystore/keystore.c => cmds/keystore/keystore.cpp cmds/keystore/keystore_cli.c => cmds/keystore/keystore_cli.cpp Changed saveLockPattern and saveLockPassword to notify the keystore on changes so that the keystore master key can be reencrypted when the keyguard changes. core/java/com/android/internal/widget/LockPatternUtils.java Changed unlock screens to pass values for keystore unlock or initialization policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java KeyStore API changes - renamed test() to state(), which now return a State enum - made APIs with byte[] key arguments private - added new KeyStore.isEmpty used to determine if a keyguard is required keystore/java/android/security/KeyStore.java In addition to tracking KeyStore API changes, added new testIsEmpty and improved some existing tests to validate expect values. keystore/tests/src/android/security/KeyStoreTest.java packages/apps/Settings Removing com.android.credentials.SET_PASSWORD intent with the removal of the ability to set an explicit keystore password now that the keyguard value is used. Changed to ensure keyguard is enabled for keystore install or unlock. Cleaned up interwoven dialog handing into discrete dialog helper classes. AndroidManifest.xml src/com/android/settings/CredentialStorage.java Remove layout for entering new password res/layout/credentials_dialog.xml Remove enable credentials checkbox res/xml/security_settings_misc.xml src/com/android/settings/SecuritySettings.java Added ability to specify minimum quality key to ChooseLockGeneric Activity. Used by CredentialStorage, but could also be used by CryptKeeperSettings. Changed ChooseLockGeneric to understand minimum quality for keystore in addition to DPM and device encryption. src/com/android/settings/ChooseLockGeneric.java Changed to use getActivePasswordQuality from getKeyguardStoredPasswordQuality based on experience in CredentialStorage. Removed bogus class javadoc. src/com/android/settings/CryptKeeperSettings.java Tracking KeyStore API changes src/com/android/settings/vpn/VpnSettings.java src/com/android/settings/wifi/WifiSettings.java Removing now unused string resources res/values-af/strings.xml res/values-am/strings.xml res/values-ar/strings.xml res/values-bg/strings.xml res/values-ca/strings.xml res/values-cs/strings.xml res/values-da/strings.xml res/values-de/strings.xml res/values-el/strings.xml res/values-en-rGB/strings.xml res/values-es-rUS/strings.xml res/values-es/strings.xml res/values-fa/strings.xml res/values-fi/strings.xml res/values-fr/strings.xml res/values-hr/strings.xml res/values-hu/strings.xml res/values-in/strings.xml res/values-it/strings.xml res/values-iw/strings.xml res/values-ja/strings.xml res/values-ko/strings.xml res/values-lt/strings.xml res/values-lv/strings.xml res/values-ms/strings.xml res/values-nb/strings.xml res/values-nl/strings.xml res/values-pl/strings.xml res/values-pt-rPT/strings.xml res/values-pt/strings.xml res/values-rm/strings.xml res/values-ro/strings.xml res/values-ru/strings.xml res/values-sk/strings.xml res/values-sl/strings.xml res/values-sr/strings.xml res/values-sv/strings.xml res/values-sw/strings.xml res/values-th/strings.xml res/values-tl/strings.xml res/values-tr/strings.xml res/values-uk/strings.xml res/values-vi/strings.xml res/values-zh-rCN/strings.xml res/values-zh-rTW/strings.xml res/values-zu/strings.xml res/values/strings.xml packages/apps/CertInstaller Tracking KeyStore API changes src/com/android/certinstaller/CertInstaller.java Fix for NPE in CertInstaller when certificate lacks basic constraints src/com/android/certinstaller/CredentialHelper.java packages/apps/KeyChain Tracking KeyStore API changes src/com/android/keychain/KeyChainActivity.java src/com/android/keychain/KeyChainService.java support/src/com/android/keychain/tests/support/IKeyChainServiceTestSupport.aidl support/src/com/android/keychain/tests/support/KeyChainServiceTestSupport.java tests/src/com/android/keychain/tests/KeyChainServiceTest.java Change-Id: I80533bf8986a92b0b99cd5fb1c4943e0f23fc1c8
This commit is contained in:
@@ -27,6 +27,7 @@ import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.security.KeyStore;
|
||||
|
||||
public class ChooseLockGeneric extends PreferenceActivity {
|
||||
|
||||
@@ -48,9 +49,11 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
private static final int CONFIRM_EXISTING_REQUEST = 100;
|
||||
private static final String PASSWORD_CONFIRMED = "password_confirmed";
|
||||
private static final String CONFIRM_CREDENTIALS = "confirm_credentials";
|
||||
public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
|
||||
|
||||
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
|
||||
private DevicePolicyManager mDPM;
|
||||
private KeyStore mKeyStore;
|
||||
private boolean mPasswordConfirmed = false;
|
||||
|
||||
@Override
|
||||
@@ -58,6 +61,7 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mKeyStore = KeyStore.getInstance();
|
||||
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
@@ -126,8 +130,8 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
|
||||
if (quality == -1) {
|
||||
// If caller didn't specify password quality, show UI and allow the user to choose.
|
||||
quality = mDPM.getPasswordQuality(null);
|
||||
quality = upgradeQualityForEncryption(quality);
|
||||
quality = getActivity().getIntent().getIntExtra(MINIMUM_QUALITY_KEY, -1);
|
||||
quality = upgradeQuality(quality);
|
||||
final PreferenceScreen prefScreen = getPreferenceScreen();
|
||||
if (prefScreen != null) {
|
||||
prefScreen.removeAll();
|
||||
@@ -135,11 +139,26 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
addPreferencesFromResource(R.xml.security_settings_picker);
|
||||
disableUnusablePreferences(quality);
|
||||
} else {
|
||||
quality = upgradeQualityForEncryption(quality);
|
||||
updateUnlockMethodAndFinish(quality, false);
|
||||
}
|
||||
}
|
||||
|
||||
private int upgradeQuality(int quality) {
|
||||
quality = upgradeQualityForDPM(quality);
|
||||
quality = upgradeQualityForEncryption(quality);
|
||||
quality = upgradeQualityForKeyStore(quality);
|
||||
return quality;
|
||||
}
|
||||
|
||||
private int upgradeQualityForDPM(int quality) {
|
||||
// Compare min allowed password quality
|
||||
int minQuality = mDPM.getPasswordQuality(null);
|
||||
if (quality < minQuality) {
|
||||
quality = minQuality;
|
||||
}
|
||||
return quality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix in "encryption minimums" to any given quality value. This prevents users
|
||||
* from downgrading the pattern/pin/password to a level below the minimums.
|
||||
@@ -152,8 +171,17 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
boolean encrypted = (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE)
|
||||
|| (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING);
|
||||
if (encrypted) {
|
||||
if (quality < DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
|
||||
quality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
if (quality < CryptKeeperSettings.MIN_PASSWORD_QUALITY) {
|
||||
quality = CryptKeeperSettings.MIN_PASSWORD_QUALITY;
|
||||
}
|
||||
}
|
||||
return quality;
|
||||
}
|
||||
|
||||
private int upgradeQualityForKeyStore(int quality) {
|
||||
if (!mKeyStore.isEmpty()) {
|
||||
if (quality < CredentialStorage.MIN_PASSWORD_QUALITY) {
|
||||
quality = CredentialStorage.MIN_PASSWORD_QUALITY;
|
||||
}
|
||||
}
|
||||
return quality;
|
||||
@@ -208,13 +236,7 @@ public class ChooseLockGeneric extends PreferenceActivity {
|
||||
throw new IllegalStateException("Tried to update password without confirming it");
|
||||
}
|
||||
|
||||
// Compare min allowed password quality and launch appropriate security setting method
|
||||
int minQuality = mDPM.getPasswordQuality(null);
|
||||
if (quality < minQuality) {
|
||||
quality = minQuality;
|
||||
}
|
||||
quality = upgradeQualityForEncryption(quality);
|
||||
|
||||
quality = upgradeQuality(quality);
|
||||
if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
|
||||
int minLength = mDPM.getPasswordMinimumLength(null);
|
||||
if (minLength < MIN_PASSWORD_LENGTH) {
|
||||
|
@@ -18,18 +18,14 @@ package com.android.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyChain.KeyChainConnection;
|
||||
import android.security.IKeyChainService;
|
||||
import android.security.KeyChain;
|
||||
import android.security.KeyStore;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
@@ -38,208 +34,105 @@ import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public class CredentialStorage extends Activity implements TextWatcher,
|
||||
DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
|
||||
|
||||
public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
|
||||
public static final String ACTION_SET_PASSWORD = "com.android.credentials.SET_PASSWORD";
|
||||
public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
|
||||
public static final String ACTION_RESET = "com.android.credentials.RESET";
|
||||
public class CredentialStorage extends Activity {
|
||||
|
||||
private static final String TAG = "CredentialStorage";
|
||||
|
||||
private KeyStore mKeyStore = KeyStore.getInstance();
|
||||
private boolean mPositive = false;
|
||||
private boolean mNeutral = false;
|
||||
public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
|
||||
public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
|
||||
public static final String ACTION_RESET = "com.android.credentials.RESET";
|
||||
|
||||
// This is the minimum acceptable password quality. If the current password quality is
|
||||
// lower than this, keystore should not be activated.
|
||||
static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
|
||||
|
||||
private final KeyStore mKeyStore = KeyStore.getInstance();
|
||||
private Bundle mBundle;
|
||||
|
||||
private TextView mOldPassword;
|
||||
private TextView mNewPassword;
|
||||
private TextView mConfirmPassword;
|
||||
private TextView mError;
|
||||
private Button mButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getAction();
|
||||
int state = mKeyStore.test();
|
||||
|
||||
if (ACTION_RESET.equals(action)) {
|
||||
showResetDialog();
|
||||
} else if (ACTION_SET_PASSWORD.equals(action)) {
|
||||
showPasswordDialog(state == KeyStore.UNINITIALIZED);
|
||||
new ResetDialog();
|
||||
} else {
|
||||
if (!checkKeyguardQuality()) {
|
||||
new ConfigureLockScreenDialog();
|
||||
return;
|
||||
}
|
||||
if (ACTION_INSTALL.equals(action) &&
|
||||
"com.android.certinstaller".equals(getCallingPackage())) {
|
||||
mBundle = intent.getExtras();
|
||||
}
|
||||
if (state == KeyStore.UNINITIALIZED) {
|
||||
showPasswordDialog(true);
|
||||
} else if (state == KeyStore.LOCKED) {
|
||||
showUnlockDialog();
|
||||
} else {
|
||||
install();
|
||||
finish();
|
||||
// ACTION_UNLOCK also handled here
|
||||
switch (mKeyStore.state()) {
|
||||
case UNINITIALIZED:
|
||||
// if we had a keyguard set, we should be initialized
|
||||
throw new AssertionError();
|
||||
case LOCKED:
|
||||
// if we have a keyguard, why didn't we unlock?
|
||||
// possibly old style password, display prompt
|
||||
new UnlockDialog();
|
||||
break;
|
||||
case UNLOCKED:
|
||||
install();
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkKeyguardQuality() {
|
||||
int quality = new LockPatternUtils(this).getActivePasswordQuality();
|
||||
return (quality >= MIN_PASSWORD_QUALITY);
|
||||
}
|
||||
|
||||
private void install() {
|
||||
if (mBundle != null && !mBundle.isEmpty()) {
|
||||
try {
|
||||
for (String key : mBundle.keySet()) {
|
||||
byte[] value = mBundle.getByteArray(key);
|
||||
if (value != null && !mKeyStore.put(key.getBytes("UTF-8"), value)) {
|
||||
Log.e(TAG, "Failed to install " + key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
setResult(RESULT_OK);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Should never happen.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showResetDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setMessage(R.string.credentials_reset_hint)
|
||||
.setNeutralButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, this)
|
||||
.create();
|
||||
dialog.setOnDismissListener(this);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void showPasswordDialog(boolean firstTime) {
|
||||
View view = View.inflate(this, R.layout.credentials_dialog, null);
|
||||
|
||||
((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_password_hint);
|
||||
if (!firstTime) {
|
||||
view.findViewById(R.id.old_password_prompt).setVisibility(View.VISIBLE);
|
||||
mOldPassword = (TextView) view.findViewById(R.id.old_password);
|
||||
mOldPassword.setVisibility(View.VISIBLE);
|
||||
mOldPassword.addTextChangedListener(this);
|
||||
}
|
||||
view.findViewById(R.id.new_passwords).setVisibility(View.VISIBLE);
|
||||
mNewPassword = (TextView) view.findViewById(R.id.new_password);
|
||||
mNewPassword.addTextChangedListener(this);
|
||||
mConfirmPassword = (TextView) view.findViewById(R.id.confirm_password);
|
||||
mConfirmPassword.addTextChangedListener(this);
|
||||
mError = (TextView) view.findViewById(R.id.error);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setView(view)
|
||||
.setTitle(R.string.credentials_set_password)
|
||||
.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);
|
||||
}
|
||||
|
||||
private void showUnlockDialog() {
|
||||
View view = View.inflate(this, R.layout.credentials_dialog, null);
|
||||
|
||||
((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_unlock_hint);
|
||||
mOldPassword = (TextView) view.findViewById(R.id.old_password);
|
||||
mOldPassword.setVisibility(View.VISIBLE);
|
||||
mOldPassword.addTextChangedListener(this);
|
||||
mError = (TextView) view.findViewById(R.id.error);
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(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);
|
||||
}
|
||||
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if ((mOldPassword == null || mOldPassword.getText().length() > 0) &&
|
||||
(mNewPassword == null || mNewPassword.getText().length() >= 8) &&
|
||||
(mConfirmPassword == null || mConfirmPassword.getText().length() >= 8)) {
|
||||
mButton.setEnabled(true);
|
||||
} else {
|
||||
mButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
public void onTextChanged(CharSequence s,int start, int before, int count) {
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int button) {
|
||||
mPositive = (button == DialogInterface.BUTTON_POSITIVE);
|
||||
mNeutral = (button == DialogInterface.BUTTON_NEUTRAL);
|
||||
}
|
||||
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
if (mPositive) {
|
||||
mPositive = false;
|
||||
mError.setVisibility(View.VISIBLE);
|
||||
|
||||
if (mNewPassword == null) {
|
||||
mKeyStore.unlock(mOldPassword.getText().toString());
|
||||
} else {
|
||||
String newPassword = mNewPassword.getText().toString();
|
||||
String confirmPassword = mConfirmPassword.getText().toString();
|
||||
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
mError.setText(R.string.credentials_passwords_mismatch);
|
||||
((AlertDialog) dialog).show();
|
||||
for (String key : mBundle.keySet()) {
|
||||
byte[] value = mBundle.getByteArray(key);
|
||||
if (value != null && !mKeyStore.put(key, value)) {
|
||||
Log.e(TAG, "Failed to install " + key);
|
||||
return;
|
||||
} else if (mOldPassword == null) {
|
||||
mKeyStore.password(newPassword);
|
||||
} else {
|
||||
mKeyStore.password(mOldPassword.getText().toString(), newPassword);
|
||||
}
|
||||
}
|
||||
setResult(RESULT_OK);
|
||||
}
|
||||
}
|
||||
|
||||
int error = mKeyStore.getLastError();
|
||||
if (error == KeyStore.NO_ERROR) {
|
||||
Toast.makeText(this, R.string.credentials_enabled, Toast.LENGTH_SHORT).show();
|
||||
install();
|
||||
} else if (error == KeyStore.UNINITIALIZED) {
|
||||
Toast.makeText(this, R.string.credentials_erased, Toast.LENGTH_SHORT).show();
|
||||
} else if (error >= KeyStore.WRONG_PASSWORD) {
|
||||
int count = error - KeyStore.WRONG_PASSWORD + 1;
|
||||
if (count > 3) {
|
||||
mError.setText(R.string.credentials_wrong_password);
|
||||
} else if (count == 1) {
|
||||
mError.setText(R.string.credentials_reset_warning);
|
||||
} else {
|
||||
mError.setText(getString(R.string.credentials_reset_warning_plural, count));
|
||||
}
|
||||
((AlertDialog) dialog).show();
|
||||
private class ResetDialog
|
||||
implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener
|
||||
{
|
||||
private boolean mResetConfirmed;
|
||||
|
||||
private ResetDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setMessage(R.string.credentials_reset_hint)
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, this)
|
||||
.create();
|
||||
dialog.setOnDismissListener(this);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override public void onClick(DialogInterface dialog, int button) {
|
||||
mResetConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
|
||||
}
|
||||
|
||||
@Override public void onDismiss(DialogInterface dialog) {
|
||||
if (mResetConfirmed) {
|
||||
mResetConfirmed = false;
|
||||
new ResetKeyStoreAndKeyChain().execute();
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
if (mNeutral) {
|
||||
mNeutral = false;
|
||||
new ResetKeyStoreAndKeyChain().execute();
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private class ResetKeyStoreAndKeyChain extends AsyncTask<Void, Void, Boolean> {
|
||||
@@ -274,4 +167,114 @@ public class CredentialStorage extends Activity implements TextWatcher,
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private class ConfigureLockScreenDialog
|
||||
implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener
|
||||
{
|
||||
private boolean mConfigureConfirmed;
|
||||
|
||||
private ConfigureLockScreenDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
|
||||
.setTitle(android.R.string.dialog_alert_title)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setMessage(R.string.credentials_configure_lock_screen_hint)
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, this)
|
||||
.create();
|
||||
dialog.setOnDismissListener(this);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override public void onClick(DialogInterface dialog, int button) {
|
||||
mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
|
||||
}
|
||||
|
||||
@Override public void onDismiss(DialogInterface dialog) {
|
||||
if (mConfigureConfirmed) {
|
||||
mConfigureConfirmed = false;
|
||||
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
|
||||
intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
|
||||
MIN_PASSWORD_QUALITY);
|
||||
startActivity(intent);
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
View view = View.inflate(CredentialStorage.this, R.layout.credentials_dialog, null);
|
||||
|
||||
((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_unlock_hint);
|
||||
mOldPassword = (TextView) view.findViewById(R.id.old_password);
|
||||
mOldPassword.setVisibility(View.VISIBLE);
|
||||
mOldPassword.addTextChangedListener(this);
|
||||
mError = (TextView) view.findViewById(R.id.error);
|
||||
|
||||
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());
|
||||
int error = mKeyStore.getLastError();
|
||||
if (error == KeyStore.NO_ERROR) {
|
||||
Toast.makeText(CredentialStorage.this,
|
||||
R.string.credentials_enabled,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
install();
|
||||
} else if (error == KeyStore.UNINITIALIZED) {
|
||||
Toast.makeText(CredentialStorage.this,
|
||||
R.string.credentials_erased,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
} else if (error >= KeyStore.WRONG_PASSWORD) {
|
||||
int count = error - KeyStore.WRONG_PASSWORD + 1;
|
||||
if (count > 3) {
|
||||
mError.setText(R.string.credentials_wrong_password);
|
||||
} else if (count == 1) {
|
||||
mError.setText(R.string.credentials_reset_warning);
|
||||
} else {
|
||||
mError.setText(getString(R.string.credentials_reset_warning_plural, count));
|
||||
}
|
||||
((AlertDialog) dialog).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -37,16 +37,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
/**
|
||||
* Confirm and execute a reset of the device to a clean "just out of the box"
|
||||
* state. Multiple confirmations are required: first, a general "are you sure
|
||||
* you want to do this?" prompt, followed by a keyguard pattern trace if the user
|
||||
* has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
|
||||
* ON THE PHONE" prompt. If at any time the phone is allowed to go to sleep, is
|
||||
* locked, et cetera, then the confirmation sequence is abandoned.
|
||||
*
|
||||
* This is the initial screen.
|
||||
*/
|
||||
public class CryptKeeperSettings extends Fragment {
|
||||
private static final String TAG = "CryptKeeper";
|
||||
|
||||
@@ -54,7 +44,7 @@ public class CryptKeeperSettings extends Fragment {
|
||||
|
||||
// This is the minimum acceptable password quality. If the current password quality is
|
||||
// lower than this, encryption should not be activated.
|
||||
private static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
|
||||
|
||||
// Minimum battery charge level (in percent) to launch encryption. If the battery charge is
|
||||
// lower than this, encryption should not be activated.
|
||||
@@ -163,7 +153,7 @@ public class CryptKeeperSettings extends Fragment {
|
||||
*/
|
||||
private boolean runKeyguardConfirmation(int request) {
|
||||
// 1. Confirm that we have a sufficient PIN/Password to continue
|
||||
int quality = new LockPatternUtils(getActivity()).getKeyguardStoredPasswordQuality();
|
||||
int quality = new LockPatternUtils(getActivity()).getActivePasswordQuality();
|
||||
if (quality < MIN_PASSWORD_QUALITY) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -70,7 +70,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
// Misc Settings
|
||||
private static final String KEY_SIM_LOCK = "sim_lock";
|
||||
private static final String KEY_SHOW_PASSWORD = "show_password";
|
||||
private static final String KEY_ENABLE_CREDENTIALS = "enable_credentials";
|
||||
private static final String KEY_RESET_CREDENTIALS = "reset_credentials";
|
||||
|
||||
private static final String TAG = "SecuritySettings";
|
||||
@@ -98,7 +97,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
|
||||
private CheckBoxPreference mShowPassword;
|
||||
|
||||
private CheckBoxPreference mEnableCredentials;
|
||||
private Preference mResetCredentials;
|
||||
|
||||
@Override
|
||||
@@ -239,8 +237,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD);
|
||||
|
||||
// Credential storage
|
||||
mEnableCredentials = (CheckBoxPreference) root.findPreference(KEY_ENABLE_CREDENTIALS);
|
||||
mEnableCredentials.setOnPreferenceChangeListener(this);
|
||||
mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
|
||||
|
||||
return root;
|
||||
@@ -337,10 +333,8 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
|
||||
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
|
||||
|
||||
int state = KeyStore.getInstance().test();
|
||||
mEnableCredentials.setChecked(state == KeyStore.NO_ERROR);
|
||||
mEnableCredentials.setEnabled(state != KeyStore.UNINITIALIZED);
|
||||
mResetCredentials.setEnabled(state != KeyStore.UNINITIALIZED);
|
||||
KeyStore.State state = KeyStore.getInstance().state();
|
||||
mResetCredentials.setEnabled(state != KeyStore.State.UNINITIALIZED);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -430,13 +424,6 @@ public class SecuritySettings extends SettingsPreferenceFragment
|
||||
// activity will be restated and the new value re-read, so the checkbox will get its
|
||||
// new value then.
|
||||
return false;
|
||||
} else if (preference == mEnableCredentials) {
|
||||
if (value != null && (Boolean) value) {
|
||||
getActivity().startActivity(new Intent(CredentialStorage.ACTION_UNLOCK));
|
||||
return false;
|
||||
} else {
|
||||
KeyStore.getInstance().lock();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.nio.charset.Charsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -698,7 +699,7 @@ public class VpnSettings extends SettingsPreferenceFragment
|
||||
}
|
||||
|
||||
private boolean isKeyStoreUnlocked() {
|
||||
return mKeyStore.test() == KeyStore.NO_ERROR;
|
||||
return mKeyStore.state() == KeyStore.State.UNLOCKED;
|
||||
}
|
||||
|
||||
// Returns true if the profile needs to access keystore
|
||||
@@ -1034,7 +1035,7 @@ public class VpnSettings extends SettingsPreferenceFragment
|
||||
String presharedKey = pskProfile.getPresharedKey();
|
||||
String key = KEY_PREFIX_IPSEC_PSK + p.getId();
|
||||
if (!TextUtils.isEmpty(presharedKey) &&
|
||||
!mKeyStore.put(key, presharedKey)) {
|
||||
!mKeyStore.put(key, presharedKey.getBytes(Charsets.UTF_8))) {
|
||||
Log.e(TAG, "keystore write failed: key=" + key);
|
||||
}
|
||||
pskProfile.setPresharedKey(key);
|
||||
@@ -1046,7 +1047,7 @@ public class VpnSettings extends SettingsPreferenceFragment
|
||||
if (l2tpProfile.isSecretEnabled()) {
|
||||
String secret = l2tpProfile.getSecretString();
|
||||
if (!TextUtils.isEmpty(secret) &&
|
||||
!mKeyStore.put(key, secret)) {
|
||||
!mKeyStore.put(key, secret.getBytes(Charsets.UTF_8))) {
|
||||
Log.e(TAG, "keystore write failed: key=" + key);
|
||||
}
|
||||
l2tpProfile.setSecretString(key);
|
||||
|
@@ -245,7 +245,7 @@ public class WifiSettings extends SettingsPreferenceFragment
|
||||
|
||||
getActivity().registerReceiver(mReceiver, mFilter);
|
||||
if (mKeyStoreNetworkId != INVALID_NETWORK_ID &&
|
||||
KeyStore.getInstance().test() == KeyStore.NO_ERROR) {
|
||||
KeyStore.getInstance().state() == KeyStore.State.UNLOCKED) {
|
||||
mWifiManager.connectNetwork(mKeyStoreNetworkId);
|
||||
}
|
||||
mKeyStoreNetworkId = INVALID_NETWORK_ID;
|
||||
@@ -417,7 +417,7 @@ public class WifiSettings extends SettingsPreferenceFragment
|
||||
|
||||
private boolean requireKeyStore(WifiConfiguration config) {
|
||||
if (WifiConfigController.requireKeyStore(config) &&
|
||||
KeyStore.getInstance().test() != KeyStore.NO_ERROR) {
|
||||
KeyStore.getInstance().state() != KeyStore.State.UNLOCKED) {
|
||||
mKeyStoreNetworkId = config.networkId;
|
||||
Credentials.getInstance().unlock(getActivity());
|
||||
return true;
|
||||
|
Reference in New Issue
Block a user