summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2015-04-29 13:16:30 -0700
committerAlex Klyubin <klyubin@google.com>2015-04-29 13:28:56 -0700
commit4812563f68c87278af68309662433279d10f573e (patch)
tree64c1a78e3339bf04acd427c9a8da78653b71720c
parent47ea8b3d6bcef193a2d0ec9f0141525c83a0bcda (diff)
downloadframeworks_base-4812563f68c87278af68309662433279d10f573e.zip
frameworks_base-4812563f68c87278af68309662433279d10f573e.tar.gz
frameworks_base-4812563f68c87278af68309662433279d10f573e.tar.bz2
AndroidKeyStore keys should not be handled by Bouncy Castle.
Bouncy Castle JCA provider incorrectly declares that its Cipher, Mac, Signature, and KeyAgreement implementations accept arbitrary keys ( including AndroidKeyStore keys). As a result, when a Cipher, Mac, Signature, or KeyAgreement instance is requested from JCA without explicitly specifying the provider (which follows best practices) and then initialied with an AndroidKeyStore key, JCA chooses the BouncyCastle's implementation, which in turn blows up because it can't handle such keys. The workaround is to install Cipher, Mac, Signature, and KeyAgreement implementations backed by AndroidKeyStore as a higher-priority JCA provider than the Bouncy Castle one. This is achieved by splitting out the above implementations from AndroidKeyStoreProvider into AndroidKeyStoreBCWorkaroundProvider and installing the AndroidKeyStoreProvider at the usual priority (below Bouncy Castle) and the AndroidKeyStoreBCWorkaroundProvider at above Bouncy Castle priority. Bug: 20691708 Change-Id: I336464f4a49bc30c6845ddc4e84b07f4105424dd
-rw-r--r--core/java/android/app/ActivityThread.java3
-rw-r--r--keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java83
-rw-r--r--keystore/java/android/security/AndroidKeyStoreProvider.java61
-rw-r--r--preloaded-classes1
4 files changed, 115 insertions, 33 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9bad9bb..2e45b79 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -114,7 +114,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
-import java.security.Security;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
@@ -5338,7 +5337,7 @@ public final class ActivityThread {
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
- Security.addProvider(new AndroidKeyStoreProvider());
+ AndroidKeyStoreProvider.install();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
diff --git a/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java
new file mode 100644
index 0000000..45329cf
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.Provider;
+
+/**
+ * {@link Provider} of JCA crypto operations operating on Android KeyStore keys.
+ *
+ * <p>This provider was separated out of {@link AndroidKeyStoreProvider} to work around the issue
+ * that Bouncy Castle provider incorrectly declares that it accepts arbitrary keys (incl. Android
+ * KeyStore ones). This causes JCA to select the Bouncy Castle's implementation of JCA crypto
+ * operations for Android KeyStore keys unless Android KeyStore's own implementations are installed
+ * as higher-priority than Bouncy Castle ones. The purpose of this provider is to do just that: to
+ * offer crypto operations operating on Android KeyStore keys and to be installed at higher priority
+ * than the Bouncy Castle provider.
+ *
+ * <p>Once Bouncy Castle provider is fixed, this provider can be merged into the
+ * {@code AndroidKeyStoreProvider}.
+ *
+ * @hide
+ */
+class AndroidKeyStoreBCWorkaroundProvider extends Provider {
+
+ // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
+ // classes when this provider is instantiated and installed early on during each app's
+ // initialization process.
+
+ private static final String PACKAGE_NAME = "android.security";
+ private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
+ PACKAGE_NAME + ".KeyStoreSecretKey";
+
+ AndroidKeyStoreBCWorkaroundProvider() {
+ super("AndroidKeyStoreBCWorkaround",
+ 1.0,
+ "Android KeyStore security provider to work around Bouncy Castle");
+
+ // javax.crypto.Mac
+ putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
+ putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
+ putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
+ putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
+ putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
+
+ // javax.crypto.Cipher
+ putSymmetricCipherImpl("AES/ECB/NoPadding",
+ PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$NoPadding");
+ putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
+ PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$PKCS7Padding");
+
+ putSymmetricCipherImpl("AES/CBC/NoPadding",
+ PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$NoPadding");
+ putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
+ PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$PKCS7Padding");
+
+ putSymmetricCipherImpl("AES/CTR/NoPadding",
+ PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
+ }
+
+ private void putMacImpl(String algorithm, String implClass) {
+ put("Mac." + algorithm, implClass);
+ put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+ }
+
+ private void putSymmetricCipherImpl(String transformation, String implClass) {
+ put("Cipher." + transformation, implClass);
+ put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+ }
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 43f3b30..518067b 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -17,6 +17,7 @@
package android.security;
import java.security.Provider;
+import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -32,10 +33,12 @@ public class AndroidKeyStoreProvider extends Provider {
// IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
// classes when this provider is instantiated and installed early on during each app's
// initialization process.
+ //
+ // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider.
+ // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
+ // for details.
private static final String PACKAGE_NAME = "android.security";
- private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
- PACKAGE_NAME + ".KeyStoreSecretKey";
public AndroidKeyStoreProvider() {
super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
@@ -62,43 +65,39 @@ public class AndroidKeyStoreProvider extends Provider {
putSecretKeyFactoryImpl("HmacSHA256");
putSecretKeyFactoryImpl("HmacSHA384");
putSecretKeyFactoryImpl("HmacSHA512");
+ }
- // javax.crypto.Mac
- putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
- putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
- putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
- putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
- putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
-
- // javax.crypto.Cipher
- putSymmetricCipherImpl("AES/ECB/NoPadding",
- PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$NoPadding");
- putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
- PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$PKCS7Padding");
-
- putSymmetricCipherImpl("AES/CBC/NoPadding",
- PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$NoPadding");
- putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
- PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$PKCS7Padding");
+ /**
+ * Installs a new instance of this provider (and the
+ * {@link AndroidKeyStoreBCWorkaroundProvider}).
+ */
+ public static void install() {
+ Provider[] providers = Security.getProviders();
+ int bcProviderPosition = -1;
+ for (int position = 0; position < providers.length; position++) {
+ Provider provider = providers[position];
+ if ("BC".equals(provider.getName())) {
+ bcProviderPosition = position;
+ break;
+ }
+ }
- putSymmetricCipherImpl("AES/CTR/NoPadding",
- PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
+ Security.addProvider(new AndroidKeyStoreProvider());
+ Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
+ if (bcProviderPosition != -1) {
+ // Bouncy Castle provider found -- install the workaround provider above it.
+ Security.insertProviderAt(workaroundProvider, bcProviderPosition);
+ } else {
+ // Bouncy Castle provider not found -- install the workaround provider at lowest
+ // priority.
+ Security.addProvider(workaroundProvider);
+ }
}
private void putSecretKeyFactoryImpl(String algorithm) {
put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
}
- private void putMacImpl(String algorithm, String implClass) {
- put("Mac." + algorithm, implClass);
- put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
- private void putSymmetricCipherImpl(String transformation, String implClass) {
- put("Cipher." + transformation, implClass);
- put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
/**
* Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
* primitive.
diff --git a/preloaded-classes b/preloaded-classes
index c94623a..d2ed762 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1152,6 +1152,7 @@ android.provider.Settings$SettingNotFoundException
android.provider.Settings$System
android.provider.Telephony$Mms
android.renderscript.RenderScript
+android.security.AndroidKeyStoreBCWorkaroundProvider
android.security.AndroidKeyStoreProvider
android.speech.tts.TextToSpeechService
android.speech.tts.TextToSpeechService$SpeechItemV1