diff options
-rw-r--r-- | core/java/android/app/ActivityThread.java | 3 | ||||
-rw-r--r-- | keystore/java/android/security/AndroidKeyStoreBCWorkaroundProvider.java | 83 | ||||
-rw-r--r-- | keystore/java/android/security/AndroidKeyStoreProvider.java | 61 | ||||
-rw-r--r-- | preloaded-classes | 1 |
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 |