diff options
author | Alex Klyubin <klyubin@google.com> | 2015-04-29 13:16:30 -0700 |
---|---|---|
committer | Alex Klyubin <klyubin@google.com> | 2015-04-29 13:28:56 -0700 |
commit | 4812563f68c87278af68309662433279d10f573e (patch) | |
tree | 64c1a78e3339bf04acd427c9a8da78653b71720c /keystore/java/android/security/AndroidKeyStoreProvider.java | |
parent | 47ea8b3d6bcef193a2d0ec9f0141525c83a0bcda (diff) |
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
Diffstat (limited to 'keystore/java/android/security/AndroidKeyStoreProvider.java')
-rw-r--r-- | keystore/java/android/security/AndroidKeyStoreProvider.java | 61 |
1 files changed, 30 insertions, 31 deletions
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java index 43f3b30fa4fb..518067b1c738 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. |