diff options
author | Kenny Root <kroot@google.com> | 2014-02-04 17:37:26 -0800 |
---|---|---|
committer | Kenny Root <kroot@google.com> | 2014-02-05 09:42:35 -0800 |
commit | 3ed78a8925825daccdba23fda1f69cbb3aa77a24 (patch) | |
tree | d352cd7e8647fe9b92ff5b9b49118380c54d9a7e /luni/src | |
parent | bfb883abadbf7e914cdac55d22d28a1c8286979b (diff) | |
download | libcore-3ed78a8925825daccdba23fda1f69cbb3aa77a24.zip libcore-3ed78a8925825daccdba23fda1f69cbb3aa77a24.tar.gz libcore-3ed78a8925825daccdba23fda1f69cbb3aa77a24.tar.bz2 |
Late binding: supplied Provider should be used
If a program supplies a Provider object, it should be used instead of
looking at the registered providers.
Bug: 12890254
Change-Id: Ia4d1ac88a1ed20ab6ad6a11d2d5f53ee51310544
Diffstat (limited to 'luni/src')
4 files changed, 111 insertions, 56 deletions
diff --git a/luni/src/main/java/javax/crypto/Cipher.java b/luni/src/main/java/javax/crypto/Cipher.java index 6299f80..91789b4 100644 --- a/luni/src/main/java/javax/crypto/Cipher.java +++ b/luni/src/main/java/javax/crypto/Cipher.java @@ -397,46 +397,61 @@ public class Cipher { private static Engine.SpiAndProvider tryTransform(Key key, Provider provider, String transform, String[] transformParts, NeedToSet type) { - Engine.SpiAndProvider sap; - ArrayList<Provider.Service> services = ENGINE.getServices(transform, provider); + if (provider != null) { + Provider.Service service = provider.getService(SERVICE, transform); + if (service == null) { + return null; + } + return tryTransformWithProvider(key, transformParts, type, service); + } + ArrayList<Provider.Service> services = ENGINE.getServices(transform); if (services == null) { return null; } for (Provider.Service service : services) { - try { - if (key != null && !service.supportsParameter(key)) { - continue; - } + Engine.SpiAndProvider sap = tryTransformWithProvider(key, transformParts, type, service); + if (sap != null) { + return sap; + } + } + return null; + } - /* - * Check to see if the Cipher even supports the attributes - * before trying to instantiate it. - */ - if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1]) - || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) { - continue; - } + private static Engine.SpiAndProvider tryTransformWithProvider(Key key, String[] transformParts, + NeedToSet type, Provider.Service service) { + try { + if (key != null && !service.supportsParameter(key)) { + return null; + } - sap = ENGINE.getInstance(service, null); - if (sap.spi == null || sap.provider == null) { - continue; - } - if (!(sap.spi instanceof CipherSpi)) { - continue; - } - CipherSpi spi = (CipherSpi) sap.spi; - if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH)) - && (transformParts[1] != null)) { - spi.engineSetMode(transformParts[1]); - } - if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH)) - && (transformParts[2] != null)) { - spi.engineSetPadding(transformParts[2]); - } + /* + * Check to see if the Cipher even supports the attributes before + * trying to instantiate it. + */ + if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1]) + || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) { + return null; + } + + Engine.SpiAndProvider sap = ENGINE.getInstance(service, null); + if (sap.spi == null || sap.provider == null) { + return sap; + } + if (!(sap.spi instanceof CipherSpi)) { return sap; - } catch (NoSuchAlgorithmException ignored) { - } catch (NoSuchPaddingException ignored) { } + CipherSpi spi = (CipherSpi) sap.spi; + if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH)) + && (transformParts[1] != null)) { + spi.engineSetMode(transformParts[1]); + } + if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH)) + && (transformParts[2] != null)) { + spi.engineSetPadding(transformParts[2]); + } + return sap; + } catch (NoSuchAlgorithmException ignored) { + } catch (NoSuchPaddingException ignored) { } return null; } diff --git a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java index b9954bc..006dda8 100644 --- a/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java +++ b/luni/src/main/java/org/apache/harmony/security/fortress/Engine.java @@ -26,7 +26,6 @@ import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.util.ArrayList; import java.util.Locale; -import java.util.Objects; /** * This class implements common functionality for Provider supplied @@ -93,19 +92,15 @@ public class Engine { private static final class ServiceCacheEntry { /** used to test for cache hit */ private final String algorithm; - /** used to test for cache hit */ - private final Provider provider; /** used to test for cache validity */ private final int cacheVersion; /** cached result */ private final ArrayList<Provider.Service> services; private ServiceCacheEntry(String algorithm, - Provider provider, int cacheVersion, ArrayList<Provider.Service> services) { this.algorithm = algorithm; - this.provider = provider; this.cacheVersion = cacheVersion; this.services = services; } @@ -139,7 +134,7 @@ public class Engine { if (algorithm == null) { throw new NoSuchAlgorithmException("Null algorithm name"); } - ArrayList<Provider.Service> services = getServices(algorithm, null); + ArrayList<Provider.Service> services = getServices(algorithm); if (services == null) { throw notFound(this.serviceName, algorithm); } @@ -159,32 +154,19 @@ public class Engine { /** * Returns a list of all possible matches for a given algorithm. */ - public ArrayList<Provider.Service> getServices(String algorithm, Provider provider) { + public ArrayList<Provider.Service> getServices(String algorithm) { int newCacheVersion = Services.getCacheVersion(); ServiceCacheEntry cacheEntry = this.serviceCache; final String algoUC = algorithm.toUpperCase(Locale.US); if (cacheEntry != null && cacheEntry.algorithm.equalsIgnoreCase(algoUC) - && Objects.equals(cacheEntry.provider, provider) && newCacheVersion == cacheEntry.cacheVersion) { return cacheEntry.services; } String name = this.serviceName + "." + algoUC; ArrayList<Provider.Service> services = Services.getServices(name); - if (provider == null || services == null) { - this.serviceCache = new ServiceCacheEntry(algoUC, provider, newCacheVersion, services); - return services; - } - ArrayList<Provider.Service> filteredServices = new ArrayList<Provider.Service>( - services.size()); - for (Provider.Service service : services) { - if (provider.equals(service.getProvider())) { - filteredServices.add(service); - } - } - this.serviceCache = new ServiceCacheEntry(algoUC, provider, newCacheVersion, - filteredServices); - return filteredServices; + this.serviceCache = new ServiceCacheEntry(algoUC, newCacheVersion, services); + return services; } /** diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java index b9241c0..21cc5da 100644 --- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java +++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java @@ -26,6 +26,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; @@ -832,6 +833,59 @@ public final class CipherTest extends TestCase { public abstract void setup(); } + public void testCipher_getInstance_SuppliedProviderNotRegistered_Success() throws Exception { + Provider mockProvider = new MockProvider("MockProvider") { + public void setup() { + put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); + } + }; + + { + Cipher c = Cipher.getInstance("FOO", mockProvider); + c.init(Cipher.ENCRYPT_MODE, new MockKey()); + assertEquals(mockProvider, c.getProvider()); + } + } + + public void testCipher_getInstance_SuppliedProviderNotRegistered_MultipartTransform_Success() + throws Exception { + Provider mockProvider = new MockProvider("MockProvider") { + public void setup() { + put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); + } + }; + + { + Cipher c = Cipher.getInstance("FOO/FOO/FOO", mockProvider); + c.init(Cipher.ENCRYPT_MODE, new MockKey()); + assertEquals(mockProvider, c.getProvider()); + } + } + + public void testCipher_getInstance_OnlyUsesSpecifiedProvider_SameNameAndClass_Success() + throws Exception { + Provider mockProvider = new MockProvider("MockProvider") { + public void setup() { + put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); + } + }; + + Security.addProvider(mockProvider); + try { + { + Provider mockProvider2 = new MockProvider("MockProvider") { + public void setup() { + put("Cipher.FOO", MockCipherSpi.AllKeyTypes.class.getName()); + } + }; + Cipher c = Cipher.getInstance("FOO", mockProvider2); + assertEquals(mockProvider2, c.getProvider()); + } + } finally { + Security.removeProvider(mockProvider.getName()); + } + } + public void testCipher_getInstance_DelayedInitialization_KeyType() throws Exception { Provider mockProviderSpecific = new MockProvider("MockProviderSpecific") { public void setup() { diff --git a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java index b09d883..eb950cc 100644 --- a/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java +++ b/luni/src/test/java/libcore/javax/crypto/MockCipherSpi.java @@ -51,12 +51,16 @@ public class MockCipherSpi extends CipherSpi { @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - throw new UnsupportedOperationException("not implemented"); + if (!"FOO".equals(mode)) { + throw new UnsupportedOperationException("not implemented"); + } } @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - throw new UnsupportedOperationException("not implemented"); + if (!"FOO".equals(padding)) { + throw new UnsupportedOperationException("not implemented"); + } } @Override |