From 0caa16a6d1b4349654956c895aab925c9522d2cf Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Wed, 11 May 2016 17:19:07 -0700 Subject: [PATCH] No need to JAR-sign OTA update packages. This removes the logic for JAR signing from -w (whole-file signing) mode. This mode is designed specifically for OTA update packages. When such packages are verified, their JAR signatures are ignored. Thus, there is no need to JAR-sign in -w mode. For context, OTA update packages are protected by a special signature residing in the ZIP End of Central Directory record (at the very end of the file). This is the signature verified when update packages are being applied to Android. Change-Id: Ia852a11ed6774ce746087cdd7f028b191ef6bc8b --- tools/signapk/src/com/android/signapk/SignApk.java | 80 +++++++++++----------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/tools/signapk/src/com/android/signapk/SignApk.java b/tools/signapk/src/com/android/signapk/SignApk.java index c80d93ccb..1df6b80ce 100644 --- a/tools/signapk/src/com/android/signapk/SignApk.java +++ b/tools/signapk/src/com/android/signapk/SignApk.java @@ -200,10 +200,10 @@ class SignApk { } } - // Files matching this pattern are not copied to the output. - private static Pattern stripPattern = - Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|(" + - Pattern.quote(JarFile.MANIFEST_NAME) + ")$"); + /* Files matching this pattern are not copied to the output. */ + private static final Pattern STRIP_PATTERN = + Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|(" + + Pattern.quote(JarFile.MANIFEST_NAME) + ")$"); private static X509Certificate readPublicKey(File file) throws IOException, GeneralSecurityException { @@ -313,8 +313,9 @@ class SignApk { * Add the hash(es) of every file to the manifest, creating it if * necessary. */ - private static Manifest addDigestsToManifest(JarFile jar, int hashes) - throws IOException, GeneralSecurityException { + private static Manifest addDigestsToManifest( + JarFile jar, Pattern ignoredFilenamePattern, int hashes) + throws IOException, GeneralSecurityException { Manifest input = jar.getManifest(); Manifest output = new Manifest(); Attributes main = output.getMainAttributes(); @@ -350,8 +351,9 @@ class SignApk { for (JarEntry entry: byName.values()) { String name = entry.getName(); - if (!entry.isDirectory() && - (stripPattern == null || !stripPattern.matcher(name).matches())) { + if (!entry.isDirectory() + && (ignoredFilenamePattern == null + || !ignoredFilenamePattern.matcher(name).matches())) { InputStream data = jar.getInputStream(entry); while ((num = data.read(buffer)) > 0) { if (md_sha1 != null) md_sha1.update(buffer, 0, num); @@ -394,16 +396,13 @@ class SignApk { * Add a copy of the public key to the archive; this should * exactly match one of the files in * /system/etc/security/otacerts.zip on the device. (The same - * cert can be extracted from the CERT.RSA file but this is much - * easier to get at.) + * cert can be extracted from the OTA update package's signature + * block but this is much easier to get at.) */ private static void addOtacert(JarOutputStream outputJar, File publicKeyFile, - long timestamp, - Manifest manifest, - int hash) + long timestamp) throws IOException, GeneralSecurityException { - MessageDigest md = MessageDigest.getInstance(hash == USE_SHA1 ? "SHA1" : "SHA256"); JarEntry je = new JarEntry(OTACERT_NAME); je.setTime(timestamp); @@ -413,14 +412,8 @@ class SignApk { int read; while ((read = input.read(b)) != -1) { outputJar.write(b, 0, read); - md.update(b, 0, read); } input.close(); - - Attributes attr = new Attributes(); - attr.putValue(hash == USE_SHA1 ? "SHA1-Digest" : "SHA-256-Digest", - new String(Base64.encode(md.digest()), "ASCII")); - manifest.getEntries().put(OTACERT_NAME, attr); } @@ -545,18 +538,31 @@ class SignApk { } /** - * Copy all the files in a manifest from input to output. We set - * the modification times in the output to a fixed time, so as to - * reduce variation in the output file and make incremental OTAs - * more efficient. + * Copy all JAR entries from input to output. We set the modification times in the output to a + * fixed time, so as to reduce variation in the output file and make incremental OTAs more + * efficient. */ - private static void copyFiles(Manifest manifest, JarFile in, JarOutputStream out, - long timestamp, int defaultAlignment) throws IOException { + private static void copyFiles(JarFile in, + Pattern ignoredFilenamePattern, + JarOutputStream out, + long timestamp, + int defaultAlignment) throws IOException { byte[] buffer = new byte[4096]; int num; - Map entries = manifest.getEntries(); - ArrayList names = new ArrayList(entries.keySet()); + ArrayList names = new ArrayList(); + for (Enumeration e = in.entries(); e.hasMoreElements();) { + JarEntry entry = e.nextElement(); + if (entry.isDirectory()) { + continue; + } + String entryName = entry.getName(); + if ((ignoredFilenamePattern != null) + && (ignoredFilenamePattern.matcher(entryName).matches())) { + continue; + } + names.add(entryName); + } Collections.sort(names); boolean firstEntry = true; @@ -757,17 +763,8 @@ class SignApk { signer = new WholeFileSignerOutputStream(out, outputStream); JarOutputStream outputJar = new JarOutputStream(signer); - Manifest manifest = addDigestsToManifest(inputJar, hash); - copyFiles(manifest, inputJar, outputJar, timestamp, 0); - addOtacert(outputJar, publicKeyFile, timestamp, manifest, hash); - - signFile(manifest, - new X509Certificate[]{ publicKey }, - new PrivateKey[]{ privateKey }, - new int[] { hash }, - timestamp, - false, // Don't sign using APK Signature Scheme v2 - outputJar); + copyFiles(inputJar, STRIP_PATTERN, outputJar, timestamp, 0); + addOtacert(outputJar, publicKeyFile, timestamp); signer.notifyClosing(); outputJar.close(); @@ -1156,8 +1153,9 @@ class SignApk { v1DigestAlgorithm[i] = getV1DigestAlgorithmForApk(publicKey[i], minSdkVersion); v1DigestAlgorithmBitSet |= v1DigestAlgorithm[i]; } - Manifest manifest = addDigestsToManifest(inputJar, v1DigestAlgorithmBitSet); - copyFiles(manifest, inputJar, outputJar, timestamp, alignment); + Manifest manifest = + addDigestsToManifest(inputJar, STRIP_PATTERN, v1DigestAlgorithmBitSet); + copyFiles(inputJar, STRIP_PATTERN, outputJar, timestamp, alignment); signFile( manifest, publicKey, privateKey, v1DigestAlgorithm, -- 2.11.0