1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)package org.chromium.android_webview;
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.net.http.SslCertificate;
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.net.http.SslError;
90529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.util.Log;
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.webkit.ValueCallback;
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.CalledByNative;
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.base.JNINamespace;
140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport org.chromium.base.ThreadUtils;
150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport org.chromium.net.AndroidPrivateKey;
160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport org.chromium.net.DefaultAndroidKeyStore;
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport java.security.Principal;
190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport java.security.PrivateKey;
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport java.security.cert.CertificateEncodingException;
210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport java.security.cert.X509Certificate;
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport javax.security.auth.x500.X500Principal;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * This class handles the JNI communication logic for the the AwContentsClient class.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Both the Java and the native peers of AwContentsClientBridge are owned by the
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * corresponding AwContents instances. This class and its native peer are connected
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * via weak references. The native AwContentsClientBridge sets up and clear these weak
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * references.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)@JNINamespace("android_webview")
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public class AwContentsClientBridge {
340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    static final String TAG = "AwContentsClientBridge";
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private AwContentsClient mClient;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The native peer of this object.
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private long mNativeContentsClientBridge;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    private DefaultAndroidKeyStore mLocalKeyStore;
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    private ClientCertLookupTable mLookupTable;
430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Used for mocking this class in tests.
450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    protected AwContentsClientBridge(DefaultAndroidKeyStore keyStore,
460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            ClientCertLookupTable table) {
470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        mLocalKeyStore = keyStore;
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        mLookupTable = table;
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    public AwContentsClientBridge(AwContentsClient client, DefaultAndroidKeyStore keyStore,
520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            ClientCertLookupTable table) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        assert client != null;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mClient = client;
550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        mLocalKeyStore = keyStore;
560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        mLookupTable = table;
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    /**
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     * Callback to communicate clientcertificaterequest back to the AwContentsClientBridge.
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     * The public methods should be called on UI thread.
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     * A request can not be proceeded, ignored  or canceled more than once. Doing this
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     * is a programming error and causes an exception.
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch     */
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    public class ClientCertificateRequestCallback {
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private int mId;
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private String mHost;
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private int mPort;
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private boolean mIsCalled;
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        public ClientCertificateRequestCallback(int id, String host, int port) {
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mId = id;
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mHost = host;
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mPort = port;
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        public void proceed(final PrivateKey privateKey, final X509Certificate[] chain) {
790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            ThreadUtils.runOnUiThread(new Runnable() {
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                @Override
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                public void run() {
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    proceedOnUiThread(privateKey, chain);
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                }
840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            });
850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        public void ignore() {
880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            ThreadUtils.runOnUiThread(new Runnable() {
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                @Override
900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                public void run() {
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    ignoreOnUiThread();
920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                }
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            });
940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        public void cancel() {
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            ThreadUtils.runOnUiThread(new Runnable() {
980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                @Override
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                public void run() {
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    cancelOnUiThread();
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                }
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            });
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private void proceedOnUiThread(PrivateKey privateKey, X509Certificate[] chain) {
1070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            checkIfCalled();
1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            AndroidPrivateKey key = mLocalKeyStore.createKey(privateKey);
1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            if (key == null || chain == null || chain.length == 0) {
1120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                Log.w(TAG, "Empty client certificate chain?");
1130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                provideResponse(null, null);
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                return;
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            }
1160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            // Encode the certificate chain.
1170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            byte[][] encodedChain = new byte[chain.length][];
1180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            try {
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                for (int i = 0; i < chain.length; ++i) {
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    encodedChain[i] = chain[i].getEncoded();
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                }
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            } catch (CertificateEncodingException e) {
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                Log.w(TAG, "Could not retrieve encoded certificate chain: " + e);
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                provideResponse(null, null);
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                return;
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            }
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mLookupTable.allow(mHost, mPort, key, encodedChain);
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            provideResponse(key, encodedChain);
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private void ignoreOnUiThread() {
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            checkIfCalled();
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            provideResponse(null, null);
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private void cancelOnUiThread() {
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            checkIfCalled();
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mLookupTable.deny(mHost, mPort);
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            provideResponse(null, null);
1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private void checkIfCalled() {
1430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            if (mIsCalled) {
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                throw new IllegalStateException("The callback was already called.");
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            }
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            mIsCalled = true;
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        private void provideResponse(AndroidPrivateKey androidKey, byte[][] certChain) {
150010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)            if (mNativeContentsClientBridge == 0) return;
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            nativeProvideClientCertificateResponse(mNativeContentsClientBridge, mId,
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    certChain, androidKey);
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Used by the native peer to set/reset a weak ref to the native peer.
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @CalledByNative
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private void setNativeContentsClientBridge(long nativeContentsClientBridge) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mNativeContentsClientBridge = nativeContentsClientBridge;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If returns false, the request is immediately canceled, and any call to proceedSslError
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // has no effect. If returns true, the request should be canceled or proceeded using
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // proceedSslError().
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Unlike the webview classic, we do not keep keep a database of certificates that
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // are allowed by the user, because this functionality is already handled via
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // ssl_policy in native layers.
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    @CalledByNative
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean allowCertificateError(int certError, byte[] derBytes, final String url,
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            final int id) {
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final SslCertificate cert = SslUtil.getCertificateFromDerBytes(derBytes);
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (cert == null) {
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // if the certificate or the client is null, cancel the request
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return false;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        final SslError sslError = SslUtil.sslErrorFromNetErrorCode(certError, cert, url);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ValueCallback<Boolean> callback = new ValueCallback<Boolean>() {
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            @Override
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            public void onReceiveValue(final Boolean value) {
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                ThreadUtils.runOnUiThread(new Runnable() {
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    @Override
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    public void run() {
1830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        proceedSslError(value.booleanValue(), id);
1840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    }
1850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                });
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        };
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mClient.onReceivedSslError(callback, sslError);
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return true;
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private void proceedSslError(boolean proceed, int id) {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (mNativeContentsClientBridge == 0) return;
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        nativeProceedSslError(mNativeContentsClientBridge, proceed, id);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Intentionally not private for testing the native peer of this class.
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    @CalledByNative
1990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    protected void selectClientCertificate(final int id, final String[] keyTypes,
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            byte[][] encodedPrincipals, final String host, final int port) {
201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        assert mNativeContentsClientBridge != 0;
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        ClientCertLookupTable.Cert cert = mLookupTable.getCertData(host, port);
2030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (mLookupTable.isDenied(host, port)) {
2040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id,
2050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    null, null);
2060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            return;
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
2080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (cert != null) {
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id,
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    cert.certChain, cert.privateKey);
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            return;
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        // Build the list of principals from encoded versions.
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        Principal[] principals = null;
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        if (encodedPrincipals.length > 0) {
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            principals = new X500Principal[encodedPrincipals.length];
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            for (int n = 0; n < encodedPrincipals.length; n++) {
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                try {
2190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    principals[n] = new X500Principal(encodedPrincipals[n]);
2200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                } catch (IllegalArgumentException e) {
2210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    Log.w(TAG, "Exception while decoding issuers list: " + e);
2220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    nativeProvideClientCertificateResponse(mNativeContentsClientBridge, id,
2230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        null, null);
2240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    return;
2250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                }
2260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            }
2270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        }
2290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        final ClientCertificateRequestCallback callback =
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                new ClientCertificateRequestCallback(id, host, port);
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        mClient.onReceivedClientCertRequest(callback, keyTypes, principals, host, port);
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
2340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @CalledByNative
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private void handleJsAlert(String url, String message, int id) {
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        JsResultHandler handler = new JsResultHandler(this, id);
238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mClient.handleJsAlert(url, message, handler);
239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @CalledByNative
242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private void handleJsConfirm(String url, String message, int id) {
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        JsResultHandler handler = new JsResultHandler(this, id);
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mClient.handleJsConfirm(url, message, handler);
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @CalledByNative
248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private void handleJsPrompt(String url, String message, String defaultValue, int id) {
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        JsResultHandler handler = new JsResultHandler(this, id);
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mClient.handleJsPrompt(url, message, defaultValue, handler);
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    @CalledByNative
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private void handleJsBeforeUnload(String url, String message, int id) {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        JsResultHandler handler = new JsResultHandler(this, id);
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mClient.handleJsBeforeUnload(url, message, handler);
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    @CalledByNative
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private boolean shouldOverrideUrlLoading(String url) {
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return mClient.shouldOverrideUrlLoading(url);
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    void confirmJsResult(int id, String prompt) {
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mNativeContentsClientBridge == 0) return;
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        nativeConfirmJsResult(mNativeContentsClientBridge, id, prompt);
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    void cancelJsResult(int id) {
270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mNativeContentsClientBridge == 0) return;
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        nativeCancelJsResult(mNativeContentsClientBridge, id);
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //--------------------------------------------------------------------------------------------
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //  Native methods
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    //--------------------------------------------------------------------------------------------
277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeProceedSslError(long nativeAwContentsClientBridge, boolean proceed,
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            int id);
2790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    private native void nativeProvideClientCertificateResponse(long nativeAwContentsClientBridge,
2800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            int id, byte[][] certChain, AndroidPrivateKey androidKey);
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeConfirmJsResult(long nativeAwContentsClientBridge, int id,
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            String prompt);
284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private native void nativeCancelJsResult(long nativeAwContentsClientBridge, int id);
285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
286