191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh/* 291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * 491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * you may not use this file except in compliance with the License. 691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * You may obtain a copy of the License at 791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * 891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * 1091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * Unless required by applicable law or agreed to in writing, software 1191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 1291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * See the License for the specific language governing permissions and 1491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh * limitations under the License. 1591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh */ 1691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 1791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehpackage com.android.settings; 1891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 1991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.app.Activity; 2091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.app.AlertDialog; 21d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstromimport android.app.admin.DevicePolicyManager; 22565653cef1039ab4e34e505185f1c77d847357cdJulia Reynoldsimport android.content.Context; 2391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.content.DialogInterface; 2491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.content.Intent; 250e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstromimport android.content.res.Resources; 269815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstromimport android.os.AsyncTask; 2791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.os.Bundle; 289815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstromimport android.os.RemoteException; 296c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport android.os.Process; 30565653cef1039ab4e34e505185f1c77d847357cdJulia Reynoldsimport android.os.UserManager; 31b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Rootimport android.security.Credentials; 32435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstromimport android.security.KeyChain.KeyChainConnection; 33d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstromimport android.security.KeyChain; 3491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.security.KeyStore; 3591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.text.Editable; 360e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstromimport android.text.TextUtils; 3791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.text.TextWatcher; 3891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.util.Log; 3991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.view.View; 4091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.Button; 4191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.TextView; 4291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.Toast; 4391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 44565653cef1039ab4e34e505185f1c77d847357cdJulia Reynoldsimport com.android.internal.widget.LockPatternUtils; 456c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport com.android.org.bouncycastle.asn1.ASN1InputStream; 466c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 476c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 486c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport org.apache.harmony.security.utils.AlgNameMapper; 496c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 506c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport java.io.ByteArrayInputStream; 516c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport java.io.IOException; 526c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 530e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom/** 540e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * CredentialStorage handles KeyStore reset, unlock, and install. 550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 560e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * CredentialStorage has a pretty convoluted state machine to migrate 570e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * from the old style separate keystore password to a new key guard 580e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * based password, as well as to deal with setting up the key guard if 590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * necessary. 600e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 610e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNINITALIZED 620e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF 630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action: set up key guard 640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes: factory state 650e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNINITALIZED 670e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: ON 680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action: confirm key guard 690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes: user had key guard but no keystore and upgraded from pre-ICS 700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * OR user had key guard and pre-ICS keystore password which was then reset 710e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 720e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: LOCKED 730e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF/ON 740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action: old unlock dialog 750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes: assume old password, need to use it to unlock. 760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * if unlock, ensure key guard before install. 770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * if reset, treat as UNINITALIZED/OFF 780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNLOCKED 800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF 810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action: set up key guard 820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes: ensure key guard, then proceed 830e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNLOCKED 850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * keyguard: ON 860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action: normal unlock/install 870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes: this is the common case 880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrompublic final class CredentialStorage extends Activity { 9091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 91d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private static final String TAG = "CredentialStorage"; 9291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 9391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK"; 9491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh public static final String ACTION_INSTALL = "com.android.credentials.INSTALL"; 9591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh public static final String ACTION_RESET = "com.android.credentials.RESET"; 9691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 97d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom // This is the minimum acceptable password quality. If the current password quality is 98d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom // lower than this, keystore should not be activated. 99d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 10091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 1010e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private static final int CONFIRM_KEY_GUARD_REQUEST = 1; 1020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 103d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private final KeyStore mKeyStore = KeyStore.getInstance(); 1040e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 1050e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 1060e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * When non-null, the bundle containing credentials to install. 1070e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 1080e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private Bundle mInstallBundle; 1090e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 1100e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 1110e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * After unsuccessful KeyStore.unlock, the number of unlock 1120e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * attempts remaining before the KeyStore will reset itself. 1130e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 1140e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Reset to -1 on successful unlock or reset. 1150e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 1160e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private int mRetriesRemaining = -1; 11791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 118cf008c28b871d4167e5aa19191ca691fb988f8fdKenny Root @Override 119cf008c28b871d4167e5aa19191ca691fb988f8fdKenny Root protected void onResume() { 120d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom super.onResume(); 12191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 12291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh Intent intent = getIntent(); 12391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh String action = intent.getAction(); 124565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); 125565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { 126565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds if (ACTION_RESET.equals(action)) { 127565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds new ResetDialog(); 128565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds } else { 129565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds if (ACTION_INSTALL.equals(action) 130565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds && "com.android.certinstaller".equals(getCallingPackage())) { 131565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds mInstallBundle = intent.getExtras(); 132565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds } 133565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds // ACTION_UNLOCK also handled here in addition to ACTION_INSTALL 134565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds handleUnlockOrInstall(); 1350e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 136565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds } else { 137565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds finish(); 1380e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1390e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1400e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 1410e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 1420e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Based on the current state of the KeyStore and key guard, try to 1430e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * make progress on unlocking or installing to the keystore. 1440e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 1450e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private void handleUnlockOrInstall() { 1460e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // something already decided we are done, do not proceed 1470e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (isFinishing()) { 1480e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 1490e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1500e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom switch (mKeyStore.state()) { 1510e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom case UNINITIALIZED: { 1520e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom ensureKeyGuard(); 1530e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 15491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 1550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom case LOCKED: { 1560e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom new UnlockDialog(); 1570e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 15891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 1590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom case UNLOCKED: { 1600e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (!checkKeyGuardQuality()) { 1610e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom new ConfigureKeyGuardDialog(); 1620e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 1630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom installIfAvailable(); 1650e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom finish(); 1660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 1670e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 1710e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 1720e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Make sure the user enters the key guard to set or change the 1730e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * keystore password. This can be used in UNINITIALIZED to set the 1740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * keystore password or UNLOCKED to change the password (as is the 1750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * case after unlocking with an old-style password). 1760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 1770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private void ensureKeyGuard() { 1780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (!checkKeyGuardQuality()) { 1790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // key guard not setup, doing so will initialize keystore 1800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom new ConfigureKeyGuardDialog(); 1810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // will return to onResume after Activity 1820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 18391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 1840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // force key guard confirmation 1850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (confirmKeyGuard()) { 1860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // will return password value via onActivityResult 1870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 1880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 1890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom finish(); 19091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 19191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 1920e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 1930e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Returns true if the currently set key guard matches our minimum quality requirements. 1940e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 1950e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private boolean checkKeyGuardQuality() { 196d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom int quality = new LockPatternUtils(this).getActivePasswordQuality(); 197d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom return (quality >= MIN_PASSWORD_QUALITY); 198d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 199d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 2006c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde private boolean isHardwareBackedKey(byte[] keyData) { 2016c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde try { 2026c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData)); 2036c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); 2046c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde String algId = pki.getAlgorithmId().getAlgorithm().getId(); 2056c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde String algName = AlgNameMapper.map2AlgName(algId); 2066c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 2076c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde return KeyChain.isBoundKeyAlgorithm(algName); 2086c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde } catch (IOException e) { 2096c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde Log.e(TAG, "Failed to parse key data"); 2106c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde return false; 2116c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde } 2126c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde } 2136c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 2140e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 2150e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Install credentials if available, otherwise do nothing. 2160e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 2170e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private void installIfAvailable() { 2180e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (mInstallBundle != null && !mInstallBundle.isEmpty()) { 2190e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom Bundle bundle = mInstallBundle; 2200e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom mInstallBundle = null; 221b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 2227422474c72b05517287fb0c226d1170cb11a064dKenny Root final int uid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, -1); 2237422474c72b05517287fb0c226d1170cb11a064dKenny Root 224b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) { 225b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME); 226b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA); 227b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 2286c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde int flags = KeyStore.FLAG_ENCRYPTED; 2296c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) { 2306c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde // Hardware backed keystore is secure enough to allow for WIFI stack 2316c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde // to enable access to secure networks without user intervention 2326c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID"); 2336c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde flags = KeyStore.FLAG_NONE; 2346c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde } 2356c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 2366c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde if (!mKeyStore.importKey(key, value, uid, flags)) { 2377422474c72b05517287fb0c226d1170cb11a064dKenny Root Log.e(TAG, "Failed to install " + key + " as user " + uid); 238d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom return; 23991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 24091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 241b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 2426c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde int flags = (uid == Process.WIFI_UID) ? KeyStore.FLAG_NONE : KeyStore.FLAG_ENCRYPTED; 2436c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde 244b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) { 245b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME); 246b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA); 247b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 2486c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde if (!mKeyStore.put(certName, certData, uid, flags)) { 2497422474c72b05517287fb0c226d1170cb11a064dKenny Root Log.e(TAG, "Failed to install " + certName + " as user " + uid); 250b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root return; 251b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root } 252b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root } 253b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 254b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) { 255b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME); 256b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA); 257b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 2586c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde if (!mKeyStore.put(caListName, caListData, uid, flags)) { 2597422474c72b05517287fb0c226d1170cb11a064dKenny Root Log.e(TAG, "Failed to install " + caListName + " as user " + uid); 260b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root return; 261b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root } 262b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root } 263b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root 264d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom setResult(RESULT_OK); 26591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 26691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 26791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 2680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 2690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Prompt for reset confirmation, resetting on confirmation, finishing otherwise. 2700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 271d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private class ResetDialog 272d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener 273d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom { 274d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private boolean mResetConfirmed; 275d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 276d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private ResetDialog() { 277d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) 278d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setTitle(android.R.string.dialog_alert_title) 279d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setMessage(R.string.credentials_reset_hint) 280d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setPositiveButton(android.R.string.ok, this) 281d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setNegativeButton(android.R.string.cancel, this) 282d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .create(); 283d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.setOnDismissListener(this); 284d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.show(); 28591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 28691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 287d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onClick(DialogInterface dialog, int button) { 288d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mResetConfirmed = (button == DialogInterface.BUTTON_POSITIVE); 28991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 29091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh 291d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onDismiss(DialogInterface dialog) { 292d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom if (mResetConfirmed) { 293d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mResetConfirmed = false; 294d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom new ResetKeyStoreAndKeyChain().execute(); 29591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh return; 29691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 297d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom finish(); 29891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 29991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh } 3009815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom 3010e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 3020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Background task to handle reset of both keystore and user installed CAs. 3030e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 3049815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom private class ResetKeyStoreAndKeyChain extends AsyncTask<Void, Void, Boolean> { 3059815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom 3069815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom @Override protected Boolean doInBackground(Void... unused) { 3079815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom 3089815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom mKeyStore.reset(); 3099815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom 3109815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom try { 311435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this); 312435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom try { 313435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom return keyChainConnection.getService().reset(); 314435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom } catch (RemoteException e) { 315435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom return false; 316435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom } finally { 317435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom keyChainConnection.close(); 318435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom } 3199815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } catch (InterruptedException e) { 3209815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom Thread.currentThread().interrupt(); 3219815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom return false; 3229815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } 3239815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } 3249815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom 3259815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom @Override protected void onPostExecute(Boolean success) { 3269815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom if (success) { 3279815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom Toast.makeText(CredentialStorage.this, 3289815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom R.string.credentials_erased, Toast.LENGTH_SHORT).show(); 3299815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } else { 3309815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom Toast.makeText(CredentialStorage.this, 3319815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom R.string.credentials_not_erased, Toast.LENGTH_SHORT).show(); 3329815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } 3339815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom finish(); 3349815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } 3359815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom } 336d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 3370e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 3380e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Prompt for key guard configuration confirmation. 3390e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 3400e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private class ConfigureKeyGuardDialog 341d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener 342d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom { 343d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private boolean mConfigureConfirmed; 344d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 3450e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private ConfigureKeyGuardDialog() { 346d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) 347d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setTitle(android.R.string.dialog_alert_title) 348d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setMessage(R.string.credentials_configure_lock_screen_hint) 349d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setPositiveButton(android.R.string.ok, this) 350d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setNegativeButton(android.R.string.cancel, this) 351d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .create(); 352d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.setOnDismissListener(this); 353d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.show(); 354d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 355d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 356d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onClick(DialogInterface dialog, int button) { 357d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE); 358d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 359d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 360d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onDismiss(DialogInterface dialog) { 361d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom if (mConfigureConfirmed) { 362d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mConfigureConfirmed = false; 363d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); 364d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, 365d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom MIN_PASSWORD_QUALITY); 366d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom startActivity(intent); 367d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom return; 368d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 369d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom finish(); 370d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 371d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 372d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 3730e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 3740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Confirm existing key guard, returning password via onActivityResult. 3750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 3760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom private boolean confirmKeyGuard() { 3770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom Resources res = getResources(); 3780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom boolean launched = new ChooseLockSettingsHelper(this) 3790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom .launchConfirmationActivity(CONFIRM_KEY_GUARD_REQUEST, 38081d7a806a6403cd98a0c6dd0ba7288d728382144Brian Carlstrom res.getText(R.string.credentials_install_gesture_prompt), 381204440427aa198a836d55418060759a1e964abccPaul Lawrence res.getText(R.string.credentials_install_gesture_explanation), 382204440427aa198a836d55418060759a1e964abccPaul Lawrence true); 3830e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return launched; 3840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 3850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 3860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom @Override 3870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom public void onActivityResult(int requestCode, int resultCode, Intent data) { 3880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom super.onActivityResult(requestCode, resultCode, data); 3890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 3900e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 3910e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Receive key guard password initiated by confirmKeyGuard. 3920e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 3930e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (requestCode == CONFIRM_KEY_GUARD_REQUEST) { 3940e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (resultCode == Activity.RESULT_OK) { 3950e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); 3960e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (!TextUtils.isEmpty(password)) { 3970e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // success 3980e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom mKeyStore.password(password); 3990e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // return to onResume 4000e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 4010e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 4020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 4030e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // failed confirmation, bail 4040e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom finish(); 4050e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 4060e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 4070e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 4080e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom /** 4090e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Prompt for unlock with old-style password. 4100e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * 4110e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * On successful unlock, ensure migration to key guard before continuing. 4120e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * On unsuccessful unlock, retry by calling handleUnlockOrInstall. 4130e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */ 414d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private class UnlockDialog implements TextWatcher, 415d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom DialogInterface.OnClickListener, DialogInterface.OnDismissListener 416d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom { 417d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private boolean mUnlockConfirmed; 418d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 419d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private final Button mButton; 420d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private final TextView mOldPassword; 421d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private final TextView mError; 422d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 423d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom private UnlockDialog() { 424d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom View view = View.inflate(CredentialStorage.this, R.layout.credentials_dialog, null); 425d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 4260e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom CharSequence text; 4270e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom if (mRetriesRemaining == -1) { 4280e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom text = getResources().getText(R.string.credentials_unlock_hint); 4290e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } else if (mRetriesRemaining > 3) { 4300e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom text = getResources().getText(R.string.credentials_wrong_password); 4310e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } else if (mRetriesRemaining == 1) { 4320e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom text = getResources().getText(R.string.credentials_reset_warning); 4330e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } else { 4340e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom text = getString(R.string.credentials_reset_warning_plural, mRetriesRemaining); 4350e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom } 4360e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom 4370e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom ((TextView) view.findViewById(R.id.hint)).setText(text); 438d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mOldPassword = (TextView) view.findViewById(R.id.old_password); 439d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mOldPassword.setVisibility(View.VISIBLE); 440d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mOldPassword.addTextChangedListener(this); 441d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mError = (TextView) view.findViewById(R.id.error); 442d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 443d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this) 444d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setView(view) 445d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setTitle(R.string.credentials_unlock) 446d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setPositiveButton(android.R.string.ok, this) 447d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .setNegativeButton(android.R.string.cancel, this) 448d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom .create(); 449d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.setOnDismissListener(this); 450d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom dialog.show(); 451d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); 452d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mButton.setEnabled(false); 453d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 454d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 455d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void afterTextChanged(Editable editable) { 456d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mButton.setEnabled(mOldPassword == null || mOldPassword.getText().length() > 0); 457d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 458d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 459d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { 460d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 461d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 462d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onTextChanged(CharSequence s,int start, int before, int count) { 463d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 464d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 465d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onClick(DialogInterface dialog, int button) { 466d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mUnlockConfirmed = (button == DialogInterface.BUTTON_POSITIVE); 467d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 468d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom 469d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom @Override public void onDismiss(DialogInterface dialog) { 470d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom if (mUnlockConfirmed) { 471d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mUnlockConfirmed = false; 472d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mError.setVisibility(View.VISIBLE); 473d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom mKeyStore.unlock(mOldPassword.getText().toString()); 474d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom int error = mKeyStore.getLastError(); 475d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom if (error == KeyStore.NO_ERROR) { 4760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom mRetriesRemaining = -1; 477d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom Toast.makeText(CredentialStorage.this, 478d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom R.string.credentials_enabled, 479d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom Toast.LENGTH_SHORT).show(); 4800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // aha, now we are unlocked, switch to key guard. 4810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // we'll end up back in onResume to install 4820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom ensureKeyGuard(); 483d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } else if (error == KeyStore.UNINITIALIZED) { 4840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom mRetriesRemaining = -1; 485d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom Toast.makeText(CredentialStorage.this, 486d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom R.string.credentials_erased, 487d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom Toast.LENGTH_SHORT).show(); 4880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // we are reset, we can now set new password with key guard 4890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom handleUnlockOrInstall(); 490d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } else if (error >= KeyStore.WRONG_PASSWORD) { 4910e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom // we need to try again 4920e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom mRetriesRemaining = error - KeyStore.WRONG_PASSWORD + 1; 4930e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom handleUnlockOrInstall(); 494d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 4950e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom return; 496d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 497d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom finish(); 498d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 499d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom } 50091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh} 501