Merge "Integrating keystore with keyguard (Part 4 of 4)"

This commit is contained in:
Brian Carlstrom
2011-06-01 14:33:40 -07:00
committed by Android (Google) Code Review
56 changed files with 234 additions and 657 deletions

View File

@@ -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) {

View File

@@ -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();
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;