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

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

Issue 1474603004: Remove Android support for out-of-process KeyStores (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser; 5 package org.chromium.chrome.browser;
6 6
7 import android.app.Activity; 7 import android.app.Activity;
8 import android.content.ActivityNotFoundException; 8 import android.content.ActivityNotFoundException;
9 import android.content.Context; 9 import android.content.Context;
10 import android.content.DialogInterface; 10 import android.content.DialogInterface;
11 import android.content.DialogInterface.OnClickListener; 11 import android.content.DialogInterface.OnClickListener;
12 import android.os.AsyncTask; 12 import android.os.AsyncTask;
13 import android.security.KeyChain; 13 import android.security.KeyChain;
14 import android.security.KeyChainAliasCallback; 14 import android.security.KeyChainAliasCallback;
15 import android.security.KeyChainException; 15 import android.security.KeyChainException;
16 import android.support.v7.app.AlertDialog; 16 import android.support.v7.app.AlertDialog;
17 import android.util.Log; 17 import android.util.Log;
18 18
19 import org.chromium.base.ThreadUtils; 19 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.VisibleForTesting; 20 import org.chromium.base.VisibleForTesting;
21 import org.chromium.base.annotations.CalledByNative; 21 import org.chromium.base.annotations.CalledByNative;
22 import org.chromium.base.annotations.JNINamespace; 22 import org.chromium.base.annotations.JNINamespace;
23 import org.chromium.chrome.R; 23 import org.chromium.chrome.R;
24 import org.chromium.chrome.browser.smartcard.PKCS11AuthenticationManager;
25 import org.chromium.net.AndroidPrivateKey; 24 import org.chromium.net.AndroidPrivateKey;
26 import org.chromium.net.DefaultAndroidKeyStore; 25 import org.chromium.net.DefaultAndroidKeyStore;
27 import org.chromium.ui.base.WindowAndroid; 26 import org.chromium.ui.base.WindowAndroid;
28 27
29 import java.security.Principal; 28 import java.security.Principal;
30 import java.security.cert.CertificateEncodingException; 29 import java.security.cert.CertificateEncodingException;
31 import java.security.cert.X509Certificate; 30 import java.security.cert.X509Certificate;
32 31
33 import javax.security.auth.x500.X500Principal; 32 import javax.security.auth.x500.X500Principal;
34 33
35 /** 34 /**
36 * Handles selection of client certificate on the Java side. This class is respo nsible for selection 35 * Handles selection of client certificate on the Java side. This class is respo nsible for selection
37 * of the client certificate to be used for authentication and retrieval of the private key and full 36 * of the client certificate to be used for authentication and retrieval of the private key and full
38 * certificate chain. 37 * certificate chain.
39 * 38 *
40 * The entry point is selectClientCertificate() and it will be called on the UI thread. Then the 39 * The entry point is selectClientCertificate() and it will be called on the UI thread. Then the
41 * class will construct and run an appropriate CertAsyncTask, that will run in b ackground, and 40 * class will construct and run an appropriate CertAsyncTask, that will run in b ackground, and
42 * finally pass the results back to the UI thread, which will return to the nati ve code. 41 * finally pass the results back to the UI thread, which will return to the nati ve code.
43 */ 42 */
44 @JNINamespace("chrome::android") 43 @JNINamespace("chrome::android")
45 public class SSLClientCertificateRequest { 44 public class SSLClientCertificateRequest {
46 static final String TAG = "SSLClientCertificateRequest"; 45 static final String TAG = "SSLClientCertificateRequest";
47 46
48 private static final DefaultAndroidKeyStore sLocalKeyStore = 47 private static final DefaultAndroidKeyStore sLocalKeyStore =
49 new DefaultAndroidKeyStore(); 48 new DefaultAndroidKeyStore();
Yaron 2015/11/25 16:24:31 Any reason not to remove the AndroidKeyStore inter
davidben 2015/11/25 17:48:14 +1 I believe this is the CL that introduced it: h
Changwan Ryu 2015/11/26 02:52:11 No need to keep this. Thanks for the pointer. Done
50 49
51 /** 50 /**
52 * Common implementation for anynchronous task of handling the certificate r equest. This 51 * Implementation for anynchronous task of handling the certificate request. This
53 * AsyncTask uses the abstract methods to retrieve the authentication materi al from a 52 * AsyncTask retrieve the authentication material from the system key store.
54 * generalized key store. The key store is accessed in background, as the AP Is being exercised 53 * The key store is accessed in background, as the APIs being exercised
55 * may be blocking. The results are posted back to native on the UI thread. 54 * may be blocking. The results are posted back to native on the UI thread.
56 */ 55 */
57 abstract static class CertAsyncTask extends AsyncTask<Void, Void, Void> { 56 private static class CertAsyncTaskKeyChain extends AsyncTask<Void, Void, Voi d> {
58 // These fields will store the results computed in doInBackground so tha t they can be posted 57 // These fields will store the results computed in doInBackground so tha t they can be posted
59 // back in onPostExecute. 58 // back in onPostExecute.
60 private byte[][] mEncodedChain; 59 private byte[][] mEncodedChain;
61 private AndroidPrivateKey mAndroidPrivateKey; 60 private AndroidPrivateKey mAndroidPrivateKey;
62 61
63 // Pointer to the native certificate request needed to return the result s. 62 // Pointer to the native certificate request needed to return the result s.
64 private final long mNativePtr; 63 private final long mNativePtr;
65 64
66 CertAsyncTask(long nativePtr) { 65 final Context mContext;
66 final String mAlias;
67
68 CertAsyncTaskKeyChain(Context context, long nativePtr, String alias) {
67 mNativePtr = nativePtr; 69 mNativePtr = nativePtr;
70 mContext = context;
71 assert alias != null;
72 mAlias = alias;
68 } 73 }
69 74
70 // These overriden methods will be used to access the key store.
71 abstract String getAlias();
72 abstract AndroidPrivateKey getPrivateKey(String alias);
73 abstract X509Certificate[] getCertificateChain(String alias);
74
75 @Override 75 @Override
76 protected Void doInBackground(Void... params) { 76 protected Void doInBackground(Void... params) {
77 String alias = getAlias(); 77 String alias = getAlias();
78 if (alias == null) return null; 78 if (alias == null) return null;
79 79
80 AndroidPrivateKey key = getPrivateKey(alias); 80 AndroidPrivateKey key = getPrivateKey(alias);
81 X509Certificate[] chain = getCertificateChain(alias); 81 X509Certificate[] chain = getCertificateChain(alias);
82 82
83 if (key == null || chain == null || chain.length == 0) { 83 if (key == null || chain == null || chain.length == 0) {
84 Log.w(TAG, "Empty client certificate chain?"); 84 Log.w(TAG, "Empty client certificate chain?");
(...skipping 14 matching lines...) Expand all
99 mEncodedChain = encodedChain; 99 mEncodedChain = encodedChain;
100 mAndroidPrivateKey = key; 100 mAndroidPrivateKey = key;
101 return null; 101 return null;
102 } 102 }
103 103
104 @Override 104 @Override
105 protected void onPostExecute(Void result) { 105 protected void onPostExecute(Void result) {
106 ThreadUtils.assertOnUiThread(); 106 ThreadUtils.assertOnUiThread();
107 nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mAndroidP rivateKey); 107 nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mAndroidP rivateKey);
108 } 108 }
109 }
110 109
111 /** Implementation of CertAsyncTask for the system KeyChain API. */ 110 private String getAlias() {
112 private static class CertAsyncTaskKeyChain extends CertAsyncTask {
113 final Context mContext;
114 final String mAlias;
115
116 CertAsyncTaskKeyChain(Context context, long nativePtr, String alias) {
117 super(nativePtr);
118 mContext = context;
119 assert alias != null;
120 mAlias = alias;
121 }
122
123 @Override
124 String getAlias() {
125 return mAlias; 111 return mAlias;
126 } 112 }
127 113
128 @Override 114 private AndroidPrivateKey getPrivateKey(String alias) {
129 AndroidPrivateKey getPrivateKey(String alias) {
130 try { 115 try {
131 return sLocalKeyStore.createKey(KeyChain.getPrivateKey(mContext, alias)); 116 return sLocalKeyStore.createKey(KeyChain.getPrivateKey(mContext, alias));
132 } catch (KeyChainException e) { 117 } catch (KeyChainException e) {
133 Log.w(TAG, "KeyChainException when looking for '" + alias + "' c ertificate"); 118 Log.w(TAG, "KeyChainException when looking for '" + alias + "' c ertificate");
134 return null; 119 return null;
135 } catch (InterruptedException e) { 120 } catch (InterruptedException e) {
136 Log.w(TAG, "InterruptedException when looking for '" + alias + " 'certificate"); 121 Log.w(TAG, "InterruptedException when looking for '" + alias + " 'certificate");
137 return null; 122 return null;
138 } 123 }
139 } 124 }
140 125
141 @Override 126 private X509Certificate[] getCertificateChain(String alias) {
142 X509Certificate[] getCertificateChain(String alias) {
143 try { 127 try {
144 return KeyChain.getCertificateChain(mContext, alias); 128 return KeyChain.getCertificateChain(mContext, alias);
145 } catch (KeyChainException e) { 129 } catch (KeyChainException e) {
146 Log.w(TAG, "KeyChainException when looking for '" + alias + "' c ertificate"); 130 Log.w(TAG, "KeyChainException when looking for '" + alias + "' c ertificate");
147 return null; 131 return null;
148 } catch (InterruptedException e) { 132 } catch (InterruptedException e) {
149 Log.w(TAG, "InterruptedException when looking for '" + alias + " 'certificate"); 133 Log.w(TAG, "InterruptedException when looking for '" + alias + " 'certificate");
150 return null; 134 return null;
151 } 135 }
152 } 136 }
153 } 137 }
154 138
155 /** Implementation of CertAsyncTask for use with a PKCS11-backed KeyStore. * /
156 private static class CertAsyncTaskPKCS11 extends CertAsyncTask {
157 private final PKCS11AuthenticationManager mPKCS11AuthManager;
158 private final String mHostName;
159 private final int mPort;
160
161 CertAsyncTaskPKCS11(long nativePtr, String hostName, int port,
162 PKCS11AuthenticationManager pkcs11CardAuthManager) {
163 super(nativePtr);
164 mHostName = hostName;
165 mPort = port;
166 mPKCS11AuthManager = pkcs11CardAuthManager;
167 }
168
169 @Override
170 String getAlias() {
171 return mPKCS11AuthManager.getClientCertificateAlias(mHostName, mPort );
172 }
173
174 @Override
175 AndroidPrivateKey getPrivateKey(String alias) {
176 return mPKCS11AuthManager.getPrivateKey(alias);
177 }
178
179 @Override
180 X509Certificate[] getCertificateChain(String alias) {
181 return mPKCS11AuthManager.getCertificateChain(alias);
182 }
183 }
184
185 /** 139 /**
186 * The system KeyChain API will call us back on the alias() method, passing the alias of the 140 * The system KeyChain API will call us back on the alias() method, passing the alias of the
187 * certificate selected by the user. 141 * certificate selected by the user.
188 */ 142 */
189 private static class KeyChainCertSelectionCallback implements KeyChainAliasC allback { 143 private static class KeyChainCertSelectionCallback implements KeyChainAliasC allback {
190 private final long mNativePtr; 144 private final long mNativePtr;
191 private final Context mContext; 145 private final Context mContext;
192 146
193 KeyChainCertSelectionCallback(Context context, long nativePtr) { 147 KeyChainCertSelectionCallback(Context context, long nativePtr) {
194 mContext = context; 148 mContext = context;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 /** 222 /**
269 * Builds and shows the dialog. 223 * Builds and shows the dialog.
270 */ 224 */
271 public void show() { 225 public void show() {
272 final AlertDialog.Builder builder = 226 final AlertDialog.Builder builder =
273 new AlertDialog.Builder(mActivity, R.style.AlertDialogTheme) ; 227 new AlertDialog.Builder(mActivity, R.style.AlertDialogTheme) ;
274 builder.setTitle(R.string.client_cert_unsupported_title) 228 builder.setTitle(R.string.client_cert_unsupported_title)
275 .setMessage(R.string.client_cert_unsupported_message) 229 .setMessage(R.string.client_cert_unsupported_message)
276 .setNegativeButton(R.string.close, 230 .setNegativeButton(R.string.close,
277 new OnClickListener() { 231 new OnClickListener() {
232 @Override
278 public void onClick(DialogInterface dialog, int which) { 233 public void onClick(DialogInterface dialog, int which) {
279 // Do nothing 234 // Do nothing
280 } 235 }
281 }); 236 });
282 builder.show(); 237 builder.show();
283 } 238 }
284 } 239 }
285 240
286 /** 241 /**
287 * Create a new asynchronous request to select a client certificate. 242 * Create a new asynchronous request to select a client certificate.
(...skipping 26 matching lines...) Expand all
314 try { 269 try {
315 for (int n = 0; n < encodedPrincipals.length; n++) { 270 for (int n = 0; n < encodedPrincipals.length; n++) {
316 principals[n] = new X500Principal(encodedPrincipals[n]); 271 principals[n] = new X500Principal(encodedPrincipals[n]);
317 } 272 }
318 } catch (Exception e) { 273 } catch (Exception e) {
319 Log.w(TAG, "Exception while decoding issuers list: " + e); 274 Log.w(TAG, "Exception while decoding issuers list: " + e);
320 return false; 275 return false;
321 } 276 }
322 } 277 }
323 278
324 final Principal[] principalsForCallback = principals; 279 KeyChainCertSelectionCallback callback =
325 // Certificate for client authentication can be obtained either from the system store of 280 new KeyChainCertSelectionCallback(activity.getApplicationContext (),
326 // from a smart card (if available). 281 nativePtr);
327 Runnable useSystemStore = new Runnable() { 282 KeyChainCertSelectionWrapper keyChain = new KeyChainCertSelectionWrapper (activity,
328 @Override 283 callback, keyTypes, principals, hostName, port, null);
329 public void run() { 284 maybeShowCertSelection(keyChain, callback,
330 KeyChainCertSelectionCallback callback = 285 new CertSelectionFailureDialog(activity));
331 new KeyChainCertSelectionCallback(activity.getApplicatio nContext(),
332 nativePtr);
333 KeyChainCertSelectionWrapper keyChain = new KeyChainCertSelectio nWrapper(activity,
334 callback, keyTypes, principalsForCallback, hostName, por t, null);
335 maybeShowCertSelection(keyChain, callback,
336 new CertSelectionFailureDialog(activity));
337 }
338 };
339
340 final Context appContext = activity.getApplicationContext();
341 final PKCS11AuthenticationManager smartCardAuthManager =
342 ((ChromeApplication) appContext).getPKCS11AuthenticationManager( );
343 if (smartCardAuthManager.isPKCS11AuthEnabled()) {
344 // Smart card support is available, prompt the user whether to use i t or Android system
345 // store.
346 Runnable useSmartCard = new Runnable() {
347 @Override
348 public void run() {
349 new CertAsyncTaskPKCS11(nativePtr, hostName, port,
350 smartCardAuthManager).execute();
351 }
352 };
353 Runnable cancelRunnable = new Runnable() {
354 @Override
355 public void run() {
356 // We took ownership of the request, need to delete it.
357 nativeOnSystemRequestCompletion(nativePtr, null, null);
358 }
359 };
360
361 KeyStoreSelectionDialog selectionDialog = new KeyStoreSelectionDialo g(
Yaron 2015/11/25 16:24:31 You can remove this class too and the strings adde
Changwan Ryu 2015/11/26 02:52:11 Done.
362 useSystemStore, useSmartCard, cancelRunnable);
363 selectionDialog.show(activity.getFragmentManager(), null);
364 } else {
365 // Smart card support is not available, use the system store uncondi tionally.
366 useSystemStore.run();
367 }
368 286
369 // We've taken ownership of the native ssl request object. 287 // We've taken ownership of the native ssl request object.
370 return true; 288 return true;
371 } 289 }
372 290
373 /** 291 /**
374 * Attempt to show the certificate selection dialog and shows the provided 292 * Attempt to show the certificate selection dialog and shows the provided
375 * CertSelectionFailureDialog if the platform's cert selection activity can' t be found. 293 * CertSelectionFailureDialog if the platform's cert selection activity can' t be found.
376 */ 294 */
377 @VisibleForTesting 295 @VisibleForTesting
(...skipping 16 matching lines...) Expand all
394 Log.d(TAG, "ClientCertificatesChanged!"); 312 Log.d(TAG, "ClientCertificatesChanged!");
395 nativeNotifyClientCertificatesChangedOnIOThread(); 313 nativeNotifyClientCertificatesChangedOnIOThread();
396 } 314 }
397 315
398 private static native void nativeNotifyClientCertificatesChangedOnIOThread() ; 316 private static native void nativeNotifyClientCertificatesChangedOnIOThread() ;
399 317
400 // Called to pass request results to native side. 318 // Called to pass request results to native side.
401 private static native void nativeOnSystemRequestCompletion( 319 private static native void nativeOnSystemRequestCompletion(
402 long requestPtr, byte[][] certChain, AndroidPrivateKey androidKey); 320 long requestPtr, byte[][] certChain, AndroidPrivateKey androidKey);
403 } 321 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698