CredentialStorage.java revision ce10b5edf0ba19b2bf74423c45d6640ab345ced4
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;
258823c3eda28930bcd6c8242bfed15b098d63acd0Robin Leeimport android.content.pm.UserInfo;
260e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstromimport android.content.res.Resources;
279815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstromimport android.os.AsyncTask;
2891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.os.Bundle;
299815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstromimport android.os.RemoteException;
306c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport android.os.Process;
318823c3eda28930bcd6c8242bfed15b098d63acd0Robin Leeimport android.os.UserHandle;
32565653cef1039ab4e34e505185f1c77d847357cdJulia Reynoldsimport android.os.UserManager;
33b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Rootimport android.security.Credentials;
34435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstromimport android.security.KeyChain.KeyChainConnection;
35d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstromimport android.security.KeyChain;
3691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.security.KeyStore;
3791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.text.Editable;
380e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstromimport android.text.TextUtils;
3991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.text.TextWatcher;
4091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.util.Log;
4191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.view.View;
4291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.Button;
4391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.TextView;
4491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yehimport android.widget.Toast;
4591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
46565653cef1039ab4e34e505185f1c77d847357cdJulia Reynoldsimport com.android.internal.widget.LockPatternUtils;
476c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport com.android.org.bouncycastle.asn1.ASN1InputStream;
486c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
496c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
506c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport org.apache.harmony.security.utils.AlgNameMapper;
516c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
526c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport java.io.ByteArrayInputStream;
536c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapndeimport java.io.IOException;
546c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom/**
560e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * CredentialStorage handles KeyStore reset, unlock, and install.
570e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
580e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * CredentialStorage has a pretty convoluted state machine to migrate
590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * from the old style separate keystore password to a new key guard
600e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * based password, as well as to deal with setting up the key guard if
610e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * necessary.
620e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNINITALIZED
640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF
650e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action:   set up key guard
660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes:    factory state
670e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNINITALIZED
690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: ON
700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action:   confirm key guard
710e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes:    user had key guard but no keystore and upgraded from pre-ICS
720e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *           OR user had key guard and pre-ICS keystore password which was then reset
730e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: LOCKED
750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF/ON
760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action:   old unlock dialog
770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes:    assume old password, need to use it to unlock.
780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *           if unlock, ensure key guard before install.
790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *           if reset, treat as UNINITALIZED/OFF
800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNLOCKED
820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyGuard: OFF
830e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action:   set up key guard
840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes:    ensure key guard, then proceed
850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom *
860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * KeyStore: UNLOCKED
870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * keyguard: ON
880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Action:   normal unlock/install
890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom * Notes:    this is the common case
900e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom */
910e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrompublic final class CredentialStorage extends Activity {
9291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
93d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    private static final String TAG = "CredentialStorage";
9491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
9591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK";
9691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    public static final String ACTION_INSTALL = "com.android.credentials.INSTALL";
9791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    public static final String ACTION_RESET = "com.android.credentials.RESET";
9891d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
99d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    // This is the minimum acceptable password quality.  If the current password quality is
100d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    // lower than this, keystore should not be activated.
101d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    static final int MIN_PASSWORD_QUALITY = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
10291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
1030e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private static final int CONFIRM_KEY_GUARD_REQUEST = 1;
1040e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
105d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    private final KeyStore mKeyStore = KeyStore.getInstance();
1060e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
1070e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
108ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker     * The UIDs that are used for system credential storage in keystore.
109ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker     */
110ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker    private static final int[] SYSTEM_CREDENTIAL_UIDS = {Process.WIFI_UID, Process.VPN_UID,
111ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker        Process.ROOT_UID, Process.SYSTEM_UID};
112ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker
113ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker    /**
1140e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * When non-null, the bundle containing credentials to install.
1150e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
1160e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private Bundle mInstallBundle;
1170e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
1180e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
1190e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * After unsuccessful KeyStore.unlock, the number of unlock
1200e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * attempts remaining before the KeyStore will reset itself.
1210e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     *
1220e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Reset to -1 on successful unlock or reset.
1230e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
1240e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private int mRetriesRemaining = -1;
12591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
126cf008c28b871d4167e5aa19191ca691fb988f8fdKenny Root    @Override
127cf008c28b871d4167e5aa19191ca691fb988f8fdKenny Root    protected void onResume() {
128d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        super.onResume();
12991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
13091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        Intent intent = getIntent();
13191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        String action = intent.getAction();
132565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
133565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds        if (!userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) {
134565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds            if (ACTION_RESET.equals(action)) {
135565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds                new ResetDialog();
136565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds            } else {
1378823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                if (ACTION_INSTALL.equals(action) && checkCallerIsCertInstallerOrSelfInProfile()) {
138565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds                    mInstallBundle = intent.getExtras();
139565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds                }
140565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds                // ACTION_UNLOCK also handled here in addition to ACTION_INSTALL
141565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds                handleUnlockOrInstall();
1420e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            }
143565653cef1039ab4e34e505185f1c77d847357cdJulia Reynolds        } else {
144a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds            // Users can set a screen lock if there is none even if they can't modify the
145a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds            // credentials store.
146a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds            if (ACTION_UNLOCK.equals(action) && mKeyStore.state() == KeyStore.State.UNINITIALIZED) {
147a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds                ensureKeyGuard();
148a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds            } else {
149a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds                finish();
150a12fc84877647499006a3ca4a4599878bb888543Julia Reynolds            }
1510e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        }
1520e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    }
1530e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
1540e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
1550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Based on the current state of the KeyStore and key guard, try to
1560e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * make progress on unlocking or installing to the keystore.
1570e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
1580e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private void handleUnlockOrInstall() {
1590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        // something already decided we are done, do not proceed
1600e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        if (isFinishing()) {
1610e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            return;
1620e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        }
1630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        switch (mKeyStore.state()) {
1640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            case UNINITIALIZED: {
1650e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                ensureKeyGuard();
1660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                return;
16791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh            }
1680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            case LOCKED: {
1690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                new UnlockDialog();
1700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                return;
17191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh            }
1720e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            case UNLOCKED: {
1730e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                if (!checkKeyGuardQuality()) {
1740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    new ConfigureKeyGuardDialog();
1750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    return;
1760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                }
1770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                installIfAvailable();
1780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                finish();
1790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                return;
1800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            }
1810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        }
1820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    }
1830e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
1840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
1850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Make sure the user enters the key guard to set or change the
1860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * keystore password. This can be used in UNINITIALIZED to set the
1870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * keystore password or UNLOCKED to change the password (as is the
1880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * case after unlocking with an old-style password).
1890e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
1900e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private void ensureKeyGuard() {
1910e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        if (!checkKeyGuardQuality()) {
1920e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            // key guard not setup, doing so will initialize keystore
1930e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            new ConfigureKeyGuardDialog();
1940e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            // will return to onResume after Activity
1950e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            return;
19691d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        }
1970e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        // force key guard confirmation
1980e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        if (confirmKeyGuard()) {
1990e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            // will return password value via onActivityResult
2000e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            return;
2010e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        }
2020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        finish();
20391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    }
20491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
2050e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
2060e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Returns true if the currently set key guard matches our minimum quality requirements.
2070e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
2080e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private boolean checkKeyGuardQuality() {
2095437588abd69bf3eff59684528aaf50e09b6cffcAdrian Roos        int quality = new LockPatternUtils(this).getActivePasswordQuality(
2105437588abd69bf3eff59684528aaf50e09b6cffcAdrian Roos                UserHandle.myUserId());
211d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        return (quality >= MIN_PASSWORD_QUALITY);
212d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    }
213d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
2146c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde    private boolean isHardwareBackedKey(byte[] keyData) {
2156c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde        try {
2166c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
2176c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
2186c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            String algId = pki.getAlgorithmId().getAlgorithm().getId();
2196c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            String algName = AlgNameMapper.map2AlgName(algId);
2206c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
2216c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            return KeyChain.isBoundKeyAlgorithm(algName);
2226c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde        } catch (IOException e) {
2236c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            Log.e(TAG, "Failed to parse key data");
2246c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde            return false;
2256c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde        }
2266c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde    }
2276c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
2280e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
2290e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Install credentials if available, otherwise do nothing.
2300e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
2310e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private void installIfAvailable() {
2328823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (mInstallBundle == null || mInstallBundle.isEmpty()) {
2338823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            return;
2348823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
2356c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
2368823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        Bundle bundle = mInstallBundle;
2378823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        mInstallBundle = null;
2388823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
239635426b0a7db8791bc62836921d3b2f22b36aceaRobin Lee        final int uid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, KeyStore.UID_SELF);
2408823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
241635426b0a7db8791bc62836921d3b2f22b36aceaRobin Lee        if (uid != KeyStore.UID_SELF && !UserHandle.isSameUser(uid, Process.myUid())) {
2428823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            int dstUserId = UserHandle.getUserId(uid);
2438823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            int myUserId = UserHandle.myUserId();
2448823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
2458823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            // Restrict install target to the wifi uid.
2468823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (uid != Process.WIFI_UID) {
2478823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.e(TAG, "Failed to install credentials as uid " + uid + ": cross-user installs"
2488823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                        + " may only target wifi uids");
2498823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return;
25091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh            }
251b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root
2528823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            Intent installIntent = new Intent(ACTION_INSTALL)
2538823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                    .setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
2548823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                    .putExtras(bundle);
2558823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            startActivityAsUser(installIntent, new UserHandle(dstUserId));
2568823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            return;
2578823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
2588823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
2598823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (bundle.containsKey(Credentials.EXTRA_USER_PRIVATE_KEY_NAME)) {
2608823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            String key = bundle.getString(Credentials.EXTRA_USER_PRIVATE_KEY_NAME);
2618823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            byte[] value = bundle.getByteArray(Credentials.EXTRA_USER_PRIVATE_KEY_DATA);
2626c0a193050747c760a01934a6c1bb204f933ad3eVinit Deshapnde
2638823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            int flags = KeyStore.FLAG_ENCRYPTED;
2648823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (uid == Process.WIFI_UID && isHardwareBackedKey(value)) {
2658823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                // Hardware backed keystore is secure enough to allow for WIFI stack
2668823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                // to enable access to secure networks without user intervention
2678823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.d(TAG, "Saving private key with FLAG_NONE for WIFI_UID");
2688823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                flags = KeyStore.FLAG_NONE;
2698823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            }
270b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root
2718823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (!mKeyStore.importKey(key, value, uid, flags)) {
2728823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.e(TAG, "Failed to install " + key + " as uid " + uid);
2738823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return;
274b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root            }
2758823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
276b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root
2778823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        int flags = (uid == Process.WIFI_UID) ? KeyStore.FLAG_NONE : KeyStore.FLAG_ENCRYPTED;
278b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root
2798823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (bundle.containsKey(Credentials.EXTRA_USER_CERTIFICATE_NAME)) {
2808823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            String certName = bundle.getString(Credentials.EXTRA_USER_CERTIFICATE_NAME);
2818823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            byte[] certData = bundle.getByteArray(Credentials.EXTRA_USER_CERTIFICATE_DATA);
2828823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
2838823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (!mKeyStore.put(certName, certData, uid, flags)) {
2848823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.e(TAG, "Failed to install " + certName + " as uid " + uid);
2858823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return;
286b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root            }
2878823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
288b50b15cdbed31e35c2c7f3cbaa7ce06a3feb3a6fKenny Root
2898823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (bundle.containsKey(Credentials.EXTRA_CA_CERTIFICATES_NAME)) {
2908823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            String caListName = bundle.getString(Credentials.EXTRA_CA_CERTIFICATES_NAME);
2918823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            byte[] caListData = bundle.getByteArray(Credentials.EXTRA_CA_CERTIFICATES_DATA);
2928823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
2938823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (!mKeyStore.put(caListName, caListData, uid, flags)) {
2948823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.e(TAG, "Failed to install " + caListName + " as uid " + uid);
2958823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return;
2968823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            }
29791d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        }
2988823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
2998823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        setResult(RESULT_OK);
30091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    }
30191d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
3020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
3030e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Prompt for reset confirmation, resetting on confirmation, finishing otherwise.
3040e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
305d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    private class ResetDialog
306d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener
307d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    {
308d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private boolean mResetConfirmed;
309d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
310d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private ResetDialog() {
311d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
312d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setTitle(android.R.string.dialog_alert_title)
313d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setMessage(R.string.credentials_reset_hint)
314d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setPositiveButton(android.R.string.ok, this)
315d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setNegativeButton(android.R.string.cancel, this)
316d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .create();
317d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.setOnDismissListener(this);
318d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.show();
31991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        }
32091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
321d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onClick(DialogInterface dialog, int button) {
322d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mResetConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
32391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        }
32491d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh
325d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onDismiss(DialogInterface dialog) {
326d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            if (mResetConfirmed) {
327d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                mResetConfirmed = false;
328d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                new ResetKeyStoreAndKeyChain().execute();
32991d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh                return;
33091d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh            }
331d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            finish();
33291d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh        }
33391d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh    }
3349815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom
3350e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
3360e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Background task to handle reset of both keystore and user installed CAs.
3370e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
3389815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom    private class ResetKeyStoreAndKeyChain extends AsyncTask<Void, Void, Boolean> {
3399815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom
3409815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom        @Override protected Boolean doInBackground(Void... unused) {
3419815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom
342ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker            // Clear all the users credentials could have been installed in for this user.
343ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker            final UserManager um = (UserManager) getSystemService(USER_SERVICE);
344ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker            for (UserInfo pi : um.getProfiles(UserHandle.getUserId(Process.myUid()))) {
345ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker                for (int uid : SYSTEM_CREDENTIAL_UIDS) {
346ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker                    mKeyStore.clearUid(UserHandle.getUid(pi.id, uid));
347ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker                }
348ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker            }
349ce10b5edf0ba19b2bf74423c45d6640ab345ced4Chad Brubaker
3509815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom
3519815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            try {
352435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                KeyChainConnection keyChainConnection = KeyChain.bind(CredentialStorage.this);
353435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                try {
354435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                    return keyChainConnection.getService().reset();
355435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                } catch (RemoteException e) {
356435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                    return false;
357435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                } finally {
358435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                    keyChainConnection.close();
359435e45e61610bfa50ca54267a72b9ad74c9f1d41Brian Carlstrom                }
3609815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            } catch (InterruptedException e) {
3619815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                Thread.currentThread().interrupt();
3629815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                return false;
3639815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            }
3649815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom        }
3659815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom
3669815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom        @Override protected void onPostExecute(Boolean success) {
3679815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            if (success) {
3689815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                Toast.makeText(CredentialStorage.this,
3699815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                               R.string.credentials_erased, Toast.LENGTH_SHORT).show();
3709815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            } else {
3719815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                Toast.makeText(CredentialStorage.this,
3729815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom                               R.string.credentials_not_erased, Toast.LENGTH_SHORT).show();
3739815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            }
3749815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom            finish();
3759815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom        }
3769815429821832c204eaf8edebb37f4e2ff7636f0Brian Carlstrom    }
377d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
3780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
3790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Prompt for key guard configuration confirmation.
3800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
3810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private class ConfigureKeyGuardDialog
382d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener
383d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    {
384d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private boolean mConfigureConfirmed;
385d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
3860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        private ConfigureKeyGuardDialog() {
387d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
388d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setTitle(android.R.string.dialog_alert_title)
389d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setMessage(R.string.credentials_configure_lock_screen_hint)
390d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setPositiveButton(android.R.string.ok, this)
391d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setNegativeButton(android.R.string.cancel, this)
392d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .create();
393d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.setOnDismissListener(this);
394d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.show();
395d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
396d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
397d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onClick(DialogInterface dialog, int button) {
398d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mConfigureConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
399d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
400d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
401d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onDismiss(DialogInterface dialog) {
402d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            if (mConfigureConfirmed) {
403d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                mConfigureConfirmed = false;
404d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
405d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
406d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                                MIN_PASSWORD_QUALITY);
407d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                startActivity(intent);
408d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                return;
409d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            }
410d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            finish();
411d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
412d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    }
413d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
4140e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
4158823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee     * Check that the caller is either certinstaller or Settings running in a profile of this user.
4168823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee     */
4178823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee    private boolean checkCallerIsCertInstallerOrSelfInProfile() {
4188823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (TextUtils.equals("com.android.certinstaller", getCallingPackage())) {
4198823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            // CertInstaller is allowed to install credentials
4208823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            return true;
4218823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
4228823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
4238823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        final int launchedFromUserId;
4248823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        try {
4258823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            int launchedFromUid = android.app.ActivityManagerNative.getDefault()
4268823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                    .getLaunchedFromUid(getActivityToken());
4278823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (launchedFromUid == -1) {
4288823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                Log.e(TAG, ACTION_INSTALL + " must be started with startActivityForResult");
4298823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return false;
4308823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            }
4318823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            if (!UserHandle.isSameApp(launchedFromUid, Process.myUid())) {
4328823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                // Not the same app
4338823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee                return false;
4348823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            }
4358823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            launchedFromUserId = UserHandle.getUserId(launchedFromUid);
4368823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        } catch (RemoteException re) {
4378823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            // Error talking to ActivityManager, just give up
4388823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            return false;
4398823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
4408823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
4418823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
4428823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        UserInfo parentInfo = userManager.getProfileParent(launchedFromUserId);
4438823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        if (parentInfo == null || parentInfo.id != UserHandle.myUserId()) {
4448823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            // Caller is not running in a profile of this user
4458823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee            return false;
4468823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        }
4478823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee        return true;
4488823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee    }
4498823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee
4508823c3eda28930bcd6c8242bfed15b098d63acd0Robin Lee    /**
4510e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Confirm existing key guard, returning password via onActivityResult.
4520e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
4530e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    private boolean confirmKeyGuard() {
4540e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        Resources res = getResources();
4550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        boolean launched = new ChooseLockSettingsHelper(this)
4568a09b619aeb233e2aab1919301f162d8acf1f0f0Jorim Jaggi                .launchConfirmationActivity(CONFIRM_KEY_GUARD_REQUEST,
4578a09b619aeb233e2aab1919301f162d8acf1f0f0Jorim Jaggi                        res.getText(R.string.credentials_title), true);
4580e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        return launched;
4590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    }
4600e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
4610e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    @Override
4620e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    public void onActivityResult(int requestCode, int resultCode, Intent data) {
4630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        super.onActivityResult(requestCode, resultCode, data);
4640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
4650e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        /**
4660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom         * Receive key guard password initiated by confirmKeyGuard.
4670e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom         */
4680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        if (requestCode == CONFIRM_KEY_GUARD_REQUEST) {
4690e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            if (resultCode == Activity.RESULT_OK) {
4700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                String password = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
4710e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                if (!TextUtils.isEmpty(password)) {
4720e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // success
4737236f2abbabefc08e68226677f51fe2117c8c0a5Chad Brubaker                    mKeyStore.unlock(password);
4740e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // return to onResume
4750e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    return;
4760e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                }
4770e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            }
4780e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            // failed confirmation, bail
4790e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            finish();
4800e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom        }
4810e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    }
4820e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
4830e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom    /**
4840e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * Prompt for unlock with old-style password.
4850e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     *
4860e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * On successful unlock, ensure migration to key guard before continuing.
4870e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     * On unsuccessful unlock, retry by calling handleUnlockOrInstall.
4880e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom     */
489d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    private class UnlockDialog implements TextWatcher,
490d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            DialogInterface.OnClickListener, DialogInterface.OnDismissListener
491d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    {
492d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private boolean mUnlockConfirmed;
493d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
494d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private final Button mButton;
495d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private final TextView mOldPassword;
496d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private final TextView mError;
497d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
498d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        private UnlockDialog() {
499d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            View view = View.inflate(CredentialStorage.this, R.layout.credentials_dialog, null);
500d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
5010e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            CharSequence text;
5020e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            if (mRetriesRemaining == -1) {
5030e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                text = getResources().getText(R.string.credentials_unlock_hint);
5040e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            } else if (mRetriesRemaining > 3) {
5050e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                text = getResources().getText(R.string.credentials_wrong_password);
5060e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            } else if (mRetriesRemaining == 1) {
5070e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                text = getResources().getText(R.string.credentials_reset_warning);
5080e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            } else {
5090e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                text = getString(R.string.credentials_reset_warning_plural, mRetriesRemaining);
5100e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            }
5110e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom
5120e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom            ((TextView) view.findViewById(R.id.hint)).setText(text);
513d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mOldPassword = (TextView) view.findViewById(R.id.old_password);
514d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mOldPassword.setVisibility(View.VISIBLE);
515d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mOldPassword.addTextChangedListener(this);
516d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mError = (TextView) view.findViewById(R.id.error);
517d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
518d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            AlertDialog dialog = new AlertDialog.Builder(CredentialStorage.this)
519d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setView(view)
520d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setTitle(R.string.credentials_unlock)
521d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setPositiveButton(android.R.string.ok, this)
522d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .setNegativeButton(android.R.string.cancel, this)
523d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    .create();
524d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.setOnDismissListener(this);
525d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            dialog.show();
526d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
527d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mButton.setEnabled(false);
528d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
529d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
530d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void afterTextChanged(Editable editable) {
531d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mButton.setEnabled(mOldPassword == null || mOldPassword.getText().length() > 0);
532d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
533d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
534d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {
535d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
536d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
537d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onTextChanged(CharSequence s,int start, int before, int count) {
538d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
539d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
540d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onClick(DialogInterface dialog, int button) {
541d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            mUnlockConfirmed = (button == DialogInterface.BUTTON_POSITIVE);
542d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
543d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom
544d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        @Override public void onDismiss(DialogInterface dialog) {
545d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            if (mUnlockConfirmed) {
546d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                mUnlockConfirmed = false;
547d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                mError.setVisibility(View.VISIBLE);
548d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                mKeyStore.unlock(mOldPassword.getText().toString());
549d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                int error = mKeyStore.getLastError();
550d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                if (error == KeyStore.NO_ERROR) {
5510e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    mRetriesRemaining = -1;
552d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    Toast.makeText(CredentialStorage.this,
553d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                                   R.string.credentials_enabled,
554d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                                   Toast.LENGTH_SHORT).show();
5550e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // aha, now we are unlocked, switch to key guard.
5560e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // we'll end up back in onResume to install
5570e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    ensureKeyGuard();
558d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                } else if (error == KeyStore.UNINITIALIZED) {
5590e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    mRetriesRemaining = -1;
560d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                    Toast.makeText(CredentialStorage.this,
561d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                                   R.string.credentials_erased,
562d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                                   Toast.LENGTH_SHORT).show();
5630e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // we are reset, we can now set new password with key guard
5640e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    handleUnlockOrInstall();
565d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                } else if (error >= KeyStore.WRONG_PASSWORD) {
5660e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    // we need to try again
5670e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    mRetriesRemaining = error - KeyStore.WRONG_PASSWORD + 1;
5680e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                    handleUnlockOrInstall();
569d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom                }
5700e88f4dd19a80e9e4d759595439773fb3e1f0c50Brian Carlstrom                return;
571d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            }
572d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom            finish();
573d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom        }
574d4023b7cca11e33e84df39dee9e9a737efab47c2Brian Carlstrom    }
57591d65a20af2d1bfb06f32d0bd821e8558afe939dChia-chi Yeh}
576