diff options
30 files changed, 295 insertions, 1001 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java index 9925882..244dfed 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserContext.java @@ -8,7 +8,6 @@ import android.content.Context; import android.content.SharedPreferences; import org.chromium.content.browser.ContentViewStatics; -import org.chromium.net.DefaultAndroidKeyStore; /** * Java side of the Browser Context: contains all the java side objects needed to host one @@ -20,12 +19,11 @@ import org.chromium.net.DefaultAndroidKeyStore; public class AwBrowserContext { private static final String HTTP_AUTH_DATABASE_FILE = "http_auth.db"; - private SharedPreferences mSharedPreferences; + private final SharedPreferences mSharedPreferences; private AwGeolocationPermissions mGeolocationPermissions; private AwFormDatabase mFormDatabase; private HttpAuthDatabase mHttpAuthDatabase; - private DefaultAndroidKeyStore mLocalKeyStore; private AwMessagePortService mMessagePortService; public AwBrowserContext(SharedPreferences sharedPreferences, Context applicationContext) { @@ -53,13 +51,6 @@ public class AwBrowserContext { return mHttpAuthDatabase; } - public DefaultAndroidKeyStore getKeyStore() { - if (mLocalKeyStore == null) { - mLocalKeyStore = new DefaultAndroidKeyStore(); - } - return mLocalKeyStore; - } - public AwMessagePortService getMessagePortService() { if (mMessagePortService == null) { mMessagePortService = new AwMessagePortService(); diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index fb2391a..ca80b7e 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -710,7 +710,7 @@ public class AwContents implements SmartClipProvider, mWebContentsDelegate = new AwWebContentsDelegateAdapter( this, contentsClient, mContentViewClient, mContext, mContainerView); mContentsClientBridge = new AwContentsClientBridge(mContext, contentsClient, - mBrowserContext.getKeyStore(), AwContentsStatics.getClientCertLookupTable()); + AwContentsStatics.getClientCertLookupTable()); mZoomControls = new AwZoomControls(this); mBackgroundThreadClient = new BackgroundThreadClientImpl(); mIoThreadClient = new IoThreadClientImpl(); 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 c1b03a1..efca3d0 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientBridge.java @@ -13,8 +13,6 @@ import android.webkit.ValueCallback; import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; -import org.chromium.net.AndroidPrivateKey; -import org.chromium.net.DefaultAndroidKeyStore; import java.security.Principal; import java.security.PrivateKey; @@ -39,23 +37,18 @@ public class AwContentsClientBridge { // The native peer of this object. private long mNativeContentsClientBridge; - private DefaultAndroidKeyStore mLocalKeyStore; - - private ClientCertLookupTable mLookupTable; + private final ClientCertLookupTable mLookupTable; // Used for mocking this class in tests. - protected AwContentsClientBridge(DefaultAndroidKeyStore keyStore, - ClientCertLookupTable table) { - mLocalKeyStore = keyStore; + protected AwContentsClientBridge(ClientCertLookupTable table) { mLookupTable = table; } public AwContentsClientBridge(Context context, AwContentsClient client, - DefaultAndroidKeyStore keyStore, ClientCertLookupTable table) { + ClientCertLookupTable table) { assert client != null; mContext = context; mClient = client; - mLocalKeyStore = keyStore; mLookupTable = table; } @@ -67,9 +60,9 @@ public class AwContentsClientBridge { */ public class ClientCertificateRequestCallback { - private int mId; - private String mHost; - private int mPort; + private final int mId; + private final String mHost; + private final int mPort; private boolean mIsCalled; public ClientCertificateRequestCallback(int id, String host, int port) { @@ -109,9 +102,7 @@ public class AwContentsClientBridge { private void proceedOnUiThread(PrivateKey privateKey, X509Certificate[] chain) { checkIfCalled(); - AndroidPrivateKey key = mLocalKeyStore.createKey(privateKey); - - if (key == null || chain == null || chain.length == 0) { + if (privateKey == null || chain == null || chain.length == 0) { Log.w(TAG, "Empty client certificate chain?"); provideResponse(null, null); return; @@ -127,8 +118,8 @@ public class AwContentsClientBridge { provideResponse(null, null); return; } - mLookupTable.allow(mHost, mPort, key, encodedChain); - provideResponse(key, encodedChain); + mLookupTable.allow(mHost, mPort, privateKey, encodedChain); + provideResponse(privateKey, encodedChain); } private void ignoreOnUiThread() { @@ -149,10 +140,10 @@ public class AwContentsClientBridge { mIsCalled = true; } - private void provideResponse(AndroidPrivateKey androidKey, byte[][] certChain) { + private void provideResponse(PrivateKey privateKey, byte[][] certChain) { if (mNativeContentsClientBridge == 0) return; nativeProvideClientCertificateResponse(mNativeContentsClientBridge, mId, - certChain, androidKey); + certChain, privateKey); } } @@ -275,7 +266,7 @@ public class AwContentsClientBridge { private native void nativeProceedSslError(long nativeAwContentsClientBridge, boolean proceed, int id); private native void nativeProvideClientCertificateResponse(long nativeAwContentsClientBridge, - int id, byte[][] certChain, AndroidPrivateKey androidKey); + int id, byte[][] certChain, PrivateKey androidKey); private native void nativeConfirmJsResult(long nativeAwContentsClientBridge, int id, String prompt); diff --git a/android_webview/java/src/org/chromium/android_webview/ClientCertLookupTable.java b/android_webview/java/src/org/chromium/android_webview/ClientCertLookupTable.java index 88e6ed1..388f19d 100644 --- a/android_webview/java/src/org/chromium/android_webview/ClientCertLookupTable.java +++ b/android_webview/java/src/org/chromium/android_webview/ClientCertLookupTable.java @@ -4,8 +4,7 @@ package org.chromium.android_webview; -import org.chromium.net.AndroidPrivateKey; - +import java.security.PrivateKey; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -22,9 +21,9 @@ public class ClientCertLookupTable { * A container for the certificate data. */ public static class Cert { - AndroidPrivateKey mPrivateKey; + PrivateKey mPrivateKey; byte[][] mCertChain; - public Cert(AndroidPrivateKey privateKey, byte[][] certChain) { + public Cert(PrivateKey privateKey, byte[][] certChain) { this.mPrivateKey = privateKey; byte[][] newChain = new byte[certChain.length][]; for (int i = 0; i < certChain.length; i++) { @@ -48,7 +47,7 @@ public class ClientCertLookupTable { mDenieds = new HashSet<String>(); } - public void allow(String host, int port, AndroidPrivateKey privateKey, byte[][] chain) { + public void allow(String host, int port, PrivateKey privateKey, byte[][] chain) { String host_and_port = hostAndPort(host, port); mCerts.put(host_and_port, new Cert(privateKey, chain)); mDenieds.remove(host_and_port); diff --git a/android_webview/native/aw_contents_client_bridge_unittest.cc b/android_webview/native/aw_contents_client_bridge_unittest.cc index f7a1de8..5f19a52 100644 --- a/android_webview/native/aw_contents_client_bridge_unittest.cc +++ b/android_webview/native/aw_contents_client_bridge_unittest.cc @@ -81,7 +81,7 @@ void AwContentsClientBridgeTest::SetUp() { jbridge_.Reset(env_, Java_MockAwContentsClientBridge_getAwContentsClientBridge(env_).obj()); bridge_.reset(new AwContentsClientBridge(env_, jbridge_.obj())); - selected_cert_ = NULL; + selected_cert_ = nullptr; cert_selected_callbacks_ = 0; cert_request_info_ = new net::SSLCertRequestInfo; } @@ -133,14 +133,14 @@ TEST_F(AwContentsClientBridgeTest, Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()), Java_MockAwContentsClientBridge_createTestCertChain( env_, jbridge_.obj()).obj(), - NULL); + nullptr); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(NULL, selected_cert_); + EXPECT_EQ(nullptr, selected_cert_); EXPECT_EQ(1, cert_selected_callbacks_); } // Verify that ProvideClientCertificateResponse calls the callback with -// NULL parameters when private key is not provided. +// null parameters when private key is not provided. TEST_F(AwContentsClientBridgeTest, TestProvideClientCertificateResponseCallsCallbackOnNullChain) { // Call SelectClientCertificate to create a callback id that mock java object @@ -150,13 +150,10 @@ TEST_F(AwContentsClientBridgeTest, make_scoped_ptr(new TestClientCertificateDelegate(this))); int requestId = Java_MockAwContentsClientBridge_getRequestId(env_, jbridge_.obj()); - bridge_->ProvideClientCertificateResponse(env_, jbridge_.obj(), - requestId, - NULL, - Java_MockAwContentsClientBridge_createTestPrivateKey( - env_, jbridge_.obj()).obj()); + bridge_->ProvideClientCertificateResponse( + env_, jbridge_.obj(), requestId, nullptr, nullptr); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(NULL, selected_cert_); + EXPECT_EQ(nullptr, selected_cert_); EXPECT_EQ(1, cert_selected_callbacks_); } diff --git a/android_webview/unittestjava/src/org/chromium/android_webview/unittest/MockAwContentsClientBridge.java b/android_webview/unittestjava/src/org/chromium/android_webview/unittest/MockAwContentsClientBridge.java index 0be5824..6a03520 100644 --- a/android_webview/unittestjava/src/org/chromium/android_webview/unittest/MockAwContentsClientBridge.java +++ b/android_webview/unittestjava/src/org/chromium/android_webview/unittest/MockAwContentsClientBridge.java @@ -7,9 +7,6 @@ package org.chromium.android_webview.unittest; import org.chromium.android_webview.AwContentsClientBridge; import org.chromium.android_webview.ClientCertLookupTable; import org.chromium.base.annotations.CalledByNative; -import org.chromium.net.AndroidKeyStore; -import org.chromium.net.AndroidPrivateKey; -import org.chromium.net.DefaultAndroidKeyStore; class MockAwContentsClientBridge extends AwContentsClientBridge { @@ -17,7 +14,7 @@ class MockAwContentsClientBridge extends AwContentsClientBridge { private String[] mKeyTypes; public MockAwContentsClientBridge() { - super(new DefaultAndroidKeyStore(), new ClientCertLookupTable()); + super(new ClientCertLookupTable()); } @Override @@ -43,16 +40,6 @@ class MockAwContentsClientBridge extends AwContentsClientBridge { } @CalledByNative - private AndroidPrivateKey createTestPrivateKey() { - return new AndroidPrivateKey() { - @Override - public AndroidKeyStore getKeyStore() { - return null; - } - }; - } - - @CalledByNative private byte[][] createTestCertChain() { return new byte[][]{{1}}; } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index 92bcd1c..f2aee2a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java @@ -82,8 +82,6 @@ import org.chromium.chrome.browser.services.AccountsChangedReceiver; import org.chromium.chrome.browser.services.AndroidEduOwnerCheckCallback; import org.chromium.chrome.browser.services.GoogleServicesManager; import org.chromium.chrome.browser.share.ShareHelper; -import org.chromium.chrome.browser.smartcard.EmptyPKCS11AuthenticationManager; -import org.chromium.chrome.browser.smartcard.PKCS11AuthenticationManager; import org.chromium.chrome.browser.sync.GmsCoreSyncListener; import org.chromium.chrome.browser.sync.SyncController; import org.chromium.chrome.browser.tab.AuthenticatorNavigationInterceptor; @@ -451,8 +449,6 @@ public class ChromeApplication extends ContentApplication { GoogleServicesManager.get(this).onMainActivityStart(); RevenueStats.getInstance(); - getPKCS11AuthenticationManager().initialize(ChromeApplication.this); - mDevToolsServer = new DevToolsServer(DEV_TOOLS_SERVER_SOCKET_PREFIX); mDevToolsServer.setRemoteDebuggingEnabled( true, DevToolsServer.Security.ALLOW_DEBUG_PERMISSION); @@ -597,12 +593,6 @@ public class ChromeApplication extends ContentApplication { return PartnerBrowserCustomizations.isIncognitoDisabled(); } - // TODO(yfriedman): This is too widely available. Plumb this through ChromeNetworkDelegate - // instead. - protected PKCS11AuthenticationManager getPKCS11AuthenticationManager() { - return EmptyPKCS11AuthenticationManager.getInstance(); - } - /** * @return A provider of external estimates. * @param nativePtr Pointer to the native ExternalEstimateProviderAndroid object. diff --git a/chrome/android/java/src/org/chromium/chrome/browser/KeyStoreSelectionDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/KeyStoreSelectionDialog.java deleted file mode 100644 index bf382a1..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/KeyStoreSelectionDialog.java +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser; - -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v7.app.AlertDialog; - -import org.chromium.chrome.R; - -/** - * Client certificate KeyStore selection dialog. When smart card (CAC) support is enabled, this - * dialog allows choosing between (the default) system certificate store and the smart card for - * client authentication. - */ -class KeyStoreSelectionDialog extends DialogFragment { - private static final CharSequence SYSTEM_STORE = "Android"; - - private final Runnable mSystemCallback; - private final Runnable mSmartCardCallback; - private final Runnable mCancelCallback; - - private Runnable mSelectedChoice; - - /** - * Constructor for KeyStore selection dialog. - * - * @param systemCallback Runnable that's invoked when the user selects to use the Android - * system store for authentication - * @param smartCardCallback Runnable that's invoked when the user selects to use the SmartCard - * store for authentication - * @param cancelCallback Runnable that's invoked when the user cancels or closes the dialog. - */ - public KeyStoreSelectionDialog(Runnable systemCallback, Runnable smartCardCallback, - Runnable cancelCallback) { - mSystemCallback = systemCallback; - mSmartCardCallback = smartCardCallback; - mCancelCallback = cancelCallback; - - // Default to SmartCard - mSelectedChoice = mSmartCardCallback; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final CharSequence[] choices = { - getString(R.string.smartcard_certificate_option), - SYSTEM_STORE - }; - AlertDialog.Builder builder = - new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme) - .setTitle(R.string.smartcard_dialog_title) - .setSingleChoiceItems(choices, 0, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - if (choices[id] == SYSTEM_STORE) { - mSelectedChoice = mSystemCallback; - } else { - mSelectedChoice = mSmartCardCallback; - } - } - }) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - mSelectedChoice.run(); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - mCancelCallback.run(); - } - }); - - return builder.create(); - } - - @Override - public void onDismiss(DialogInterface dialog) { - super.onDismiss(dialog); - } -} diff --git a/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java index 6d9fcf3..b26ed61 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/SSLClientCertificateRequest.java @@ -21,12 +21,10 @@ import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; -import org.chromium.chrome.browser.smartcard.PKCS11AuthenticationManager; -import org.chromium.net.AndroidPrivateKey; -import org.chromium.net.DefaultAndroidKeyStore; import org.chromium.ui.base.WindowAndroid; import java.security.Principal; +import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; @@ -45,39 +43,37 @@ import javax.security.auth.x500.X500Principal; public class SSLClientCertificateRequest { static final String TAG = "SSLClientCertificateRequest"; - private static final DefaultAndroidKeyStore sLocalKeyStore = - new DefaultAndroidKeyStore(); - /** - * Common implementation for anynchronous task of handling the certificate request. This - * AsyncTask uses the abstract methods to retrieve the authentication material from a - * generalized key store. The key store is accessed in background, as the APIs being exercised + * Implementation for anynchronous task of handling the certificate request. This + * AsyncTask retrieves the authentication material from the system key store. + * The key store is accessed in background, as the APIs being exercised * may be blocking. The results are posted back to native on the UI thread. */ - abstract static class CertAsyncTask extends AsyncTask<Void, Void, Void> { + private static class CertAsyncTaskKeyChain extends AsyncTask<Void, Void, Void> { // These fields will store the results computed in doInBackground so that they can be posted // back in onPostExecute. private byte[][] mEncodedChain; - private AndroidPrivateKey mAndroidPrivateKey; + private PrivateKey mPrivateKey; // Pointer to the native certificate request needed to return the results. private final long mNativePtr; - CertAsyncTask(long nativePtr) { + final Context mContext; + final String mAlias; + + CertAsyncTaskKeyChain(Context context, long nativePtr, String alias) { mNativePtr = nativePtr; + mContext = context; + assert alias != null; + mAlias = alias; } - // These overriden methods will be used to access the key store. - abstract String getAlias(); - abstract AndroidPrivateKey getPrivateKey(String alias); - abstract X509Certificate[] getCertificateChain(String alias); - @Override protected Void doInBackground(Void... params) { String alias = getAlias(); if (alias == null) return null; - AndroidPrivateKey key = getPrivateKey(alias); + PrivateKey key = getPrivateKey(alias); X509Certificate[] chain = getCertificateChain(alias); if (key == null || chain == null || chain.length == 0) { @@ -97,38 +93,23 @@ public class SSLClientCertificateRequest { } mEncodedChain = encodedChain; - mAndroidPrivateKey = key; + mPrivateKey = key; return null; } @Override protected void onPostExecute(Void result) { ThreadUtils.assertOnUiThread(); - nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mAndroidPrivateKey); - } - } - - /** Implementation of CertAsyncTask for the system KeyChain API. */ - private static class CertAsyncTaskKeyChain extends CertAsyncTask { - final Context mContext; - final String mAlias; - - CertAsyncTaskKeyChain(Context context, long nativePtr, String alias) { - super(nativePtr); - mContext = context; - assert alias != null; - mAlias = alias; + nativeOnSystemRequestCompletion(mNativePtr, mEncodedChain, mPrivateKey); } - @Override - String getAlias() { + private String getAlias() { return mAlias; } - @Override - AndroidPrivateKey getPrivateKey(String alias) { + private PrivateKey getPrivateKey(String alias) { try { - return sLocalKeyStore.createKey(KeyChain.getPrivateKey(mContext, alias)); + return KeyChain.getPrivateKey(mContext, alias); } catch (KeyChainException e) { Log.w(TAG, "KeyChainException when looking for '" + alias + "' certificate"); return null; @@ -138,8 +119,7 @@ public class SSLClientCertificateRequest { } } - @Override - X509Certificate[] getCertificateChain(String alias) { + private X509Certificate[] getCertificateChain(String alias) { try { return KeyChain.getCertificateChain(mContext, alias); } catch (KeyChainException e) { @@ -152,36 +132,6 @@ public class SSLClientCertificateRequest { } } - /** Implementation of CertAsyncTask for use with a PKCS11-backed KeyStore. */ - private static class CertAsyncTaskPKCS11 extends CertAsyncTask { - private final PKCS11AuthenticationManager mPKCS11AuthManager; - private final String mHostName; - private final int mPort; - - CertAsyncTaskPKCS11(long nativePtr, String hostName, int port, - PKCS11AuthenticationManager pkcs11CardAuthManager) { - super(nativePtr); - mHostName = hostName; - mPort = port; - mPKCS11AuthManager = pkcs11CardAuthManager; - } - - @Override - String getAlias() { - return mPKCS11AuthManager.getClientCertificateAlias(mHostName, mPort); - } - - @Override - AndroidPrivateKey getPrivateKey(String alias) { - return mPKCS11AuthManager.getPrivateKey(alias); - } - - @Override - X509Certificate[] getCertificateChain(String alias) { - return mPKCS11AuthManager.getCertificateChain(alias); - } - } - /** * The system KeyChain API will call us back on the alias() method, passing the alias of the * certificate selected by the user. @@ -275,6 +225,7 @@ public class SSLClientCertificateRequest { .setMessage(R.string.client_cert_unsupported_message) .setNegativeButton(R.string.close, new OnClickListener() { + @Override public void onClick(DialogInterface dialog, int which) { // Do nothing } @@ -321,50 +272,13 @@ public class SSLClientCertificateRequest { } } - final Principal[] principalsForCallback = principals; - // Certificate for client authentication can be obtained either from the system store of - // from a smart card (if available). - Runnable useSystemStore = new Runnable() { - @Override - public void run() { - KeyChainCertSelectionCallback callback = - new KeyChainCertSelectionCallback(activity.getApplicationContext(), - nativePtr); - KeyChainCertSelectionWrapper keyChain = new KeyChainCertSelectionWrapper(activity, - callback, keyTypes, principalsForCallback, hostName, port, null); - maybeShowCertSelection(keyChain, callback, - new CertSelectionFailureDialog(activity)); - } - }; - - final Context appContext = activity.getApplicationContext(); - final PKCS11AuthenticationManager smartCardAuthManager = - ((ChromeApplication) appContext).getPKCS11AuthenticationManager(); - if (smartCardAuthManager.isPKCS11AuthEnabled()) { - // Smart card support is available, prompt the user whether to use it or Android system - // store. - Runnable useSmartCard = new Runnable() { - @Override - public void run() { - new CertAsyncTaskPKCS11(nativePtr, hostName, port, - smartCardAuthManager).execute(); - } - }; - Runnable cancelRunnable = new Runnable() { - @Override - public void run() { - // We took ownership of the request, need to delete it. - nativeOnSystemRequestCompletion(nativePtr, null, null); - } - }; - - KeyStoreSelectionDialog selectionDialog = new KeyStoreSelectionDialog( - useSystemStore, useSmartCard, cancelRunnable); - selectionDialog.show(activity.getFragmentManager(), null); - } else { - // Smart card support is not available, use the system store unconditionally. - useSystemStore.run(); - } + KeyChainCertSelectionCallback callback = + new KeyChainCertSelectionCallback(activity.getApplicationContext(), + nativePtr); + KeyChainCertSelectionWrapper keyChain = new KeyChainCertSelectionWrapper(activity, + callback, keyTypes, principals, hostName, port, null); + maybeShowCertSelection(keyChain, callback, + new CertSelectionFailureDialog(activity)); // We've taken ownership of the native ssl request object. return true; @@ -399,5 +313,5 @@ public class SSLClientCertificateRequest { // Called to pass request results to native side. private static native void nativeOnSystemRequestCompletion( - long requestPtr, byte[][] certChain, AndroidPrivateKey androidKey); + long requestPtr, byte[][] certChain, PrivateKey privateKey); } diff --git a/chrome/android/java/src/org/chromium/chrome/browser/smartcard/EmptyPKCS11AuthenticationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/smartcard/EmptyPKCS11AuthenticationManager.java deleted file mode 100644 index d475f34..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/smartcard/EmptyPKCS11AuthenticationManager.java +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.smartcard; - -import android.content.Context; - -import org.chromium.base.ThreadUtils; -import org.chromium.net.AndroidPrivateKey; - -import java.security.cert.X509Certificate; - -/** - * Stub implementation of PKCS11AuthenticationManager. - */ -public class EmptyPKCS11AuthenticationManager implements PKCS11AuthenticationManager { - private static PKCS11AuthenticationManager sInstance; - - public static PKCS11AuthenticationManager getInstance() { - ThreadUtils.assertOnUiThread(); - if (sInstance == null) sInstance = new EmptyPKCS11AuthenticationManager(); - return sInstance; - } - - protected EmptyPKCS11AuthenticationManager() {} - - @Override - public boolean isPKCS11AuthEnabled() { - return false; - } - - @Override - public String getClientCertificateAlias(String hostName, int port) { - return null; - } - - @Override - public void initialize(Context context) {} - - @Override - public X509Certificate[] getCertificateChain(String alias) { - return null; - } - - @Override - public AndroidPrivateKey getPrivateKey(String alias) { - return null; - } -} diff --git a/chrome/android/java/src/org/chromium/chrome/browser/smartcard/PKCS11AuthenticationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/smartcard/PKCS11AuthenticationManager.java deleted file mode 100644 index 5cc66e2..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/smartcard/PKCS11AuthenticationManager.java +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.smartcard; - -import android.content.Context; - -import org.chromium.net.AndroidPrivateKey; - -import java.security.cert.X509Certificate; - -/** - * Defines API for managing interaction with SmartCard-based certificate storage using PKCS11. - */ -public interface PKCS11AuthenticationManager { - /** - * @return true iff SmartCard-based authentication is available. - */ - public boolean isPKCS11AuthEnabled(); - - /** - * Retrieves the preferred client certificate alias for the given host, port pair, or null if - * none can be retrieved. - * - * @param hostName The host for which to retrieve client certificate. - * @param port The port to use in conjunction with host to retrieve client certificate. - */ - public String getClientCertificateAlias(String hostName, int port); - - /** - * Returns the X509Certificate chain for the requested alias, or null if no there is no result. - */ - public X509Certificate[] getCertificateChain(String alias); - - /** - * Performs necessary initializing for using a PKCS11-based KeysStore. - */ - public void initialize(Context context); - - /** - * Returns the AndroidPrivateKey for the requested alias, or null if there is no result. - */ - public AndroidPrivateKey getPrivateKey(String alias); -} diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 9b6b7e1..76ae5a0 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd @@ -1284,14 +1284,6 @@ You are signing in with a managed account and giving its administrator control o Refreshing page </message> - <!-- Smartcard certificate support --> - <message name="IDS_SMARTCARD_DIALOG_TITLE" desc="Title of a dialog asking whether to use Android default keystore or a smartcard for certificate authentication."> - Choose certificate for authentication - </message> - <message name="IDS_SMARTCARD_CERTIFICATE_OPTION" desc="An option to use Smart Card when a dialog asking whether to use Android default keystore or a Smart Card for certificate authentication."> - Smart card - </message> - <!-- App banner strings --> <message name="IDS_APP_BANNER_INSTALLING" desc="Button text indicating that an application is being installed. [CHAR-LIMIT=25]"> Installing… diff --git a/chrome/test/android/unit_tests_apk/src/org/chromium/chrome/unit_tests_apk/ChromeNativeTestApplication.java b/chrome/test/android/unit_tests_apk/src/org/chromium/chrome/unit_tests_apk/ChromeNativeTestApplication.java index 6c71c52..77df74e 100644 --- a/chrome/test/android/unit_tests_apk/src/org/chromium/chrome/unit_tests_apk/ChromeNativeTestApplication.java +++ b/chrome/test/android/unit_tests_apk/src/org/chromium/chrome/unit_tests_apk/ChromeNativeTestApplication.java @@ -5,7 +5,6 @@ package org.chromium.chrome.unit_tests_apk; import org.chromium.chrome.browser.ChromeApplication; -import org.chromium.chrome.browser.smartcard.PKCS11AuthenticationManager; /** * A stub implementation of the chrome application to be used in chrome unit_tests. @@ -18,11 +17,6 @@ public class ChromeNativeTestApplication extends ChromeApplication { } @Override - protected PKCS11AuthenticationManager getPKCS11AuthenticationManager() { - return null; - } - - @Override public void initCommandLine() { } } diff --git a/net/BUILD.gn b/net/BUILD.gn index c8740974..f0081df 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn @@ -1194,7 +1194,6 @@ if (is_android) { "android/java/src/org/chromium/net/AndroidCertVerifyResult.java", "android/java/src/org/chromium/net/AndroidKeyStore.java", "android/java/src/org/chromium/net/AndroidNetworkLibrary.java", - "android/java/src/org/chromium/net/AndroidPrivateKey.java", "android/java/src/org/chromium/net/AndroidTrafficStats.java", "android/java/src/org/chromium/net/GURLUtils.java", "android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java", diff --git a/net/android/BUILD.gn b/net/android/BUILD.gn index df00495..483aed8 100644 --- a/net/android/BUILD.gn +++ b/net/android/BUILD.gn @@ -13,16 +13,6 @@ android_library("net_java") { srcjar_deps = [ ":net_errors_java", ":net_android_java_enums_srcjar", - ":remote_android_keystore_aidl", - ] -} - -android_aidl("remote_android_keystore_aidl") { - interface_file = - "java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl" - sources = [ - "java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl", - "java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl", ] } diff --git a/net/android/android_private_key.cc b/net/android/android_private_key.cc deleted file mode 100644 index 8f56085..0000000 --- a/net/android/android_private_key.cc +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/android/android_private_key.h" - -#include <vector> -#include "jni/AndroidPrivateKey_jni.h" - -namespace net { -namespace android { - -base::android::ScopedJavaLocalRef<jobject> GetKeyStore( - jobject private_key_ref) { - JNIEnv* env = base::android::AttachCurrentThread(); - return Java_AndroidPrivateKey_getKeyStore( - env, private_key_ref); -} - -bool RegisterAndroidPrivateKey(JNIEnv* env) { - return RegisterNativesImpl(env); -} - -} // namespace android -} // namespace net diff --git a/net/android/android_private_key.h b/net/android/android_private_key.h deleted file mode 100644 index 24f4f45..0000000 --- a/net/android/android_private_key.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_ANDROID_ANDROID_PRIVATE_KEY_H -#define NET_ANDROID_ANDROID_PRIVATE_KEY_H - -#include <jni.h> - -#include "base/android/scoped_java_ref.h" -#include "net/base/net_export.h" - - -namespace net { -namespace android { - -// Returns the KeyStore associated with a given AndroidPrivateKey -NET_EXPORT base::android::ScopedJavaLocalRef<jobject> GetKeyStore( - jobject private_key); - -// Register JNI methods -NET_EXPORT bool RegisterAndroidPrivateKey(JNIEnv* env); - -} // namespace android -} // namespace net - -#endif // NET_ANDROID_ANDROID_PRIVATE_KEY_H diff --git a/net/android/java/src/org/chromium/net/AndroidKeyStore.java b/net/android/java/src/org/chromium/net/AndroidKeyStore.java index b4fadba..030c44f 100644 --- a/net/android/java/src/org/chromium/net/AndroidKeyStore.java +++ b/net/android/java/src/org/chromium/net/AndroidKeyStore.java @@ -4,14 +4,25 @@ package org.chromium.net; +import org.chromium.base.Log; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; +import java.lang.reflect.Method; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.interfaces.ECKey; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.ECParameterSpec; + /** * Specifies all the dependencies from the native OpenSSL engine on an Android KeyStore. */ @JNINamespace("net::android") -public interface AndroidKeyStore { +public class AndroidKeyStore { + private static final String TAG = "AndroidKeyStore"; /** * Returns the public modulus of a given RSA private key as a byte @@ -20,22 +31,35 @@ public interface AndroidKeyStore { * an OpenSSL BIGNUM object. Required to craft a custom native RSA * object where RSA_size() works as expected. * - * @param key A PrivateKey instance, must implement RSAKey. + * @param privateKey A PrivateKey instance, must implement RSAKey. * @return A byte buffer corresponding to the modulus. This is - * big-endian representation of a BigInteger. + * big-endian representation of a BigInteger. */ @CalledByNative - byte[] getRSAKeyModulus(AndroidPrivateKey key); + private static byte[] getRSAKeyModulus(PrivateKey privateKey) { + if (privateKey instanceof RSAKey) { + return ((RSAKey) privateKey).getModulus().toByteArray(); + } + Log.w(TAG, "Not a RSAKey instance!"); + return null; + } /** * Returns the 'order' parameter of a given ECDSA private key as a * a byte buffer. - * @param key A PrivateKey instance. Must implement ECKey. + * @param privateKey A PrivateKey instance. Must implement ECKey. * @return A byte buffer corresponding to the 'order' parameter. * This is a big-endian representation of a BigInteger. */ @CalledByNative - byte[] getECKeyOrder(AndroidPrivateKey key); + private static byte[] getECKeyOrder(PrivateKey privateKey) { + if (privateKey instanceof ECKey) { + ECParameterSpec params = ((ECKey) privateKey).getParams(); + return params.getOrder().toByteArray(); + } + Log.w(TAG, "Not an ECKey instance!"); + return null; + } /** * Sign a given message with a given PrivateKey object. This method @@ -57,7 +81,7 @@ public interface AndroidKeyStore { * ECDSA_sign(0,...). The message must be a hash and the function shall * compute a direct ECDSA signature for it. * - * @param key The PrivateKey handle. + * @param privateKey The PrivateKey handle. * @param message The message to sign. * @return signature as a byte buffer. * @@ -66,17 +90,117 @@ public interface AndroidKeyStore { * getOpenSSLHandleForPrivateKey() below for work-around. */ @CalledByNative - byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, byte[] message); + private static byte[] rawSignDigestWithPrivateKey(PrivateKey privateKey, byte[] message) { + // Get the Signature for this key. + Signature signature = null; + // Hint: Algorithm names come from: + // http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html + try { + String keyAlgorithm = privateKey.getAlgorithm(); + if ("RSA".equalsIgnoreCase(keyAlgorithm)) { + // IMPORTANT: Due to a platform bug, this will throw NoSuchAlgorithmException + // on Android 4.1.x. Fixed in 4.2 and higher. + // See https://android-review.googlesource.com/#/c/40352/ + signature = Signature.getInstance("NONEwithRSA"); + } else if ("EC".equalsIgnoreCase(keyAlgorithm)) { + signature = Signature.getInstance("NONEwithECDSA"); + } + } catch (NoSuchAlgorithmException e) { + // Intentionally do nothing. + } + + if (signature == null) { + Log.e(TAG, "Unsupported private key algorithm: " + privateKey.getAlgorithm()); + return null; + } + + // Sign the message. + try { + signature.initSign(privateKey); + signature.update(message); + return signature.sign(); + } catch (Exception e) { + Log.e(TAG, "Exception while signing message with " + privateKey.getAlgorithm() + + " private key: " + e); + return null; + } + } /** * Return the type of a given PrivateKey object. This is an integer * that maps to one of the values defined by org.chromium.net.PrivateKeyType, * which is itself auto-generated from net/android/private_key_type_list.h - * @param key The PrivateKey handle + * @param privateKey The PrivateKey handle * @return key type, or PrivateKeyType.INVALID if unknown. */ @CalledByNative - int getPrivateKeyType(AndroidPrivateKey key); + private static int getPrivateKeyType(PrivateKey privateKey) { + String keyAlgorithm = privateKey.getAlgorithm(); + if ("RSA".equalsIgnoreCase(keyAlgorithm)) { + return PrivateKeyType.RSA; + } else if ("EC".equalsIgnoreCase(keyAlgorithm)) { + return PrivateKeyType.ECDSA; + } else { + return PrivateKeyType.INVALID; + } + } + + private static Object getOpenSSLKeyForPrivateKey(PrivateKey privateKey) { + // Sanity checks + if (privateKey == null) { + Log.e(TAG, "privateKey == null"); + return null; + } + if (!(privateKey instanceof RSAPrivateKey)) { + Log.e(TAG, "does not implement RSAPrivateKey"); + return null; + } + // First, check that this is a proper instance of OpenSSLRSAPrivateKey + // or one of its sub-classes. + Class<?> superClass; + try { + superClass = + Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey"); + } catch (Exception e) { + // This may happen if the target device has a completely different + // implementation of the java.security APIs, compared to vanilla + // Android. Highly unlikely, but still possible. + Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); + return null; + } + if (!superClass.isInstance(privateKey)) { + // This may happen if the PrivateKey was not created by the "AndroidOpenSSL" + // provider, which should be the default. That could happen if an OEM decided + // to implement a different default provider. Also highly unlikely. + Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" + + privateKey.getClass().getCanonicalName()); + return null; + } + + try { + // Use reflection to invoke the 'getOpenSSLKey()' method on the + // private key. This returns another Java object that wraps a native + // EVP_PKEY and OpenSSLEngine. Note that the method is final in Android + // 4.1, so calling the superclass implementation is ok. + Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); + getKey.setAccessible(true); + Object opensslKey = null; + try { + opensslKey = getKey.invoke(privateKey); + } finally { + getKey.setAccessible(false); + } + if (opensslKey == null) { + // Bail when detecting OEM "enhancement". + Log.e(TAG, "getOpenSSLKey() returned null"); + return null; + } + return opensslKey; + } catch (Exception e) { + Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e); + return null; + } + } /** * Return the system EVP_PKEY handle corresponding to a given PrivateKey @@ -106,11 +230,48 @@ public interface AndroidKeyStore { * libcore/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java * libcore/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp * - * @param key The PrivateKey handle. + * @param privateKey The PrivateKey handle. * @return The EVP_PKEY handle, as a 32-bit integer (0 if not available) */ @CalledByNative - long getOpenSSLHandleForPrivateKey(AndroidPrivateKey key); + private static long getOpenSSLHandleForPrivateKey(PrivateKey privateKey) { + Object opensslKey = getOpenSSLKeyForPrivateKey(privateKey); + if (opensslKey == null) return 0; + + try { + // Use reflection to invoke the 'getPkeyContext' method on the + // result of the getOpenSSLKey(). This is an 32-bit integer + // which is the address of an EVP_PKEY object. Note that this + // method these days returns a 64-bit long, but since this code + // path is used for older Android versions, it may still return + // a 32-bit int here. To be on the safe side, we cast the return + // value via Number rather than directly to Integer or Long. + Method getPkeyContext; + try { + getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext"); + } catch (Exception e) { + // Bail here too, something really not working as expected. + Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e); + return 0; + } + getPkeyContext.setAccessible(true); + long evp_pkey = 0; + try { + evp_pkey = ((Number) getPkeyContext.invoke(opensslKey)).longValue(); + } finally { + getPkeyContext.setAccessible(false); + } + if (evp_pkey == 0) { + // The PrivateKey is probably rotten for some reason. + Log.e(TAG, "getPkeyContext() returned null"); + } + return evp_pkey; + + } catch (Exception e) { + Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e); + return 0; + } + } /** * Return the OpenSSLEngine object corresponding to a given PrivateKey @@ -119,15 +280,67 @@ public interface AndroidKeyStore { * This shall only be used for Android 4.1 to work around a platform bug. * See https://crbug.com/381465. * - * @param key The PrivateKey handle. + * @param privateKey The PrivateKey handle. * @return The OpenSSLEngine object (or null if not available) */ @CalledByNative - Object getOpenSSLEngineForPrivateKey(AndroidPrivateKey key); + private static Object getOpenSSLEngineForPrivateKey(PrivateKey privateKey) { + // Find the system OpenSSLEngine class. + Class<?> engineClass; + try { + engineClass = Class.forName("org.apache.harmony.xnet.provider.jsse.OpenSSLEngine"); + } catch (Exception e) { + // This may happen if the target device has a completely different + // implementation of the java.security APIs, compared to vanilla + // Android. Highly unlikely, but still possible. + Log.e(TAG, "Cannot find system OpenSSLEngine class: " + e); + return null; + } + + Object opensslKey = getOpenSSLKeyForPrivateKey(privateKey); + if (opensslKey == null) return null; + + try { + // Use reflection to invoke the 'getEngine' method on the + // result of the getOpenSSLKey(). + Method getEngine; + try { + getEngine = opensslKey.getClass().getDeclaredMethod("getEngine"); + } catch (Exception e) { + // Bail here too, something really not working as expected. + Log.e(TAG, "No getEngine() method on OpenSSLKey member:" + e); + return null; + } + getEngine.setAccessible(true); + Object engine = null; + try { + engine = getEngine.invoke(opensslKey); + } finally { + getEngine.setAccessible(false); + } + if (engine == null) { + // The PrivateKey is probably rotten for some reason. + Log.e(TAG, "getEngine() returned null"); + } + // Sanity-check the returned engine. + if (!engineClass.isInstance(engine)) { + Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:" + + engine.getClass().getCanonicalName()); + return null; + } + return engine; + + } catch (Exception e) { + Log.e(TAG, "Exception while trying to retrieve OpenSSLEngine object: " + e); + return null; + } + } /** * Called when the native OpenSSL engine no longer needs access to the underlying key. */ @CalledByNative - void releaseKey(AndroidPrivateKey key); + private static void releaseKey(PrivateKey privateKey) { + // no-op for in-process. GC will handle key collection + } } diff --git a/net/android/java/src/org/chromium/net/AndroidPrivateKey.java b/net/android/java/src/org/chromium/net/AndroidPrivateKey.java deleted file mode 100644 index d1fade8..0000000 --- a/net/android/java/src/org/chromium/net/AndroidPrivateKey.java +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.net; - -import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.annotations.JNINamespace; - -/** - * Abstract private key that bundles the PrivateKey and AndroidKeyStore that it belongs to. - */ -@JNINamespace("net::android") -public interface AndroidPrivateKey { - /** @return AndroidKeyStore that handles this key. */ - @CalledByNative - AndroidKeyStore getKeyStore(); -} diff --git a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java deleted file mode 100644 index 30de150..0000000 --- a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.net; - -import android.util.Log; - -import java.lang.reflect.Method; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Signature; -import java.security.interfaces.ECKey; -import java.security.interfaces.RSAKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.ECParameterSpec; - -/** - * Simple implementation of the AndroidKeyStore for use with an in-process Java KeyStore. - */ -public class DefaultAndroidKeyStore implements AndroidKeyStore { - - private static final String TAG = "AndroidKeyStoreInProcessImpl"; - - private static class DefaultAndroidPrivateKey implements AndroidPrivateKey { - // The actual Java key being wrapped. - final PrivateKey mKey; - // Key store handling this key. - final DefaultAndroidKeyStore mStore; - - DefaultAndroidPrivateKey(PrivateKey key, DefaultAndroidKeyStore store) { - mKey = key; - mStore = store; - } - - PrivateKey getJavaKey() { - return mKey; - } - - @Override - public AndroidKeyStore getKeyStore() { - return mStore; - } - } - - public AndroidPrivateKey createKey(PrivateKey javaKey) { - return new DefaultAndroidPrivateKey(javaKey, this); - } - - @Override - public byte[] getRSAKeyModulus(AndroidPrivateKey key) { - PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey(); - if (javaKey instanceof RSAKey) { - return ((RSAKey) javaKey).getModulus().toByteArray(); - } - Log.w(TAG, "Not a RSAKey instance!"); - return null; - } - - @Override - public byte[] getECKeyOrder(AndroidPrivateKey key) { - PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey(); - if (javaKey instanceof ECKey) { - ECParameterSpec params = ((ECKey) javaKey).getParams(); - return params.getOrder().toByteArray(); - } - Log.w(TAG, "Not an ECKey instance!"); - return null; - } - - @Override - public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, - byte[] message) { - PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey(); - // Get the Signature for this key. - Signature signature = null; - // Hint: Algorithm names come from: - // http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html - try { - String keyAlgorithm = javaKey.getAlgorithm(); - if ("RSA".equalsIgnoreCase(keyAlgorithm)) { - // IMPORTANT: Due to a platform bug, this will throw NoSuchAlgorithmException - // on Android 4.0.x and 4.1.x. Fixed in 4.2 and higher. - // See https://android-review.googlesource.com/#/c/40352/ - signature = Signature.getInstance("NONEwithRSA"); - } else if ("EC".equalsIgnoreCase(keyAlgorithm)) { - signature = Signature.getInstance("NONEwithECDSA"); - } - } catch (NoSuchAlgorithmException e) { - // Intentionally do nothing. - } - - if (signature == null) { - Log.e(TAG, "Unsupported private key algorithm: " + javaKey.getAlgorithm()); - return null; - } - - // Sign the message. - try { - signature.initSign(javaKey); - signature.update(message); - return signature.sign(); - } catch (Exception e) { - Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm() - + " private key: " + e); - return null; - } - } - - @Override - public int getPrivateKeyType(AndroidPrivateKey key) { - PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey(); - String keyAlgorithm = javaKey.getAlgorithm(); - if ("RSA".equalsIgnoreCase(keyAlgorithm)) { - return PrivateKeyType.RSA; - } else if ("EC".equalsIgnoreCase(keyAlgorithm)) { - return PrivateKeyType.ECDSA; - } else { - return PrivateKeyType.INVALID; - } - } - - private Object getOpenSSLKeyForPrivateKey(AndroidPrivateKey key) { - PrivateKey javaKey = ((DefaultAndroidPrivateKey) key).getJavaKey(); - // Sanity checks - if (javaKey == null) { - Log.e(TAG, "key == null"); - return null; - } - if (!(javaKey instanceof RSAPrivateKey)) { - Log.e(TAG, "does not implement RSAPrivateKey"); - return null; - } - // First, check that this is a proper instance of OpenSSLRSAPrivateKey - // or one of its sub-classes. - Class<?> superClass; - try { - superClass = Class.forName( - "org.apache.harmony.xnet.provider.jsse.OpenSSLRSAPrivateKey"); - } catch (Exception e) { - // This may happen if the target device has a completely different - // implementation of the java.security APIs, compared to vanilla - // Android. Highly unlikely, but still possible. - Log.e(TAG, "Cannot find system OpenSSLRSAPrivateKey class: " + e); - return null; - } - if (!superClass.isInstance(javaKey)) { - // This may happen if the PrivateKey was not created by the "AndroidOpenSSL" - // provider, which should be the default. That could happen if an OEM decided - // to implement a different default provider. Also highly unlikely. - Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" - + javaKey.getClass().getCanonicalName()); - return null; - } - - try { - // Use reflection to invoke the 'getOpenSSLKey()' method on the - // private key. This returns another Java object that wraps a native - // EVP_PKEY and OpenSSLEngine. Note that the method is final in Android - // 4.1, so calling the superclass implementation is ok. - Method getKey = superClass.getDeclaredMethod("getOpenSSLKey"); - getKey.setAccessible(true); - Object opensslKey = null; - try { - opensslKey = getKey.invoke(javaKey); - } finally { - getKey.setAccessible(false); - } - if (opensslKey == null) { - // Bail when detecting OEM "enhancement". - Log.e(TAG, "getOpenSSLKey() returned null"); - return null; - } - return opensslKey; - } catch (Exception e) { - Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e); - return null; - } - } - - @Override - public long getOpenSSLHandleForPrivateKey(AndroidPrivateKey key) { - Object opensslKey = getOpenSSLKeyForPrivateKey(key); - if (opensslKey == null) return 0; - - try { - // Use reflection to invoke the 'getPkeyContext' method on the - // result of the getOpenSSLKey(). This is an 32-bit integer - // which is the address of an EVP_PKEY object. Note that this - // method these days returns a 64-bit long, but since this code - // path is used for older Android versions, it may still return - // a 32-bit int here. To be on the safe side, we cast the return - // value via Number rather than directly to Integer or Long. - Method getPkeyContext; - try { - getPkeyContext = opensslKey.getClass().getDeclaredMethod("getPkeyContext"); - } catch (Exception e) { - // Bail here too, something really not working as expected. - Log.e(TAG, "No getPkeyContext() method on OpenSSLKey member:" + e); - return 0; - } - getPkeyContext.setAccessible(true); - long evp_pkey = 0; - try { - evp_pkey = ((Number) getPkeyContext.invoke(opensslKey)).longValue(); - } finally { - getPkeyContext.setAccessible(false); - } - if (evp_pkey == 0) { - // The PrivateKey is probably rotten for some reason. - Log.e(TAG, "getPkeyContext() returned null"); - } - return evp_pkey; - - } catch (Exception e) { - Log.e(TAG, "Exception while trying to retrieve system EVP_PKEY handle: " + e); - return 0; - } - } - - @Override - public Object getOpenSSLEngineForPrivateKey(AndroidPrivateKey key) { - // Find the system OpenSSLEngine class. - Class<?> engineClass; - try { - engineClass = Class.forName( - "org.apache.harmony.xnet.provider.jsse.OpenSSLEngine"); - } catch (Exception e) { - // This may happen if the target device has a completely different - // implementation of the java.security APIs, compared to vanilla - // Android. Highly unlikely, but still possible. - Log.e(TAG, "Cannot find system OpenSSLEngine class: " + e); - return null; - } - - Object opensslKey = getOpenSSLKeyForPrivateKey(key); - if (opensslKey == null) return null; - - try { - // Use reflection to invoke the 'getEngine' method on the - // result of the getOpenSSLKey(). - Method getEngine; - try { - getEngine = opensslKey.getClass().getDeclaredMethod("getEngine"); - } catch (Exception e) { - // Bail here too, something really not working as expected. - Log.e(TAG, "No getEngine() method on OpenSSLKey member:" + e); - return null; - } - getEngine.setAccessible(true); - Object engine = null; - try { - engine = getEngine.invoke(opensslKey); - } finally { - getEngine.setAccessible(false); - } - if (engine == null) { - // The PrivateKey is probably rotten for some reason. - Log.e(TAG, "getEngine() returned null"); - } - // Sanity-check the returned engine. - if (!engineClass.isInstance(engine)) { - Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:" - + engine.getClass().getCanonicalName()); - return null; - } - return engine; - - } catch (Exception e) { - Log.e(TAG, "Exception while trying to retrieve OpenSSLEngine object: " + e); - return null; - } - } - - @Override - public void releaseKey(AndroidPrivateKey key) { - // no-op for in-process. GC will handle key collection - } -} diff --git a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl b/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl deleted file mode 100644 index 97b21b7..0000000 --- a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.net; - -import org.chromium.net.IRemoteAndroidKeyStoreCallbacks; - -/** - * Interface for communication with an Android KeyStore in another process. - */ -interface IRemoteAndroidKeyStore { - // Remote calls for SSlClientCertificateRequest - these allow retrieving - // the alias of the certificate to be used, its encoded chain and a handle - // for identifying a private key in the remote process. - String getClientCertificateAlias(); - byte[] getEncodedCertificateChain(in String alias); - int getPrivateKeyHandle(in String alias); - - // Registers callbacks for service->client communication. - void setClientCallbacks(IRemoteAndroidKeyStoreCallbacks callbacks); - - // Remote calls for AndroidKeyStore - these functions are performing operations - // with a PrivateKey in the remote process using the handle provided by - // |getPrivateKeyHandle|. - - byte[] getRSAKeyModulus(in int handle); - // Deprecated: This RPC is never used. - byte[] getPrivateKeyEncodedBytes(in int handle); - // Deprecated: This RPC is never used. - byte[] getDSAKeyParamQ(in int handle); - byte[] getECKeyOrder(in int handle); - byte[] rawSignDigestWithPrivateKey(in int handle, in byte[] message); - int getPrivateKeyType(in int handle); - void releaseKey(in int handle); -} diff --git a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl b/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl deleted file mode 100644 index 2c2564b..0000000 --- a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.net; - -/** - * Interface for communication from the remote authentication service back to the client. - */ -interface IRemoteAndroidKeyStoreCallbacks { - /** - * A critical failure has occurred and the service won't be able to recover. - * The client should unbind and optionally rebind at a later time. - */ - void onDisabled(); - - /** - * The service has started up and is fully initialized. This allows for the - * service to take some time to initialize. Remote calls shouldn't be invoked - * until this call has fired. - */ - void onInitComplete(); -} diff --git a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl b/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl deleted file mode 100644 index 3b54d29..0000000 --- a/net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -interface org.chomium.net.IRemoteAndroidKeyStore; -interface org.chromium.net.IRemoteAndroidKeyStoreCallbacks;
\ No newline at end of file diff --git a/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java b/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java deleted file mode 100644 index f732c45..0000000 --- a/net/android/java/src/org/chromium/net/RemoteAndroidKeyStore.java +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.net; - -import android.os.RemoteException; -import android.util.Log; - -/** - * Provides a remoted implementation of AndroidKeyStore where all calls are forwarded via - * binder to an external process. - */ -public class RemoteAndroidKeyStore implements AndroidKeyStore { - - private static final String TAG = "AndroidKeyStoreRemoteImpl"; - - private static class RemotePrivateKey implements AndroidPrivateKey { - // Reference to the key on a remote store. - final int mHandle; - // Key store handling this key. - final RemoteAndroidKeyStore mStore; - - RemotePrivateKey(int handle, RemoteAndroidKeyStore store) { - mHandle = handle; - mStore = store; - } - - public int getHandle() { - return mHandle; - } - - @Override - public AndroidKeyStore getKeyStore() { - return mStore; - } - } - - private final IRemoteAndroidKeyStore mRemoteManager; - - public RemoteAndroidKeyStore(IRemoteAndroidKeyStore manager) { - mRemoteManager = manager; - } - - @Override - public byte[] getRSAKeyModulus(AndroidPrivateKey key) { - RemotePrivateKey remoteKey = (RemotePrivateKey) key; - try { - Log.d(TAG, "getRSAKeyModulus"); - return mRemoteManager.getRSAKeyModulus(remoteKey.getHandle()); - } catch (RemoteException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public byte[] getECKeyOrder(AndroidPrivateKey key) { - RemotePrivateKey remoteKey = (RemotePrivateKey) key; - try { - Log.d(TAG, "getECKeyOrder"); - return mRemoteManager.getECKeyOrder(remoteKey.getHandle()); - } catch (RemoteException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public byte[] rawSignDigestWithPrivateKey(AndroidPrivateKey key, byte[] message) { - RemotePrivateKey remoteKey = (RemotePrivateKey) key; - try { - Log.d(TAG, "rawSignDigestWithPrivateKey"); - return mRemoteManager.rawSignDigestWithPrivateKey(remoteKey.getHandle(), message); - } catch (RemoteException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public int getPrivateKeyType(AndroidPrivateKey key) { - RemotePrivateKey remoteKey = (RemotePrivateKey) key; - try { - Log.d(TAG, "getPrivateKeyType"); - return mRemoteManager.getPrivateKeyType(remoteKey.getHandle()); - } catch (RemoteException e) { - e.printStackTrace(); - return 0; - } - } - - @Override - public long getOpenSSLHandleForPrivateKey(AndroidPrivateKey privateKey) { - // This should not be called as it's only for older versions of Android. - assert false; - return 0; - } - - @Override - public Object getOpenSSLEngineForPrivateKey(AndroidPrivateKey privateKey) { - // This should not be called as it's only for older versions of Android. - assert false; - return null; - } - - public AndroidPrivateKey createKey(String alias) { - try { - int handle = mRemoteManager.getPrivateKeyHandle(alias); - return new RemotePrivateKey(handle, this); - } catch (RemoteException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public void releaseKey(AndroidPrivateKey key) { - RemotePrivateKey remoteKey = (RemotePrivateKey) key; - try { - Log.d(TAG, "releaseKey"); - mRemoteManager.releaseKey(remoteKey.getHandle()); - } catch (RemoteException e) { - e.printStackTrace(); - } - } -} diff --git a/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java b/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java index a35427a..614ac79 100644 --- a/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java +++ b/net/android/javatests/src/org/chromium/net/AndroidKeyStoreTestUtil.java @@ -24,7 +24,6 @@ public class AndroidKeyStoreTestUtil { private static final String TAG = "AndroidKeyStoreTestUtil"; - private static final DefaultAndroidKeyStore sKeyStore = new DefaultAndroidKeyStore(); /** * Called from native code to create a PrivateKey object from its * encoded PKCS#8 representation. @@ -32,7 +31,7 @@ public class AndroidKeyStoreTestUtil { * @return new PrivateKey handle, or null in case of error. */ @CalledByNative - public static AndroidPrivateKey createPrivateKeyFromPKCS8(int type, byte[] encodedKey) { + public static PrivateKey createPrivateKeyFromPKCS8(int type, byte[] encodedKey) { String algorithm = null; switch (type) { case PrivateKeyType.RSA: @@ -49,7 +48,7 @@ public class AndroidKeyStoreTestUtil { KeyFactory factory = KeyFactory.getInstance(algorithm); KeySpec ks = new PKCS8EncodedKeySpec(encodedKey); PrivateKey key = factory.generatePrivate(ks); - return sKeyStore.createKey(key); + return key; } catch (NoSuchAlgorithmException e) { Log.e(TAG, "Could not create " + algorithm + " factory instance!"); diff --git a/net/android/keystore.cc b/net/android/keystore.cc index 4fa8dbf..32984dd 100644 --- a/net/android/keystore.cc +++ b/net/android/keystore.cc @@ -10,7 +10,6 @@ #include "base/android/jni_array.h" #include "base/logging.h" #include "jni/AndroidKeyStore_jni.h" -#include "net/android/android_private_key.h" using base::android::AttachCurrentThread; using base::android::HasException; @@ -26,9 +25,7 @@ bool GetRSAKeyModulus(jobject private_key_ref, std::vector<uint8_t>* result) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jbyteArray> modulus_ref = - Java_AndroidKeyStore_getRSAKeyModulus(env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + Java_AndroidKeyStore_getRSAKeyModulus(env, private_key_ref); if (modulus_ref.is_null()) return false; @@ -40,10 +37,7 @@ bool GetECKeyOrder(jobject private_key_ref, std::vector<uint8_t>* result) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jbyteArray> order_ref = - Java_AndroidKeyStore_getECKeyOrder( - env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + Java_AndroidKeyStore_getECKeyOrder(env, private_key_ref); if (order_ref.is_null()) return false; @@ -64,11 +58,8 @@ bool RawSignDigestWithPrivateKey(jobject private_key_ref, // Invoke platform API ScopedJavaLocalRef<jbyteArray> signature_ref = - Java_AndroidKeyStore_rawSignDigestWithPrivateKey( - env, - GetKeyStore(private_key_ref).obj(), - private_key_ref, - digest_ref.obj()); + Java_AndroidKeyStore_rawSignDigestWithPrivateKey(env, private_key_ref, + digest_ref.obj()); if (HasException(env) || signature_ref.is_null()) return false; @@ -79,10 +70,7 @@ bool RawSignDigestWithPrivateKey(jobject private_key_ref, PrivateKeyType GetPrivateKeyType(jobject private_key_ref) { JNIEnv* env = AttachCurrentThread(); - int type = Java_AndroidKeyStore_getPrivateKeyType( - env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + int type = Java_AndroidKeyStore_getPrivateKeyType(env, private_key_ref); return static_cast<PrivateKeyType>(type); } @@ -96,10 +84,8 @@ AndroidEVP_PKEY* GetOpenSSLSystemHandleForPrivateKey(jobject private_key_ref) { // Given that this routine shall only be called on Android < 4.2, // this won't be a problem in the far future (e.g. when Android gets // ported to 64-bit environments, if ever). - long pkey = Java_AndroidKeyStore_getOpenSSLHandleForPrivateKey( - env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + long pkey = + Java_AndroidKeyStore_getOpenSSLHandleForPrivateKey(env, private_key_ref); return reinterpret_cast<AndroidEVP_PKEY*>(pkey); } @@ -107,18 +93,13 @@ ScopedJavaLocalRef<jobject> GetOpenSSLEngineForPrivateKey( jobject private_key_ref) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> engine = - Java_AndroidKeyStore_getOpenSSLEngineForPrivateKey( - env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + Java_AndroidKeyStore_getOpenSSLEngineForPrivateKey(env, private_key_ref); return engine; } void ReleaseKey(jobject private_key_ref) { JNIEnv* env = AttachCurrentThread(); - Java_AndroidKeyStore_releaseKey(env, - GetKeyStore(private_key_ref).obj(), - private_key_ref); + Java_AndroidKeyStore_releaseKey(env, private_key_ref); env->DeleteGlobalRef(private_key_ref); } diff --git a/net/android/keystore_unittest.cc b/net/android/keystore_unittest.cc index b7eb083..4faa245 100644 --- a/net/android/keystore_unittest.cc +++ b/net/android/keystore_unittest.cc @@ -408,7 +408,7 @@ void DoKeySigningWithWrapper(EVP_PKEY* wrapper_key, } // namespace -TEST(AndroidKeyStore,GetRSAKeyModulus) { +TEST(AndroidKeyStore, GetRSAKeyModulus) { crypto::OpenSSLErrStackTracer err_trace(FROM_HERE); InitEnv(); diff --git a/net/android/net_jni_registrar.cc b/net/android/net_jni_registrar.cc index baf43be..656166b 100644 --- a/net/android/net_jni_registrar.cc +++ b/net/android/net_jni_registrar.cc @@ -6,7 +6,6 @@ #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" -#include "net/android/android_private_key.h" #include "net/android/gurl_utils.h" #include "net/android/http_auth_negotiate_android.h" #include "net/android/keystore.h" @@ -25,7 +24,6 @@ namespace android { static base::android::RegistrationMethod kNetRegisteredMethods[] = { {"AndroidCertVerifyResult", RegisterCertVerifyResult}, - {"AndroidPrivateKey", RegisterAndroidPrivateKey}, {"AndroidKeyStore", RegisterKeyStore}, {"AndroidNetworkLibrary", RegisterNetworkLibrary}, {"AndroidTrafficStats", traffic_stats::Register}, diff --git a/net/net.gyp b/net/net.gyp index 537d4a3..f4c9894 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1373,7 +1373,6 @@ 'android/java/src/org/chromium/net/AndroidCertVerifyResult.java', 'android/java/src/org/chromium/net/AndroidKeyStore.java', 'android/java/src/org/chromium/net/AndroidNetworkLibrary.java', - 'android/java/src/org/chromium/net/AndroidPrivateKey.java', 'android/java/src/org/chromium/net/AndroidTrafficStats.java', 'android/java/src/org/chromium/net/GURLUtils.java', 'android/java/src/org/chromium/net/HttpNegotiateAuthenticator.java', @@ -1414,26 +1413,11 @@ 'network_change_notifier_android_types_java', 'net_errors_java', 'private_key_types_java', - 'remote_android_keystore_aidl', 'traffic_stats_error_java', ], 'includes': [ '../build/java.gypi' ], }, { - # Processes the interface files for communication with an Android KeyStore - # running in a separate process. - 'target_name': 'remote_android_keystore_aidl', - 'type': 'none', - 'variables': { - 'aidl_interface_file': '../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl', - }, - 'sources': [ - '../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStore.aidl', - '../net/android/java/src/org/chromium/net/IRemoteAndroidKeyStoreCallbacks.aidl', - ], - 'includes': [ '../build/java_aidl.gypi' ], - }, - { 'target_name': 'net_java_test_support', 'type': 'none', 'variables': { diff --git a/net/net.gypi b/net/net.gypi index e2c3f9d..db33f77 100644 --- a/net/net.gypi +++ b/net/net.gypi @@ -394,8 +394,6 @@ 'quic/stream_sequencer_buffer.h', ], 'net_non_nacl_sources': [ - 'android/android_private_key.cc', - 'android/android_private_key.h', 'android/cert_verify_result_android.cc', 'android/cert_verify_result_android.h', 'android/gurl_utils.cc', |