blob: e5d40b7add0ef96cdff969cdf7145d19b786697f [file] [log] [blame]
Chia-chi Yeh91d65a22011-01-20 18:46:01 +08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings;
18
19import android.app.Activity;
20import android.app.AlertDialog;
Brian Carlstromd4023b72011-05-25 13:24:20 -070021import android.app.admin.DevicePolicyManager;
Julia Reynolds565653c2014-06-12 11:49:12 -040022import android.content.Context;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +080023import android.content.DialogInterface;
24import android.content.Intent;
Zoltan Szatmary-Ban307e3d02015-07-09 17:30:20 +010025import android.content.pm.PackageManager;
Robin Lee8823c3e2014-11-06 20:57:11 +000026import android.content.pm.UserInfo;
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -070027import android.content.res.Resources;
Brian Carlstrom98154292011-05-12 23:58:39 -070028import android.os.AsyncTask;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +080029import android.os.Bundle;
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -070030import android.os.Process;
Jason Monk39b46742015-09-10 15:52:51 -040031import android.os.RemoteException;
Robin Lee8823c3e2014-11-06 20:57:11 +000032import android.os.UserHandle;
Julia Reynolds565653c2014-06-12 11:49:12 -040033import android.os.UserManager;
Kenny Rootb50b15c2012-03-21 14:57:29 -070034import android.security.Credentials;
Brian Carlstromd4023b72011-05-25 13:24:20 -070035import android.security.KeyChain;
Jason Monk39b46742015-09-10 15:52:51 -040036import android.security.KeyChain.KeyChainConnection;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +080037import android.security.KeyStore;
38import android.text.Editable;
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -070039import android.text.TextUtils;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +080040import android.text.TextWatcher;
41import android.util.Log;
42import android.view.View;
43import android.widget.Button;
44import android.widget.TextView;
45import android.widget.Toast;
46
Julia Reynolds565653c2014-06-12 11:49:12 -040047import com.android.internal.widget.LockPatternUtils;
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -070048import com.android.org.bouncycastle.asn1.ASN1InputStream;
49import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Maurice Lam2eb170c2017-04-28 16:18:47 -070050import com.android.settings.password.ChooseLockSettingsHelper;
Fan Zhangab0a0c82017-06-05 17:15:21 -070051import com.android.settings.security.ConfigureKeyGuardDialog;
insight.lee03159e42017-01-17 08:27:01 +090052import com.android.settings.vpn2.VpnUtils;
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -070053
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -070054import java.io.ByteArrayInputStream;
55import java.io.IOException;
56
Maurice Lam2eb170c2017-04-28 16:18:47 -070057import sun.security.util.ObjectIdentifier;
58import sun.security.x509.AlgorithmId;
59
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -070060/**
61 * CredentialStorage handles KeyStore reset, unlock, and install.
62 *
63 * CredentialStorage has a pretty convoluted state machine to migrate
64 * from the old style separate keystore password to a new key guard
65 * based password, as well as to deal with setting up the key guard if
66 * necessary.
67 *
68 * KeyStore: UNINITALIZED
69 * KeyGuard: OFF
70 * Action: set up key guard
71 * Notes: factory state
72 *
73 * KeyStore: UNINITALIZED
74 * KeyGuard: ON
75 * Action: confirm key guard
76 * Notes: user had key guard but no keystore and upgraded from pre-ICS
Fan Zhangab0a0c82017-06-05 17:15:21 -070077 * OR user had key guard and pre-ICS keystore password which was then reset
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -070078 *
79 * KeyStore: LOCKED
80 * KeyGuard: OFF/ON
81 * Action: old unlock dialog
82 * Notes: assume old password, need to use it to unlock.
Fan Zhangab0a0c82017-06-05 17:15:21 -070083 * if unlock, ensure key guard before install.
84 * if reset, treat as UNINITALIZED/OFF
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -070085 *
86 * KeyStore: UNLOCKED
87 * KeyGuard: OFF
88 * Action: set up key guard
89 * Notes: ensure key guard, then proceed
90 *
91 * KeyStore: UNLOCKED
92 * keyguard: ON
93 * Action: normal unlock/install
94 * Notes: this is the common case
95 */
96public final class CredentialStorage extends Activity {
Chia-chi Yeh91d65a22011-01-20 18:46:01 +080097
98 private static final String TAG = "CredentialStorage";
99
Brian Carlstromd4023b72011-05-25 13:24:20 -0700100 public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
101 public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
102 public static final String ACTION_RESET = "com.android.credentials.RESET";
103
104 // This is the minimum acceptable password quality. If the current password quality is
105 // lower than this, keystore should not be activated.
Fan Zhangab0a0c82017-06-05 17:15:21 -0700106 public static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
Brian Carlstromd4023b72011-05-25 13:24:20 -0700107
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700108 private static final int CONFIRM_KEY_GUARD_REQUEST = 1;
Ricky Waic0e50702016-05-24 11:13:56 +0100109 private static final int CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST = 2;
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700110
Brian Carlstromd4023b72011-05-25 13:24:20 -0700111 private final KeyStore mKeyStore = KeyStore.getInstance();
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700112
113 /**
114 * When non-null, the bundle containing credentials to install.
115 */
116 private Bundle mInstallBundle;
117
118 /**
119 * After unsuccessful KeyStore.unlock, the number of unlock
120 * attempts remaining before the KeyStore will reset itself.
121 *
122 * Reset to -1 on successful unlock or reset.
123 */
124 private int mRetriesRemaining = -1;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800125
Kenny Rootcf008c22012-09-16 14:01:43 -0700126 @Override
127 protected void onResume() {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700128 super.onResume();
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800129
130 Intent intent = getIntent();
131 String action = intent.getAction();
Julia Reynolds565653c2014-06-12 11:49:12 -0400132 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
133 if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) {
134 if (ACTION_RESET.equals(action)) {
135 new ResetDialog();
136 } else {
Robin Lee8823c3e2014-11-06 20:57:11 +0000137 if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) {
Julia Reynolds565653c2014-06-12 11:49:12 -0400138 mInstallBundle = intent.getExtras();
139 }
140 // ACTION_UNLOCK also handled here in addition to ACTION_INSTALL
141 handleUnlockOrInstall();
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800142 }
Julia Reynolds565653c2014-06-12 11:49:12 -0400143 } else {
Julia Reynoldsa12fc842015-03-03 12:32:30 -0500144 // Users can set a screen lock if there is none even if they can't modify the
145 // credentials store.
146 if (ACTION_UNLOCK.equals(action) && mKeyStore.state() == KeyStore.State.UNINITIALIZED) {
147 ensureKeyGuard();
148 } else {
149 finish();
150 }
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700151 }
152 }
153
154 /**
155 * Based on the current state of the KeyStore and key guard, try to
156 * make progress on unlocking or installing to the keystore.
157 */
158 private void handleUnlockOrInstall() {
159 // something already decided we are done, do not proceed
160 if (isFinishing()) {
161 return;
162 }
163 switch (mKeyStore.state()) {
164 case UNINITIALIZED: {
165 ensureKeyGuard();
166 return;
167 }
168 case LOCKED: {
169 new UnlockDialog();
170 return;
171 }
172 case UNLOCKED: {
173 if (!checkKeyGuardQuality()) {
Fan Zhangab0a0c82017-06-05 17:15:21 -0700174 final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
175 dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG);
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700176 return;
177 }
178 installIfAvailable();
179 finish();
180 return;
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800181 }
182 }
183 }
184
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700185 /**
186 * Make sure the user enters the key guard to set or change the
187 * keystore password. This can be used in UNINITIALIZED to set the
188 * keystore password or UNLOCKED to change the password (as is the
189 * case after unlocking with an old-style password).
190 */
191 private void ensureKeyGuard() {
192 if (!checkKeyGuardQuality()) {
193 // key guard not setup, doing so will initialize keystore
Fan Zhangab0a0c82017-06-05 17:15:21 -0700194 final ConfigureKeyGuardDialog dialog = new ConfigureKeyGuardDialog();
195 dialog.show(getFragmentManager(), ConfigureKeyGuardDialog.TAG);
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700196 // will return to onResume after Activity
197 return;
198 }
199 // force key guard confirmation
Ricky Waic0e50702016-05-24 11:13:56 +0100200 if (confirmKeyGuard(CONFIRM_KEY_GUARD_REQUEST)) {
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700201 // will return password value via onActivityResult
202 return;
203 }
204 finish();
205 }
206
207 /**
208 * Returns true if the currently set key guard matches our minimum quality requirements.
209 */
210 private boolean checkKeyGuardQuality() {
Robin Lee330c2052016-04-07 14:55:06 +0100211 int credentialOwner =
212 UserManager.get(this).getCredentialOwnerProfile(UserHandle.myUserId());
213 int quality = new LockPatternUtils(this).getActivePasswordQuality(credentialOwner);
Brian Carlstromd4023b72011-05-25 13:24:20 -0700214 return (quality >= MIN_PASSWORD_QUALITY);
215 }
216
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -0700217 private boolean isHardwareBackedKey(byte[] keyData) {
218 try {
219 ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
220 PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
Kenny Root1b291c12016-01-20 15:50:55 -0800221 String algOid = pki.getAlgorithmId().getAlgorithm().getId();
222 String algName = new AlgorithmId(new ObjectIdentifier(algOid)).getName();
Vinit Deshapnde6c0a1932013-09-30 10:41:27 -0700223
224 return KeyChain.isBoundKeyAlgorithm(algName);
225 } catch (IOException e) {
226 Log.e(TAG, "Failed to parse key data");
227 return false;
228 }
229 }
230
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700231 /**
232 * Install credentials if available, otherwise do nothing.
233 */
234 private void installIfAvailable() {
Robin Lee8823c3e2014-11-06 20:57:11 +0000235 if (mInstallBundle == null || mInstallBundle.isEmpty()) {
236 return;
Brian Carlstromd4023b72011-05-25 13:24:20 -0700237 }
Robin Lee8823c3e2014-11-06 20:57:11 +0000238
239 Bundle bundle = mInstallBundle;
240 mInstallBundle = null;
241
Robin Lee635426b2015-01-30 14:57:25 +0000242 final int uid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, KeyStore.UID_SELF);
Robin Lee8823c3e2014-11-06 20:57:11 +0000243
Robin Lee635426b2015-01-30 14:57:25 +0000244 if (uid != KeyStore.UID_SELF && !UserHandle.isSameUser(uid, Process.myUid())) {
Robin Lee8823c3e2014-11-06 20:57:11 +0000245 int dstUserId = UserHandle.getUserId(uid);
246 int myUserId = UserHandle.myUserId();
247
248 // Restrict install target to the wifi uid.
249 if (uid != Process.WIFI_UID) {
250 Log.e(TAG, "Failed to install credentials as uid " + uid + ": cross-user installs"
251 + " may only target wifi uids");
252 return;
253 }
254
255 Intent installIntent = new Intent(ACTION_INSTALL)
256 .setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
257 .putExtras(bundle);
258 startActivityAsUser(installIntent, new UserHandle(dstUserId));
259 return;
260 }
261
262 if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
263 String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
264 byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
265
266 int flags = KeyStore.FLAG_ENCRYPTED;
267 if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) {
268 // Hardware backed keystore is secure enough to allow for WIFI stack
269 // to enable access to secure networks without user intervention
270 Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID");
271 flags = KeyStore.FLAG_NONE;
272 }
273
274 if (!mKeyStore.importKey(key, value, uid, flags)) {
275 Log.e(TAG, "Failed to install " + key + " as uid " + uid);
276 return;
277 }
278 }
279
Chad Brubaker616b3fe2016-07-19 11:13:46 -0700280 int flags = KeyStore.FLAG_NONE;
Robin Lee8823c3e2014-11-06 20:57:11 +0000281
282 if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) {
283 String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME);
284 byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
285
286 if (!mKeyStore.put(certName, certData, uid, flags)) {
287 Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
288 return;
289 }
290 }
291
292 if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) {
293 String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME);
294 byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
295
296 if (!mKeyStore.put(caListName, caListData, uid, flags)) {
297 Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
298 return;
299 }
300 }
301
Chad Brubaker68baa352017-04-10 10:26:46 -0700302 // Send the broadcast.
303 Intent broadcast = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
304 sendBroadcast(broadcast);
305
Robin Lee8823c3e2014-11-06 20:57:11 +0000306 setResult(RESULT_OK);
Brian Carlstromd4023b72011-05-25 13:24:20 -0700307 }
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800308
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700309 /**
310 * Prompt for reset confirmation, resetting on confirmation, finishing otherwise.
311 */
Brian Carlstromd4023b72011-05-25 13:24:20 -0700312 private class ResetDialog
Fan Zhangab0a0c82017-06-05 17:15:21 -0700313 implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700314 private boolean mResetConfirmed;
315
316 private ResetDialog() {
317 AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
318 .setTitle(android.R.string.dialog_alert_title)
Brian Carlstromd4023b72011-05-25 13:24:20 -0700319 .setMessage(R.string.credentials_reset_hint)
320 .setPositiveButton(android.R.string.ok, this)
321 .setNegativeButton(android.R.string.cancel, this)
322 .create();
323 dialog.setOnDismissListener(this);
324 dialog.show();
325 }
326
Fan Zhangab0a0c82017-06-05 17:15:21 -0700327 @Override
328 public void onClick(DialogInterface dialog, int button) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700329 mResetConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
330 }
331
Fan Zhangab0a0c82017-06-05 17:15:21 -0700332 @Override
333 public void onDismiss(DialogInterface dialog) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700334 if (mResetConfirmed) {
335 mResetConfirmed = false;
Ricky Waic0e50702016-05-24 11:13:56 +0100336 if (confirmKeyGuard(CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST)) {
337 // will return password value via onActivityResult
338 return;
339 }
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800340 }
Brian Carlstromd4023b72011-05-25 13:24:20 -0700341 finish();
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800342 }
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800343 }
Brian Carlstrom98154292011-05-12 23:58:39 -0700344
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700345 /**
346 * Background task to handle reset of both keystore and user installed CAs.
347 */
Brian Carlstrom98154292011-05-12 23:58:39 -0700348 private class ResetKeyStoreAndKeyChain extends AsyncTask<Void, Void, Boolean> {
349
Fan Zhangab0a0c82017-06-05 17:15:21 -0700350 @Override
351 protected Boolean doInBackground(Void... unused) {
Brian Carlstrom98154292011-05-12 23:58:39 -0700352
Chad Brubakerce10b5e2015-05-21 15:57:24 -0700353 // Clear all the users credentials could have been installed in for this user.
Ricky Waic0e50702016-05-24 11:13:56 +0100354 new LockPatternUtils(CredentialStorage.this).resetKeyStore(UserHandle.myUserId());
Chad Brubakerce10b5e2015-05-21 15:57:24 -0700355
Brian Carlstrom98154292011-05-12 23:58:39 -0700356 try {
Brian Carlstrom435e45e2011-05-17 16:22:06 -0700357 KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this);
358 try {
359 return keyChainConnection.getService().reset();
360 } catch (RemoteException e) {
361 return false;
362 } finally {
363 keyChainConnection.close();
364 }
Brian Carlstrom98154292011-05-12 23:58:39 -0700365 } catch (InterruptedException e) {
366 Thread.currentThread().interrupt();
367 return false;
Brian Carlstrom98154292011-05-12 23:58:39 -0700368 }
369 }
370
Fan Zhangab0a0c82017-06-05 17:15:21 -0700371 @Override
372 protected void onPostExecute(Boolean success) {
Brian Carlstrom98154292011-05-12 23:58:39 -0700373 if (success) {
374 Toast.makeText(CredentialStorage.this,
Fan Zhangab0a0c82017-06-05 17:15:21 -0700375 R.string.credentials_erased, Toast.LENGTH_SHORT).show();
insight.lee03159e42017-01-17 08:27:01 +0900376 clearLegacyVpnIfEstablished();
Brian Carlstrom98154292011-05-12 23:58:39 -0700377 } else {
378 Toast.makeText(CredentialStorage.this,
Fan Zhangab0a0c82017-06-05 17:15:21 -0700379 R.string.credentials_not_erased, Toast.LENGTH_SHORT).show();
Brian Carlstrom98154292011-05-12 23:58:39 -0700380 }
381 finish();
382 }
383 }
Brian Carlstromd4023b72011-05-25 13:24:20 -0700384
insight.lee03159e42017-01-17 08:27:01 +0900385 private void clearLegacyVpnIfEstablished() {
386 boolean isDone = VpnUtils.disconnectLegacyVpn(getApplicationContext());
387 if (isDone) {
388 Toast.makeText(CredentialStorage.this, R.string.vpn_disconnected,
389 Toast.LENGTH_SHORT).show();
390 }
391 }
392
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700393 /**
Robin Lee8823c3e2014-11-06 20:57:11 +0000394 * Check that the caller is either certinstaller or Settings running in a profile of this user.
395 */
396 private boolean checkCallerIsCertInstallerOrSelfInProfile() {
397 if (TextUtils.equals("com.android.certinstaller", getCallingPackage())) {
Zoltan Szatmary-Ban307e3d02015-07-09 17:30:20 +0100398 // CertInstaller is allowed to install credentials if it has the same signature as
399 // Settings package.
400 return getPackageManager().checkSignatures(
401 getCallingPackage(), getPackageName()) == PackageManager.SIGNATURE_MATCH;
Robin Lee8823c3e2014-11-06 20:57:11 +0000402 }
403
404 final int launchedFromUserId;
405 try {
Sudheer Shankaacb1a612016-11-10 15:30:14 -0800406 int launchedFromUid = android.app.ActivityManager.getService()
Robin Lee8823c3e2014-11-06 20:57:11 +0000407 .getLaunchedFromUid(getActivityToken());
408 if (launchedFromUid == -1) {
409 Log.e(TAG, ACTION_INSTALL + " must be started with startActivityForResult");
410 return false;
411 }
412 if (!UserHandle.isSameApp(launchedFromUid, Process.myUid())) {
413 // Not the same app
414 return false;
415 }
416 launchedFromUserId = UserHandle.getUserId(launchedFromUid);
417 } catch (RemoteException re) {
418 // Error talking to ActivityManager, just give up
419 return false;
420 }
421
422 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
423 UserInfo parentInfo = userManager.getProfileParent(launchedFromUserId);
424 if (parentInfo == null || parentInfo.id != UserHandle.myUserId()) {
425 // Caller is not running in a profile of this user
426 return false;
427 }
428 return true;
429 }
430
431 /**
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700432 * Confirm existing key guard, returning password via onActivityResult.
433 */
Ricky Waic0e50702016-05-24 11:13:56 +0100434 private boolean confirmKeyGuard(int requestCode) {
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700435 Resources res = getResources();
436 boolean launched = new ChooseLockSettingsHelper(this)
Ricky Waic0e50702016-05-24 11:13:56 +0100437 .launchConfirmationActivity(requestCode,
Jorim Jaggi8a09b612015-04-06 17:47:18 -0700438 res.getText(R.string.credentials_title), true);
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700439 return launched;
440 }
441
442 @Override
443 public void onActivityResult(int requestCode, int resultCode, Intent data) {
444 super.onActivityResult(requestCode, resultCode, data);
445
446 /**
447 * Receive key guard password initiated by confirmKeyGuard.
448 */
449 if (requestCode == CONFIRM_KEY_GUARD_REQUEST) {
450 if (resultCode == Activity.RESULT_OK) {
451 String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
452 if (!TextUtils.isEmpty(password)) {
453 // success
Chad Brubaker7236f2a2015-05-07 10:29:18 -0700454 mKeyStore.unlock(password);
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700455 // return to onResume
456 return;
457 }
458 }
459 // failed confirmation, bail
460 finish();
Ricky Waic0e50702016-05-24 11:13:56 +0100461 } else if (requestCode == CONFIRM_CLEAR_SYSTEM_CREDENTIAL_REQUEST) {
462 if (resultCode == Activity.RESULT_OK) {
463 new ResetKeyStoreAndKeyChain().execute();
464 return;
465 }
466 // failed confirmation, bail
467 finish();
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700468 }
469 }
470
471 /**
472 * Prompt for unlock with old-style password.
473 *
474 * On successful unlock, ensure migration to key guard before continuing.
475 * On unsuccessful unlock, retry by calling handleUnlockOrInstall.
476 */
Brian Carlstromd4023b72011-05-25 13:24:20 -0700477 private class UnlockDialog implements TextWatcher,
Fan Zhangab0a0c82017-06-05 17:15:21 -0700478 DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700479 private boolean mUnlockConfirmed;
480
481 private final Button mButton;
482 private final TextView mOldPassword;
483 private final TextView mError;
484
485 private UnlockDialog() {
486 View view = View.inflate(CredentialStorage.this, R.layout.credentials_dialog, null);
487
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700488 CharSequence text;
489 if (mRetriesRemaining == -1) {
490 text = getResources().getText(R.string.credentials_unlock_hint);
491 } else if (mRetriesRemaining > 3) {
492 text = getResources().getText(R.string.credentials_wrong_password);
493 } else if (mRetriesRemaining == 1) {
494 text = getResources().getText(R.string.credentials_reset_warning);
495 } else {
496 text = getString(R.string.credentials_reset_warning_plural, mRetriesRemaining);
497 }
498
499 ((TextView) view.findViewById(R.id.hint)).setText(text);
Brian Carlstromd4023b72011-05-25 13:24:20 -0700500 mOldPassword = (TextView) view.findViewById(R.id.old_password);
501 mOldPassword.setVisibility(View.VISIBLE);
502 mOldPassword.addTextChangedListener(this);
503 mError = (TextView) view.findViewById(R.id.error);
504
505 AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
506 .setView(view)
507 .setTitle(R.string.credentials_unlock)
508 .setPositiveButton(android.R.string.ok, this)
509 .setNegativeButton(android.R.string.cancel, this)
510 .create();
511 dialog.setOnDismissListener(this);
512 dialog.show();
513 mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
514 mButton.setEnabled(false);
515 }
516
Fan Zhangab0a0c82017-06-05 17:15:21 -0700517 @Override
518 public void afterTextChanged(Editable editable) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700519 mButton.setEnabled(mOldPassword == null || mOldPassword.getText().length() > 0);
520 }
521
Fan Zhangab0a0c82017-06-05 17:15:21 -0700522 @Override
523 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700524 }
525
Fan Zhangab0a0c82017-06-05 17:15:21 -0700526 @Override
527 public void onTextChanged(CharSequence s, int start, int before, int count) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700528 }
529
Fan Zhangab0a0c82017-06-05 17:15:21 -0700530 @Override
531 public void onClick(DialogInterface dialog, int button) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700532 mUnlockConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
533 }
534
Fan Zhangab0a0c82017-06-05 17:15:21 -0700535 @Override
536 public void onDismiss(DialogInterface dialog) {
Brian Carlstromd4023b72011-05-25 13:24:20 -0700537 if (mUnlockConfirmed) {
538 mUnlockConfirmed = false;
539 mError.setVisibility(View.VISIBLE);
540 mKeyStore.unlock(mOldPassword.getText().toString());
541 int error = mKeyStore.getLastError();
542 if (error == KeyStore.NO_ERROR) {
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700543 mRetriesRemaining = -1;
Brian Carlstromd4023b72011-05-25 13:24:20 -0700544 Toast.makeText(CredentialStorage.this,
Fan Zhangab0a0c82017-06-05 17:15:21 -0700545 R.string.credentials_enabled,
546 Toast.LENGTH_SHORT).show();
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700547 // aha, now we are unlocked, switch to key guard.
548 // we'll end up back in onResume to install
549 ensureKeyGuard();
Brian Carlstromd4023b72011-05-25 13:24:20 -0700550 } else if (error == KeyStore.UNINITIALIZED) {
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700551 mRetriesRemaining = -1;
Brian Carlstromd4023b72011-05-25 13:24:20 -0700552 Toast.makeText(CredentialStorage.this,
Fan Zhangab0a0c82017-06-05 17:15:21 -0700553 R.string.credentials_erased,
554 Toast.LENGTH_SHORT).show();
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700555 // we are reset, we can now set new password with key guard
556 handleUnlockOrInstall();
Brian Carlstromd4023b72011-05-25 13:24:20 -0700557 } else if (error >= KeyStore.WRONG_PASSWORD) {
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700558 // we need to try again
559 mRetriesRemaining = error - KeyStore.WRONG_PASSWORD + 1;
560 handleUnlockOrInstall();
Brian Carlstromd4023b72011-05-25 13:24:20 -0700561 }
Brian Carlstrom0e88f4d2011-06-02 16:47:15 -0700562 return;
Brian Carlstromd4023b72011-05-25 13:24:20 -0700563 }
564 finish();
565 }
566 }
Chia-chi Yeh91d65a22011-01-20 18:46:01 +0800567}