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