13e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom/*
23e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project
33e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom *
43e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
53e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * you may not use this file except in compliance with the License.
63e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * You may obtain a copy of the License at
73e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom *
83e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
93e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom *
103e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
113e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * See the License for the specific language governing permissions and
143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * limitations under the License.
153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom */
163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrompackage com.android.keychain.tests;
183e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
193e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.app.Activity;
203e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.content.Intent;
213e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.os.AsyncTask;
223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.os.Bundle;
2365e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstromimport android.os.StrictMode;
243e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.KeyChain;
25f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstromimport android.security.KeyChainAliasCallback;
26f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstromimport android.security.KeyChainException;
273e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.text.method.ScrollingMovementMethod;
283e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.util.Log;
293e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.widget.TextView;
303e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.net.Socket;
313e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.net.URL;
323e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.KeyStore;
333e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.Principal;
343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.PrivateKey;
353e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.CertificateException;
363e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.X509Certificate;
373e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.HttpsURLConnection;
383e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.KeyManager;
393e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.KeyManagerFactory;
403e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.SSLContext;
413e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.SSLSocketFactory;
423e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.TrustManager;
433e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.X509ExtendedKeyManager;
443e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport javax.net.ssl.X509TrustManager;
453e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport libcore.java.security.TestKeyStore;
463e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport libcore.javax.net.ssl.TestSSLContext;
47b56adc2162cecde6e6aa6561ad873bca29426d2fJesse Wilsonimport com.google.mockwebserver.MockResponse;
48b56adc2162cecde6e6aa6561ad873bca29426d2fJesse Wilsonimport com.google.mockwebserver.MockWebServer;
493e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
503e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom/**
513e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Simple activity based test that exercises the KeyChain API
523e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom */
533e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrompublic class KeyChainTestActivity extends Activity {
543e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
553e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private static final String TAG = "KeyChainTestActivity";
563e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
578be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    private static final int REQUEST_CA_INSTALL = 1;
583e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
593e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private TextView mTextView;
603e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
6165e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom    private TestKeyStore mTestKeyStore;
623e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
633e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private final Object mAliasLock = new Object();
643e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private String mAlias;
653e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
663e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private final Object mGrantedLock = new Object();
673e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private boolean mGranted;
683e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
693e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private void log(final String message) {
703e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        Log.d(TAG, message);
713e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        runOnUiThread(new Runnable() {
723e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            @Override public void run() {
733e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                mTextView.append(message + "\n");
743e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            }
753e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        });
763e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
773e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
783e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    @Override public void onCreate(Bundle savedInstanceState) {
793e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        super.onCreate(savedInstanceState);
803e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
8165e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
8265e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .detectDiskReads()
8365e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .detectDiskWrites()
8465e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .detectAll()
8565e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .penaltyLog()
8665e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .penaltyDeath()
8765e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                   .build());
8865e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
8965e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                               .detectLeakedSqlLiteObjects()
9065e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                               .detectLeakedClosableObjects()
9165e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                               .penaltyLog()
9265e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                               .penaltyDeath()
9365e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                               .build());
9465e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom
953e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        mTextView = new TextView(this);
963e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        mTextView.setMovementMethod(new ScrollingMovementMethod());
973e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        setContentView(mTextView);
983e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
993e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        log("Starting test...");
1008be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        testKeyChainImproperUse();
1013e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
10265e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        new SetupTestKeyStore().execute();
1038be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    }
1048be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom
1058be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    private void testKeyChainImproperUse() {
1063e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        try {
107bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            KeyChain.getPrivateKey(null, null);
1083e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            throw new AssertionError();
1093e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        } catch (InterruptedException e) {
1105aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
111f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom        } catch (KeyChainException e) {
1125aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
1135aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (NullPointerException expected) {
1145aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            log("KeyChain failed as expected with null argument.");
1155aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        }
1165aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom
1175aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        try {
118bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            KeyChain.getPrivateKey(this, null);
1195aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError();
1205aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (InterruptedException e) {
1215aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
122f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom        } catch (KeyChainException e) {
1235aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
1245aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (NullPointerException expected) {
1255aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            log("KeyChain failed as expected with null argument.");
1265aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        }
1275aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom
1285aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        try {
129bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            KeyChain.getPrivateKey(null, "");
1305aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError();
1315aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (InterruptedException e) {
1325aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
133f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom        } catch (KeyChainException e) {
1345aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
1355aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (NullPointerException expected) {
1365aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            log("KeyChain failed as expected with null argument.");
1375aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        }
1385aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom
1395aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        try {
140bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            KeyChain.getPrivateKey(this, "");
1415aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError();
1425aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom        } catch (InterruptedException e) {
1435aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
144f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom        } catch (KeyChainException e) {
1455aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            throw new AssertionError(e);
1463e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        } catch (IllegalStateException expected) {
1473e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            log("KeyChain failed as expected on main thread.");
1483e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
1498be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    }
1503e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
15165e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom    private class SetupTestKeyStore extends AsyncTask<Void, Void, Void> {
15265e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        @Override protected Void doInBackground(Void... params) {
15365e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            mTestKeyStore = TestKeyStore.getServer();
15465e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            return null;
15565e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        }
15665e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        @Override protected void onPostExecute(Void result) {
15765e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            testCaInstall();
15865e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom        }
15965e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom    }
16065e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom
1618be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    private void testCaInstall() {
1628be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        try {
1638be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            log("Requesting install of server's CA...");
16465e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            X509Certificate ca = mTestKeyStore.getRootCertificate("RSA");
1658dde66b240e5777c3c831767914e9ef773384aacBrian Carlstrom            Intent intent = KeyChain.createInstallIntent();
1668dde66b240e5777c3c831767914e9ef773384aacBrian Carlstrom            intent.putExtra(KeyChain.EXTRA_NAME, TAG);
1678dde66b240e5777c3c831767914e9ef773384aacBrian Carlstrom            intent.putExtra(KeyChain.EXTRA_CERTIFICATE, ca.getEncoded());
1688be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            startActivityForResult(intent, REQUEST_CA_INSTALL);
1698be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        } catch (Exception e) {
1708be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            throw new AssertionError(e);
1718be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        }
1723e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
1733e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
1743e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
1758be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    private class TestHttpsRequest extends AsyncTask<Void, Void, Void> {
1768be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        @Override protected Void doInBackground(Void... params) {
1778be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            try {
1788be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                log("Starting web server...");
1798be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                URL url = startWebServer();
1808be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                log("Making https request to " + url);
1818be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                makeHttpsRequest(url);
1828be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                log("Tests succeeded.");
1838be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom
1848be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                return null;
1858be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            } catch (Exception e) {
1868be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                throw new AssertionError(e);
1878be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            }
1888be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        }
1898be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        private URL startWebServer() throws Exception {
19065e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            KeyStore serverKeyStore = mTestKeyStore.keyStore;
19165e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom            char[] serverKeyStorePassword = mTestKeyStore.storePassword;
1928be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            String kmfAlgoritm = KeyManagerFactory.getDefaultAlgorithm();
1938be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfAlgoritm);
1948be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            kmf.init(serverKeyStore, serverKeyStorePassword);
1958be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            SSLContext serverContext = SSLContext.getInstance("SSL");
1968be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            serverContext.init(kmf.getKeyManagers(),
1978be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                               new TrustManager[] { new TrustAllTrustManager() },
1988be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                               null);
1998be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            SSLSocketFactory sf = serverContext.getSocketFactory();
2008be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            SSLSocketFactory needClientAuth = TestSSLContext.clientAuth(sf, false, true);
2018be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            MockWebServer server = new MockWebServer();
2028be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            server.useHttps(needClientAuth, false);
2038be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
2048be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            server.play();
2058be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            return server.getUrl("/");
2068be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        }
2078be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        private void makeHttpsRequest(URL url) throws Exception {
2088be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            SSLContext clientContext = SSLContext.getInstance("SSL");
2098be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            clientContext.init(new KeyManager[] { new KeyChainKeyManager() }, null, null);
2108be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
2118be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            connection.setSSLSocketFactory(clientContext.getSocketFactory());
2128be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            if (connection.getResponseCode() != 200) {
2138be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                throw new AssertionError();
2143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            }
2153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
2173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
2183e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private class KeyChainKeyManager extends X509ExtendedKeyManager {
2193e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public String chooseClientAlias(String[] keyTypes,
2203e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                                                  Principal[] issuers,
2213e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                                                  Socket socket) {
2223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            log("KeyChainKeyManager chooseClientAlias...");
2233e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
224f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom            KeyChain.choosePrivateKeyAlias(KeyChainTestActivity.this, new AliasResponse(),
22565e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                           keyTypes, issuers,
22665e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                           socket.getInetAddress().getHostName(), socket.getPort(),
22765e649e856d88520ac04f5b16313a3f167e569e0Brian Carlstrom                                           "My Test Certificate");
2283e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            String alias;
2293e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            synchronized (mAliasLock) {
2303e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                while (mAlias == null) {
2313e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                    try {
2323e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                        mAliasLock.wait();
2333e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                    } catch (InterruptedException ignored) {
2343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                    }
2353e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                }
2363e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                alias = mAlias;
2373e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            }
2383e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            return alias;
2393e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2403e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public String chooseServerAlias(String keyType,
2413e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                                                  Principal[] issuers,
2423e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                                                  Socket socket) {
2433e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            // not a client SSLSocket callback
2443e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            throw new UnsupportedOperationException();
2453e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2463e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public X509Certificate[] getCertificateChain(String alias) {
2475aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            try {
2485aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                log("KeyChainKeyManager getCertificateChain...");
249bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                X509Certificate[] certificateChain
250bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                        = KeyChain.getCertificateChain(KeyChainTestActivity.this, alias);
251bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                if (certificateChain == null) {
252bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                    log("Null certificate chain!");
253bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                    return null;
2545aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                }
255aa14e89b1194c4d4054fcd8dbd0af9d08dd5715cBrian Carlstrom                for (int i = 0; i < certificateChain.length; i++) {
256aa14e89b1194c4d4054fcd8dbd0af9d08dd5715cBrian Carlstrom                    log("certificate[" + i + "]=" + certificateChain[i]);
257aa14e89b1194c4d4054fcd8dbd0af9d08dd5715cBrian Carlstrom                }
258bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                return certificateChain;
2595aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            } catch (InterruptedException e) {
2605aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                Thread.currentThread().interrupt();
2615aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                return null;
262f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom            } catch (KeyChainException e) {
2635aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                throw new RuntimeException(e);
2643e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            }
2653e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2663e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public String[] getClientAliases(String keyType, Principal[] issuers) {
2673e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            // not a client SSLSocket callback
2683e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            throw new UnsupportedOperationException();
2693e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2703e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public String[] getServerAliases(String keyType, Principal[] issuers) {
2713e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            // not a client SSLSocket callback
2723e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            throw new UnsupportedOperationException();
2733e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2743e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public PrivateKey getPrivateKey(String alias) {
2755aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            try {
2765aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                log("KeyChainKeyManager getPrivateKey...");
277bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                PrivateKey privateKey = KeyChain.getPrivateKey(KeyChainTestActivity.this,
278bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                                                                         alias);
2795aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                log("privateKey=" + privateKey);
2805aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                return privateKey;
2815aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom            } catch (InterruptedException e) {
2825aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                Thread.currentThread().interrupt();
2835aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                return null;
284f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom            } catch (KeyChainException e) {
2855aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom                throw new RuntimeException(e);
2863e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            }
2873e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
2883e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
2893e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
290f5b50a4678120890d62bb07bb47cbd3f1ba4b243Brian Carlstrom    private class AliasResponse implements KeyChainAliasCallback {
291bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom        @Override public void alias(String alias) {
292bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            if (alias == null) {
293bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                log("AliasResponse empty!");
294bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                log("Do you need to install some client certs with:");
295bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                log("    adb shell am startservice -n "
296bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                    + "com.android.keychain.tests/.KeyChainServiceTest");
297bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                return;
298bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            }
299bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            log("Alias choosen '" + alias + "'");
300bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom            synchronized (mAliasLock) {
301bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                mAlias = alias;
302bb04f703be50794c41e453e82c70e354a545ea54Brian Carlstrom                mAliasLock.notifyAll();
3038be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            }
3048be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom        }
3058be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom    }
3068be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom
3073e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    private static class TrustAllTrustManager implements X509TrustManager {
3083e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public void checkClientTrusted(X509Certificate[] chain, String authType)
3093e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                throws CertificateException {
3103e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
3113e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public void checkServerTrusted(X509Certificate[] chain, String authType)
3123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                throws CertificateException {
3133e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
3143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        @Override public X509Certificate[] getAcceptedIssuers() {
3153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            return null;
3163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
3173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
3183e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom
3193e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
3203e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        switch (requestCode) {
3218be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            case REQUEST_CA_INSTALL: {
3228be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                log("onActivityResult REQUEST_CA_INSTALL...");
3238be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                if (resultCode != RESULT_OK) {
3248be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                    log("REQUEST_CA_INSTALL failed!");
3258be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                    return;
3268be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                }
3278be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                new TestHttpsRequest().execute();
3288be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom                break;
3298be0660196926b8f0a571f218711cf1b34fbaba2Brian Carlstrom            }
3303e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom            default:
3313e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom                throw new IllegalStateException("requestCode == " + requestCode);
3323e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom        }
3333e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom    }
3343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom}
335