Switch order of digest and digest encryption algorithm
Sometimes "digest encryption algorithm" would be "RSA" which would match
a Signature provider, but its default setup would be whatever the
provider chose. This works fine with newer algorithms that have a
specific OID for their signature format (e.g., ECDSA and SHA256), but
not with algorithms that just have a generic OID for all possible uses
(e.g., RSA). Stock Android never hits this problem, because nothing
registers a "Signature.RSA" provider, but Spongycastle does so using
JarURLClassLoader after inserting Spongycastle causes a problem.
Flip the order of tries to make this work more uniformly with more JAR
and provider combinations.
(cherry picked from commit b1da6d3df5f9cce6e6d77c63599eba62edb465d6)
Bug: 17790692
Bug: https://code.google.com/p/android/issues/detail?id=68562
Change-Id: I3bb07ea25d7bf1d55fa2466b204594179ac38932
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index d5d8191..f55829d 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -24,7 +24,15 @@
import java.io.InputStream;
import java.net.URL;
import java.security.CodeSigner;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
import java.security.Permission;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
@@ -1014,4 +1022,73 @@
res = jarFile.getInputStream(zipEntry).read();
assertEquals("Wrong length of empty jar entry", -1, res);
}
+
+ public void testJarFile_BadSignatureProvider_Success() throws Exception {
+ Security.insertProviderAt(new JarFileBadProvider(), 1);
+ try {
+ // Needs a JAR with "RSA" as digest encryption algorithm
+ checkSignedJar(jarName6);
+ } finally {
+ Security.removeProvider(JarFileBadProvider.NAME);
+ }
+ }
+
+ public static class JarFileBadProvider extends Provider {
+ public static final String NAME = "JarFileBadProvider";
+
+ public JarFileBadProvider() {
+ super(NAME, 1.0, "Bad provider for JarFileTest");
+
+ put("Signature.RSA", NotReallyASignature.class.getName());
+ }
+
+ /**
+ * This should never be instantiated, so everything throws an exception.
+ */
+ public static class NotReallyASignature extends SignatureSpi {
+ @Override
+ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
+ fail("Should not call this provider");
+ }
+
+ @Override
+ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
+ fail("Should not call this provider");
+ }
+
+ @Override
+ protected void engineUpdate(byte b) throws SignatureException {
+ fail("Should not call this provider");
+ }
+
+ @Override
+ protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+ fail("Should not call this provider");
+ }
+
+ @Override
+ protected byte[] engineSign() throws SignatureException {
+ fail("Should not call this provider");
+ return null;
+ }
+
+ @Override
+ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
+ fail("Should not call this provider");
+ return false;
+ }
+
+ @Override
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ fail("Should not call this provider");
+ }
+
+ @Override
+ protected Object engineGetParameter(String param) throws InvalidParameterException {
+ fail("Should not call this provider");
+ return null;
+ }
+ }
+ }
}
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index e7f3596..5755dc2 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -124,28 +124,12 @@
final String daOid = sigInfo.getDigestAlgorithm();
final String daName = sigInfo.getDigestAlgorithmName();
final String deaOid = sigInfo.getDigestEncryptionAlgorithm();
+ final String deaName = sigInfo.getDigestEncryptionAlgorithmName();
String alg = null;
Signature sig = null;
- if (deaOid != null) {
- alg = deaOid;
- try {
- sig = Signature.getInstance(alg);
- } catch (NoSuchAlgorithmException e) {
- }
-
- final String deaName = sigInfo.getDigestEncryptionAlgorithmName();
- if (sig == null && deaName != null) {
- alg = deaName;
- try {
- sig = Signature.getInstance(alg);
- } catch (NoSuchAlgorithmException e) {
- }
- }
- }
-
- if (sig == null && daOid != null && deaOid != null) {
+ if (daOid != null && deaOid != null) {
alg = daOid + "with" + deaOid;
try {
sig = Signature.getInstance(alg);
@@ -153,8 +137,7 @@
}
// Try to convert to names instead of OID.
- if (sig == null) {
- final String deaName = sigInfo.getDigestEncryptionAlgorithmName();
+ if (sig == null && daName != null && deaName != null) {
alg = daName + "with" + deaName;
try {
sig = Signature.getInstance(alg);
@@ -163,6 +146,22 @@
}
}
+ if (sig == null && deaOid != null) {
+ alg = deaOid;
+ try {
+ sig = Signature.getInstance(alg);
+ } catch (NoSuchAlgorithmException e) {
+ }
+
+ if (sig == null) {
+ alg = deaName;
+ try {
+ sig = Signature.getInstance(alg);
+ } catch (NoSuchAlgorithmException e) {
+ }
+ }
+ }
+
// We couldn't find a valid Signature type.
if (sig == null) {
return null;