Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1391)

Unified Diff: android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java

Issue 235563005: Add client cert support to android_webview (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: revert unintended file addition Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
index 66e4f1ec9522047bf983c2461f4f653f47352712..5e1eb83803def1b02baf2a7acfc9550de5639edf 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java
@@ -6,10 +6,21 @@ package org.chromium.android_webview;
import android.net.http.SslCertificate;
import android.net.http.SslError;
+import android.util.Log;
import android.webkit.ValueCallback;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
+import org.chromium.net.AndroidPrivateKey;
+import org.chromium.net.DefaultAndroidKeyStore;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
/**
* This class handles the JNI communication logic for the the AwContentsClient class.
@@ -20,16 +31,81 @@ import org.chromium.base.JNINamespace;
*/
@JNINamespace("android_webview")
public class AwContentsClientBridge {
+ static final String TAG = "AwContentsClientBridge";
+
+ private static final DefaultAndroidKeyStore sLocalKeyStore =
boliu 2014/04/14 23:56:04 lazy? Make AwBrowserContext own this?
sgurun-gerrit only 2014/04/15 23:40:03 Done.
+ new DefaultAndroidKeyStore();
private AwContentsClient mClient;
// The native peer of this object.
private long mNativeContentsClientBridge;
+ // Used for mocking this class in tests.
+ protected AwContentsClientBridge() { }
+
public AwContentsClientBridge(AwContentsClient client) {
assert client != null;
mClient = client;
}
+ /**
+ * Callback to communicate clientcertificaterequest back to the AwContentsClientBridge.
+ * The public methods should be called on UI thread.
+ */
+ public class ClientCertificateRequestCallback {
+
+ // We have the ownership of the native response object.
+ long mNativePtr;
boliu 2014/04/14 23:56:04 private?
sgurun-gerrit only 2014/04/15 23:40:03 Done.
+ String mHost;
+ int mPort;
+
+ public ClientCertificateRequestCallback(long nativePtr, String host, int port) {
+ mNativePtr = nativePtr;
boliu 2014/04/14 23:56:04 Do we leak if client ignores calblack and this obj
sgurun-gerrit only 2014/04/15 23:40:03 correct, but client will have a lot bigger problem
+ mHost = host;
+ mPort = port;
+ }
+
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain) {
+ ThreadUtils.assertOnUiThread();
+ AndroidPrivateKey key = sLocalKeyStore.createKey(privateKey);
+
+ if (key == null || chain == null || chain.length == 0) {
+ Log.w(TAG, "Empty client certificate chain?");
+ provideResponse(null, null);
+ return;
+ }
+ // Encode the certificate chain.
+ byte[][] encodedChain = new byte[chain.length][];
+ try {
+ for (int i = 0; i < chain.length; ++i) {
+ encodedChain[i] = chain[i].getEncoded();
+ }
+ } catch (CertificateEncodingException e) {
+ Log.w(TAG, "Could not retrieve encoded certificate chain: " + e);
+ provideResponse(null, null);
+ return;
+ }
+ ClientCertLookupTable.getInstance().allow(mHost, mPort, key, encodedChain);
+ provideResponse(key, encodedChain);
+ }
+
+ public void ignore() {
+ ThreadUtils.assertOnUiThread();
+ provideResponse(null, null);
+ }
+
+ public void cancel() {
+ ThreadUtils.assertOnUiThread();
+ ClientCertLookupTable.getInstance().deny(mHost, mPort);
+ provideResponse(null, null);
+ }
+
+ private void provideResponse(AndroidPrivateKey androidKey, byte[][] certChain) {
+ nativeProvideClientCertificateResponse(mNativeContentsClientBridge, mNativePtr,
+ certChain, androidKey);
+ }
+ }
+
// Used by the native peer to set/reset a weak ref to the native peer.
@CalledByNative
private void setNativeContentsClientBridge(long nativeContentsClientBridge) {
@@ -66,6 +142,46 @@ public class AwContentsClientBridge {
nativeProceedSslError(mNativeContentsClientBridge, proceed, id);
}
+ // Intentionally not private for testing the native peer of this class.
+ @CalledByNative
+ protected boolean selectClientCertificate(final long nativePtr, final String[] keyTypes,
+ byte[][] encodedPrincipals, final String host, final int port) {
+
boliu 2014/04/14 23:56:04 nit: remove blank line
sgurun-gerrit only 2014/04/15 23:40:03 Done.
+ ClientCertLookupTable table = ClientCertLookupTable.getInstance();
+ ClientCertLookupTable.Cert cert = table.getCertData(host, port);
boliu 2014/04/14 23:56:04 This doesn't need to be keyed by keyTypes/encodedP
sgurun-gerrit only 2014/04/15 23:40:03 Encodedprincipals are not that important since the
+ if (cert != null) {
+ // we have taken the ownership of the native object
boliu 2014/04/14 23:56:04 nit: Capitalize first word and period at end.
sgurun-gerrit only 2014/04/15 23:40:03 Done.
+ nativeProvideClientCertificateResponse(mNativeContentsClientBridge, nativePtr,
+ cert.certChain, cert.privateKey);
+ return true;
+ } else if (table.isDenied(host, port)) {
+ // we have taken the ownership of the native object
+ nativeProvideClientCertificateResponse(mNativeContentsClientBridge, nativePtr,
+ null, null);
+ return true;
+ }
+
+ // Build the list of principals from encoded versions.
+ Principal[] principals = null;
+ if (encodedPrincipals.length > 0) {
+ principals = new X500Principal[encodedPrincipals.length];
+ try {
+ for (int n = 0; n < encodedPrincipals.length; n++) {
+ principals[n] = new X500Principal(encodedPrincipals[n]);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while decoding issuers list: " + e);
+ return false;
+ }
+ }
+
+ final ClientCertificateRequestCallback callback =
+ new ClientCertificateRequestCallback(nativePtr, host, port);
+ // We've taken the ownership of the native ssl request object.
+ mClient.onReceivedClientCertRequest(callback, keyTypes, principals, host, port);
+ return true;
+ }
+
@CalledByNative
private void handleJsAlert(String url, String message, int id) {
JsResultHandler handler = new JsResultHandler(this, id);
@@ -110,6 +226,8 @@ public class AwContentsClientBridge {
//--------------------------------------------------------------------------------------------
private native void nativeProceedSslError(long nativeAwContentsClientBridge, boolean proceed,
int id);
+ private native void nativeProvideClientCertificateResponse(long nativeAwContentsClientBridge,
+ long nativePtr, byte[][] certChain, AndroidPrivateKey androidKey);
private native void nativeConfirmJsResult(long nativeAwContentsClientBridge, int id,
String prompt);

Powered by Google App Engine
This is Rietveld 408576698