Loading core/java/android/webkit/BrowserFrame.java +34 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,9 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.nio.charset.Charsets; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -1141,7 +1144,7 @@ class BrowserFrame extends Handler { } /** * Called by JNI when the native HTTP(S) stack gets an invalid cert chain. * Called by JNI when the native HTTPS stack gets an invalid cert chain. * * We delegate the request to CallbackProxy, and route its response to * {@link #nativeSslCertErrorProceed(int)} or Loading Loading @@ -1181,6 +1184,32 @@ class BrowserFrame extends Handler { } } /** * Called by JNI when the native HTTPS stack gets a client * certificate request. * * We delegate the request to CallbackProxy, and route its response to * {@link #nativeSslClientCert(int, X509Certificate)}. */ private void requestClientCert(int handle, byte[] host_and_port_bytes) { String host_and_port = new String(host_and_port_bytes, Charsets.UTF_8); SslClientCertLookupTable table = SslClientCertLookupTable.getInstance(); if (table.IsAllowed(host_and_port)) { // previously allowed nativeSslClientCert(handle, table.PrivateKey(host_and_port), table.CertificateChain(host_and_port)); } else if (table.IsDenied(host_and_port)) { // previously denied nativeSslClientCert(handle, null, null); } else { // previously ignored or new mCallbackProxy.onReceivedClientCertRequest( new ClientCertRequestHandler(this, handle, host_and_port, table), host_and_port); } } /** * Called by JNI when the native HTTP stack needs to download a file. * Loading Loading @@ -1366,4 +1395,8 @@ class BrowserFrame extends Handler { private native void nativeSslCertErrorProceed(int handle); private native void nativeSslCertErrorCancel(int handle, int cert_error); native void nativeSslClientCert(int handle, byte[] pkcs8EncodedPrivateKey, byte[][] asn1DerEncodedCertificateChain); } core/java/android/webkit/CallbackProxy.java +34 −7 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ class CallbackProxy extends Handler { private static final int SET_INSTALLABLE_WEBAPP = 138; private static final int NOTIFY_SEARCHBOX_LISTENERS = 139; private static final int AUTO_LOGIN = 140; private static final int CLIENT_CERT_REQUEST = 141; // Message triggered by the client to resume execution private static final int NOTIFY = 200; Loading Loading @@ -348,6 +349,16 @@ class CallbackProxy extends Handler { } break; case CLIENT_CERT_REQUEST: if (mWebViewClient != null) { HashMap<String, Object> map = (HashMap<String, Object>) msg.obj; mWebViewClient.onReceivedClientCertRequest(mWebView, (ClientCertRequestHandler) map.get("handler"), (String) map.get("host_and_port")); } break; case PROGRESS: // Synchronize to ensure mLatestProgress is not modified after // setProgress is called and before mProgressUpdatePending is Loading Loading @@ -998,13 +1009,29 @@ class CallbackProxy extends Handler { return; } Message msg = obtainMessage(SSL_ERROR); //, handler); HashMap<String, Object> map = new HashMap(); map.put("handler", handler); map.put("error", error); msg.obj = map; sendMessage(msg); } /** * @hide */ public void onReceivedClientCertRequest(ClientCertRequestHandler handler, String host_and_port) { // Do an unsynchronized quick check to avoid posting if no callback has // been set. if (mWebViewClient == null) { handler.cancel(); return; } Message msg = obtainMessage(CLIENT_CERT_REQUEST); HashMap<String, Object> map = new HashMap(); map.put("handler", handler); map.put("host_and_port", host_and_port); msg.obj = map; sendMessage(msg); } /** * @hide - hide this because it contains a parameter of type SslCertificate, * which is located in a hidden package. Loading core/java/android/webkit/ClientCertRequestHandler.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import org.apache.harmony.xnet.provider.jsse.NativeCrypto; /** * ClientCertRequestHandler: class responsible for handling client * certificate requests. This class is passed as a parameter to * BrowserCallback.displayClientCertRequestDialog and is meant to * receive the user's response. * * @hide */ public final class ClientCertRequestHandler { private final BrowserFrame mBrowserFrame; private final int mHandle; private final String mHostAndPort; private final SslClientCertLookupTable mTable; ClientCertRequestHandler(BrowserFrame browserFrame, int handle, String host_and_port, SslClientCertLookupTable table) { mBrowserFrame = browserFrame; mHandle = handle; mHostAndPort = host_and_port; mTable = table; } /** * Proceed with the specified private key and client certificate chain. */ public void proceed(PrivateKey privateKey, X509Certificate[] chain) { byte[] privateKeyBytes = privateKey.getEncoded(); byte[][] chainBytes; try { chainBytes = NativeCrypto.encodeCertificates(chain); } catch (CertificateEncodingException e) { mBrowserFrame.nativeSslClientCert(mHandle, null, null); return; } mTable.Allow(mHostAndPort, privateKeyBytes, chainBytes); mBrowserFrame.nativeSslClientCert(mHandle, privateKeyBytes, chainBytes); } /** * Igore the request for now, the user may be prompted again. */ public void ignore() { mBrowserFrame.nativeSslClientCert(mHandle, null, null); } /** * Cancel this request, remember the users negative choice. */ public void cancel() { mTable.Deny(mHostAndPort); mBrowserFrame.nativeSslClientCert(mHandle, null, null); } } core/java/android/webkit/SslCertLookupTable.java +2 −2 Original line number Diff line number Diff line Loading @@ -19,11 +19,11 @@ package android.webkit; import android.os.Bundle; import android.net.http.SslError; /* /** * A simple class to store the wrong certificates that user is aware but * chose to proceed. */ class SslCertLookupTable { final class SslCertLookupTable { private static SslCertLookupTable sTable; private final Bundle table; Loading core/java/android/webkit/SslClientCertLookupTable.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * A simple class to store client certificates that user has chosen. */ final class SslClientCertLookupTable { private static SslClientCertLookupTable sTable; private final Map<String, byte[]> privateKeys; private final Map<String, byte[][]> certificateChains; private final Set<String> denied; public static synchronized SslClientCertLookupTable getInstance() { if (sTable == null) { sTable = new SslClientCertLookupTable(); } return sTable; } private SslClientCertLookupTable() { privateKeys = new HashMap<String, byte[]>(); certificateChains = new HashMap<String, byte[][]>(); denied = new HashSet<String>(); } public void Allow(String host_and_port, byte[] privateKey, byte[][] chain) { privateKeys.put(host_and_port, privateKey); certificateChains.put(host_and_port, chain); denied.remove(host_and_port); } public void Deny(String host_and_port) { privateKeys.remove(host_and_port); certificateChains.remove(host_and_port); denied.add(host_and_port); } public boolean IsAllowed(String host_and_port) { return privateKeys.containsKey(host_and_port); } public boolean IsDenied(String host_and_port) { return denied.contains(host_and_port); } public byte[] PrivateKey(String host_and_port) { return privateKeys.get(host_and_port); } public byte[][] CertificateChain(String host_and_port) { return certificateChains.get(host_and_port); } } Loading
core/java/android/webkit/BrowserFrame.java +34 −1 Original line number Diff line number Diff line Loading @@ -44,6 +44,9 @@ import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.URLEncoder; import java.nio.charset.Charsets; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.HashMap; Loading Loading @@ -1141,7 +1144,7 @@ class BrowserFrame extends Handler { } /** * Called by JNI when the native HTTP(S) stack gets an invalid cert chain. * Called by JNI when the native HTTPS stack gets an invalid cert chain. * * We delegate the request to CallbackProxy, and route its response to * {@link #nativeSslCertErrorProceed(int)} or Loading Loading @@ -1181,6 +1184,32 @@ class BrowserFrame extends Handler { } } /** * Called by JNI when the native HTTPS stack gets a client * certificate request. * * We delegate the request to CallbackProxy, and route its response to * {@link #nativeSslClientCert(int, X509Certificate)}. */ private void requestClientCert(int handle, byte[] host_and_port_bytes) { String host_and_port = new String(host_and_port_bytes, Charsets.UTF_8); SslClientCertLookupTable table = SslClientCertLookupTable.getInstance(); if (table.IsAllowed(host_and_port)) { // previously allowed nativeSslClientCert(handle, table.PrivateKey(host_and_port), table.CertificateChain(host_and_port)); } else if (table.IsDenied(host_and_port)) { // previously denied nativeSslClientCert(handle, null, null); } else { // previously ignored or new mCallbackProxy.onReceivedClientCertRequest( new ClientCertRequestHandler(this, handle, host_and_port, table), host_and_port); } } /** * Called by JNI when the native HTTP stack needs to download a file. * Loading Loading @@ -1366,4 +1395,8 @@ class BrowserFrame extends Handler { private native void nativeSslCertErrorProceed(int handle); private native void nativeSslCertErrorCancel(int handle, int cert_error); native void nativeSslClientCert(int handle, byte[] pkcs8EncodedPrivateKey, byte[][] asn1DerEncodedCertificateChain); }
core/java/android/webkit/CallbackProxy.java +34 −7 Original line number Diff line number Diff line Loading @@ -118,6 +118,7 @@ class CallbackProxy extends Handler { private static final int SET_INSTALLABLE_WEBAPP = 138; private static final int NOTIFY_SEARCHBOX_LISTENERS = 139; private static final int AUTO_LOGIN = 140; private static final int CLIENT_CERT_REQUEST = 141; // Message triggered by the client to resume execution private static final int NOTIFY = 200; Loading Loading @@ -348,6 +349,16 @@ class CallbackProxy extends Handler { } break; case CLIENT_CERT_REQUEST: if (mWebViewClient != null) { HashMap<String, Object> map = (HashMap<String, Object>) msg.obj; mWebViewClient.onReceivedClientCertRequest(mWebView, (ClientCertRequestHandler) map.get("handler"), (String) map.get("host_and_port")); } break; case PROGRESS: // Synchronize to ensure mLatestProgress is not modified after // setProgress is called and before mProgressUpdatePending is Loading Loading @@ -998,13 +1009,29 @@ class CallbackProxy extends Handler { return; } Message msg = obtainMessage(SSL_ERROR); //, handler); HashMap<String, Object> map = new HashMap(); map.put("handler", handler); map.put("error", error); msg.obj = map; sendMessage(msg); } /** * @hide */ public void onReceivedClientCertRequest(ClientCertRequestHandler handler, String host_and_port) { // Do an unsynchronized quick check to avoid posting if no callback has // been set. if (mWebViewClient == null) { handler.cancel(); return; } Message msg = obtainMessage(CLIENT_CERT_REQUEST); HashMap<String, Object> map = new HashMap(); map.put("handler", handler); map.put("host_and_port", host_and_port); msg.obj = map; sendMessage(msg); } /** * @hide - hide this because it contains a parameter of type SslCertificate, * which is located in a hidden package. Loading
core/java/android/webkit/ClientCertRequestHandler.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import org.apache.harmony.xnet.provider.jsse.NativeCrypto; /** * ClientCertRequestHandler: class responsible for handling client * certificate requests. This class is passed as a parameter to * BrowserCallback.displayClientCertRequestDialog and is meant to * receive the user's response. * * @hide */ public final class ClientCertRequestHandler { private final BrowserFrame mBrowserFrame; private final int mHandle; private final String mHostAndPort; private final SslClientCertLookupTable mTable; ClientCertRequestHandler(BrowserFrame browserFrame, int handle, String host_and_port, SslClientCertLookupTable table) { mBrowserFrame = browserFrame; mHandle = handle; mHostAndPort = host_and_port; mTable = table; } /** * Proceed with the specified private key and client certificate chain. */ public void proceed(PrivateKey privateKey, X509Certificate[] chain) { byte[] privateKeyBytes = privateKey.getEncoded(); byte[][] chainBytes; try { chainBytes = NativeCrypto.encodeCertificates(chain); } catch (CertificateEncodingException e) { mBrowserFrame.nativeSslClientCert(mHandle, null, null); return; } mTable.Allow(mHostAndPort, privateKeyBytes, chainBytes); mBrowserFrame.nativeSslClientCert(mHandle, privateKeyBytes, chainBytes); } /** * Igore the request for now, the user may be prompted again. */ public void ignore() { mBrowserFrame.nativeSslClientCert(mHandle, null, null); } /** * Cancel this request, remember the users negative choice. */ public void cancel() { mTable.Deny(mHostAndPort); mBrowserFrame.nativeSslClientCert(mHandle, null, null); } }
core/java/android/webkit/SslCertLookupTable.java +2 −2 Original line number Diff line number Diff line Loading @@ -19,11 +19,11 @@ package android.webkit; import android.os.Bundle; import android.net.http.SslError; /* /** * A simple class to store the wrong certificates that user is aware but * chose to proceed. */ class SslCertLookupTable { final class SslCertLookupTable { private static SslCertLookupTable sTable; private final Bundle table; Loading
core/java/android/webkit/SslClientCertLookupTable.java 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * A simple class to store client certificates that user has chosen. */ final class SslClientCertLookupTable { private static SslClientCertLookupTable sTable; private final Map<String, byte[]> privateKeys; private final Map<String, byte[][]> certificateChains; private final Set<String> denied; public static synchronized SslClientCertLookupTable getInstance() { if (sTable == null) { sTable = new SslClientCertLookupTable(); } return sTable; } private SslClientCertLookupTable() { privateKeys = new HashMap<String, byte[]>(); certificateChains = new HashMap<String, byte[][]>(); denied = new HashSet<String>(); } public void Allow(String host_and_port, byte[] privateKey, byte[][] chain) { privateKeys.put(host_and_port, privateKey); certificateChains.put(host_and_port, chain); denied.remove(host_and_port); } public void Deny(String host_and_port) { privateKeys.remove(host_and_port); certificateChains.remove(host_and_port); denied.add(host_and_port); } public boolean IsAllowed(String host_and_port) { return privateKeys.containsKey(host_and_port); } public boolean IsDenied(String host_and_port) { return denied.contains(host_and_port); } public byte[] PrivateKey(String host_and_port) { return privateKeys.get(host_and_port); } public byte[][] CertificateChain(String host_and_port) { return certificateChains.get(host_and_port); } }