Migrate StrictJarVerifier and ShortcutPackageInfo to java.util.Base64
Previously, they weres using libcore.io.Base64, which is @deprecated.
The two implementations' encoders produce the exact same result.
The two implementations' decoders' behavior differs for malformed
input:
- In case of error, libcore.io.Base64.decode() returns null while
java.util.Base64.getDecoder().decode() throws.
- java.util.Base64 tends to be stricter about rejecting malformed
input; specifically, it allows neither whitespace nor unexpected
'=' characters (should only occur in the padding) whereas
libcore.io.Base64.decode() leniently allows them throughout the
input.
- if the input terminates prematurely, libcore.io.Base64 tends to
return fewer bytes (stops at a four byte boundary).
The behavior differences for malformed Base64 encoded data should
not affect ShortcutPackageInfo because it should only need to deal
with XML attribute values written by itself, which are well-formed.
Note that this CL does not lead to any known changes of the encoding
step, so values written by earlier versions should not cause problems
when read by later versions of ShortcutPackageInfo.
StrictJarVerifier may now reject or behave differently for .jar /
.zip files with malformed attribute values but this seems okay since,
per its name, it is meant to be strict. For example, after this CL,
StrictJarVerifier will no longer accept algorithm + "-Digest"
attribute values with extra whitespace or padding characters as valid.
Test: Confirmed that the two implementations' encoders produce the
same result by running the following code just before this CL:
assertEquals(
libcore.io.Base64.encode(allBytes()),
Base64.getEncoder().encodeToString(allBytes()));
where allBytes() returns a byte[] with values (byte) 0 .. (byte) 255
Test: Test that phone still boots after flashing code that includes
this CL.
Test: CtsLibcoreTestCases
Bug: 31292683
Change-Id: I775d32f329f693514a8f14d87e1ef0d7a757e6c3
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index cb71ecc..debc170 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -17,7 +17,7 @@
package android.util.jar;
-import java.io.ByteArrayInputStream;
+import android.util.apk.ApkSignatureSchemeV2Verifier;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
@@ -33,13 +33,9 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
-import android.util.ArraySet;
-import android.util.apk.ApkSignatureSchemeV2Verifier;
-import libcore.io.Base64;
import sun.security.jca.Providers;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
@@ -139,7 +135,7 @@
*/
void verify() {
byte[] d = digest.digest();
- if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
+ if (!verifyMessageDigest(d, hash)) {
throw invalidDigest(JarFile.MANIFEST_NAME, name, name);
}
verifiedEntries.put(name, certChains);
@@ -490,12 +486,22 @@
md.update(data, start, end - start);
}
byte[] b = md.digest();
- byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
- return MessageDigest.isEqual(b, Base64.decode(hashBytes));
+ byte[] encodedHashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
+ return verifyMessageDigest(b, encodedHashBytes);
}
return ignorable;
}
+ private static boolean verifyMessageDigest(byte[] expected, byte[] encodedActual) {
+ byte[] actual;
+ try {
+ actual = java.util.Base64.getDecoder().decode(encodedActual);
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ return MessageDigest.isEqual(expected, actual);
+ }
+
/**
* Returns all of the {@link java.security.cert.Certificate} chains that
* were used to verify the signature on the JAR entry called