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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java

Issue 12374020: Add Android support for SSL client authentication to the browser layer. (Closed) Base URL: http://git.chromium.org/chromium/src.git@client-cert-test
Patch Set: optimizations Created 7 years, 9 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser;
6
7 import java.security.cert.CertificateEncodingException;
8 import java.security.cert.X509Certificate;
9 import java.security.Principal;
10 import java.security.PrivateKey;
11 import javax.security.auth.x500.X500Principal;
12
13 import android.app.Activity;
14 import android.content.Context;
15 import android.os.AsyncTask;
16 import android.security.KeyChain;
17 import android.security.KeyChainAliasCallback;
18 import android.security.KeyChainException;
19 import android.util.Log;
20
21 import org.chromium.base.ActivityStatus;
22 import org.chromium.base.CalledByNative;
23 import org.chromium.base.JNINamespace;
24 import org.chromium.base.ThreadUtils;
25
26 @JNINamespace("chrome::android")
27 public class SSLClientCertificateRequest extends AsyncTask<Void, Void, Void>
28 implements KeyChainAliasCallback {
29
30 static final String TAG = "SSLClientCertificateRequest";
31
32 // ClientCertRequest models an asynchronous client certificate request
33 // on the Dalvik side. There is a matching C++ ClientCertRequest
34 // class that has _slightly_ different lifecycles (e.g. if a Tab
35 // is closed while an asynchronous request is still pending, the native
36 // C++ class will be deleted, but the Java one must persist until the
37 // system sends its answer to the activity).
38 //
39 // Each request must be started from the UI thread, and the system
40 // will answer the KeyChain.choosePrivateKeyAlias() call with a
41 // private key alias string, which can be used to call
42 // KeyChain.getCertificateChain() and KeyChain.getPrivateKey(),
43 // however these functions are blocking and can't be called on the
44 // UI thread.
45 //
46 // To solve this, start an AsyncTask when an alias is received.
47 // it will retrieve the certificate chain and private key in the
48 // background, then later send the result back to the UI thread.
49 //
50 private final int mNativePtr;
51 private String mAlias;
52 private byte[][] mEncodedChain;
53 private PrivateKey mPrivateKey;
54
55 private SSLClientCertificateRequest(int nativePtr) {
56 mNativePtr = nativePtr;
57 mAlias = null;
58 mEncodedChain = null;
59 mPrivateKey = null;
60 }
61
62 // KeyChainAliasCallback implementation
63 @Override
64 public void alias(String alias) {
65 if (alias == null) {
66 // No certificate was selected.
67 onPostExecute(null);
68 } else {
69 mAlias = alias;
70 // Launch background thread.
71 execute();
72 }
73 }
74
75 @Override
76 protected Void doInBackground(Void... params) {
77 // Executed in a background thread, can call blocking APIs.
78 X509Certificate[] chain = null;
79 PrivateKey key = null;
80 Context context = ActivityStatus.getActivity().getApplicationContext();
81 try {
82 key = KeyChain.getPrivateKey(context, mAlias);
83 chain = KeyChain.getCertificateChain(context, mAlias);
84 } catch (KeyChainException e) {
85 Log.w(TAG, "KeyChainException when looking for '" + mAlias + "' cert ificate");
86 return null;
87 } catch (InterruptedException e) {
88 Log.w(TAG, "InterruptedException when looking for '" + mAlias + "'ce rtificate");
89 return null;
90 }
91
92 if (key == null || chain == null || chain.length == 0) {
93 Log.w(TAG, "Empty client certificate chain?");
94 return null;
95 }
96
97 // Get the encoded certificate chain.
98 byte[][] encoded_chain = new byte[chain.length][];
99 try {
100 for (int i = 0; i < chain.length; ++i) {
101 encoded_chain[i] = chain[i].getEncoded();
102 }
103 } catch (CertificateEncodingException e) {
104 Log.w(TAG, "Could not retrieve encoded certificate chain: " + e);
105 return null;
106 }
107
108 mEncodedChain = encoded_chain;
109 mPrivateKey = key;
110 return null;
111 }
112
113 @Override
114 protected void onPostExecute(Void result) {
115 // Back to the UI thread.
116 nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mPrivateKey);
117 }
118
119
120 /**
121 * Create a new asynchronous request to select a client certificate.
122 *
123 * @param request_id The unique numerical id for the request.
124 * @param key_types The list of supported key exchange types.
125 * @param encoded_principals The list of CA DistinguishedNames.
126 * @param host_name The server host name is available (empty otherwise).
127 * @param port The server port if available (0 otherwise).
128 * @return true on success.
129 */
130 @CalledByNative
131 static private boolean selectClientCertificate(int nativePtr,
132 String[] key_types,
133 byte[][] encoded_principals,
134 String host_name,
135 int port) {
136 ThreadUtils.assertOnUiThread();
137
138 Activity activity = ActivityStatus.getActivity();
139 if (activity == null) {
140 Log.w(TAG, "No active Chromium main activity!?");
141 return false;
142 }
143
144 // Build the list of principals from encoded versions.
145 Principal[] principals = null;
146 if (encoded_principals.length > 0) {
147 principals = new X500Principal[encoded_principals.length];
148 try {
149 for (int n = 0; n < encoded_principals.length; n++) {
150 principals[n] = new X500Principal(encoded_principals[n]);
151 }
152 } catch (Exception e) {
153 // Bail on error.
154 Log.w(TAG, "Exception while decoding issuers list: " + e);
155 return false;
156 }
157 }
158
159 // All good, create new request, add it to our list and launch
160 // the certificate selection activity.
161 SSLClientCertificateRequest request = new SSLClientCertificateRequest(na tivePtr);
162
163 KeyChain.choosePrivateKeyAlias(activity, request, key_types,
164 principals, host_name, port, null);
165 return true;
166 }
167
168 // Called to pass request results to native side.
169 private static native void nativeOnSystemRequestCompletion(
170 int nativeSSLClientCertificateRequest,
171 byte[][] certChain,
172 PrivateKey privateKey);
173 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698