Merge "No need to JAR-sign OTA update packages."
am: 094caf99aa
* commit '094caf99aab48c7ef62fd635503a0c70c18ecfde':
No need to JAR-sign OTA update packages.
Change-Id: I0a0e73cc5f64ba20600c30b9f304b0ff06705693
This commit is contained in:
@@ -200,10 +200,10 @@ class SignApk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files matching this pattern are not copied to the output.
|
/* Files matching this pattern are not copied to the output. */
|
||||||
private static Pattern stripPattern =
|
private static final Pattern STRIP_PATTERN =
|
||||||
Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|(" +
|
Pattern.compile("^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|("
|
||||||
Pattern.quote(JarFile.MANIFEST_NAME) + ")$");
|
+ Pattern.quote(JarFile.MANIFEST_NAME) + ")$");
|
||||||
|
|
||||||
private static X509Certificate readPublicKey(File file)
|
private static X509Certificate readPublicKey(File file)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
@@ -313,8 +313,9 @@ class SignApk {
|
|||||||
* Add the hash(es) of every file to the manifest, creating it if
|
* Add the hash(es) of every file to the manifest, creating it if
|
||||||
* necessary.
|
* necessary.
|
||||||
*/
|
*/
|
||||||
private static Manifest addDigestsToManifest(JarFile jar, int hashes)
|
private static Manifest addDigestsToManifest(
|
||||||
throws IOException, GeneralSecurityException {
|
JarFile jar, Pattern ignoredFilenamePattern, int hashes)
|
||||||
|
throws IOException, GeneralSecurityException {
|
||||||
Manifest input = jar.getManifest();
|
Manifest input = jar.getManifest();
|
||||||
Manifest output = new Manifest();
|
Manifest output = new Manifest();
|
||||||
Attributes main = output.getMainAttributes();
|
Attributes main = output.getMainAttributes();
|
||||||
@@ -350,8 +351,9 @@ class SignApk {
|
|||||||
|
|
||||||
for (JarEntry entry: byName.values()) {
|
for (JarEntry entry: byName.values()) {
|
||||||
String name = entry.getName();
|
String name = entry.getName();
|
||||||
if (!entry.isDirectory() &&
|
if (!entry.isDirectory()
|
||||||
(stripPattern == null || !stripPattern.matcher(name).matches())) {
|
&& (ignoredFilenamePattern == null
|
||||||
|
|| !ignoredFilenamePattern.matcher(name).matches())) {
|
||||||
InputStream data = jar.getInputStream(entry);
|
InputStream data = jar.getInputStream(entry);
|
||||||
while ((num = data.read(buffer)) > 0) {
|
while ((num = data.read(buffer)) > 0) {
|
||||||
if (md_sha1 != null) md_sha1.update(buffer, 0, num);
|
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
|
* Add a copy of the public key to the archive; this should
|
||||||
* exactly match one of the files in
|
* exactly match one of the files in
|
||||||
* /system/etc/security/otacerts.zip on the device. (The same
|
* /system/etc/security/otacerts.zip on the device. (The same
|
||||||
* cert can be extracted from the CERT.RSA file but this is much
|
* cert can be extracted from the OTA update package's signature
|
||||||
* easier to get at.)
|
* block but this is much easier to get at.)
|
||||||
*/
|
*/
|
||||||
private static void addOtacert(JarOutputStream outputJar,
|
private static void addOtacert(JarOutputStream outputJar,
|
||||||
File publicKeyFile,
|
File publicKeyFile,
|
||||||
long timestamp,
|
long timestamp)
|
||||||
Manifest manifest,
|
|
||||||
int hash)
|
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
MessageDigest md = MessageDigest.getInstance(hash == USE_SHA1 ? "SHA1" : "SHA256");
|
|
||||||
|
|
||||||
JarEntry je = new JarEntry(OTACERT_NAME);
|
JarEntry je = new JarEntry(OTACERT_NAME);
|
||||||
je.setTime(timestamp);
|
je.setTime(timestamp);
|
||||||
@@ -413,14 +412,8 @@ class SignApk {
|
|||||||
int read;
|
int read;
|
||||||
while ((read = input.read(b)) != -1) {
|
while ((read = input.read(b)) != -1) {
|
||||||
outputJar.write(b, 0, read);
|
outputJar.write(b, 0, read);
|
||||||
md.update(b, 0, read);
|
|
||||||
}
|
}
|
||||||
input.close();
|
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
|
* Copy all JAR entries from input to output. We set the modification times in the output to a
|
||||||
* the modification times in the output to a fixed time, so as to
|
* fixed time, so as to reduce variation in the output file and make incremental OTAs more
|
||||||
* reduce variation in the output file and make incremental OTAs
|
* efficient.
|
||||||
* more efficient.
|
|
||||||
*/
|
*/
|
||||||
private static void copyFiles(Manifest manifest, JarFile in, JarOutputStream out,
|
private static void copyFiles(JarFile in,
|
||||||
long timestamp, int defaultAlignment) throws IOException {
|
Pattern ignoredFilenamePattern,
|
||||||
|
JarOutputStream out,
|
||||||
|
long timestamp,
|
||||||
|
int defaultAlignment) throws IOException {
|
||||||
byte[] buffer = new byte[4096];
|
byte[] buffer = new byte[4096];
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
Map<String, Attributes> entries = manifest.getEntries();
|
ArrayList<String> names = new ArrayList<String>();
|
||||||
ArrayList<String> names = new ArrayList<String>(entries.keySet());
|
for (Enumeration<JarEntry> 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);
|
Collections.sort(names);
|
||||||
|
|
||||||
boolean firstEntry = true;
|
boolean firstEntry = true;
|
||||||
@@ -757,17 +763,8 @@ class SignApk {
|
|||||||
signer = new WholeFileSignerOutputStream(out, outputStream);
|
signer = new WholeFileSignerOutputStream(out, outputStream);
|
||||||
JarOutputStream outputJar = new JarOutputStream(signer);
|
JarOutputStream outputJar = new JarOutputStream(signer);
|
||||||
|
|
||||||
Manifest manifest = addDigestsToManifest(inputJar, hash);
|
copyFiles(inputJar, STRIP_PATTERN, outputJar, timestamp, 0);
|
||||||
copyFiles(manifest, inputJar, outputJar, timestamp, 0);
|
addOtacert(outputJar, publicKeyFile, timestamp);
|
||||||
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);
|
|
||||||
|
|
||||||
signer.notifyClosing();
|
signer.notifyClosing();
|
||||||
outputJar.close();
|
outputJar.close();
|
||||||
@@ -1156,8 +1153,9 @@ class SignApk {
|
|||||||
v1DigestAlgorithm[i] = getV1DigestAlgorithmForApk(publicKey[i], minSdkVersion);
|
v1DigestAlgorithm[i] = getV1DigestAlgorithmForApk(publicKey[i], minSdkVersion);
|
||||||
v1DigestAlgorithmBitSet |= v1DigestAlgorithm[i];
|
v1DigestAlgorithmBitSet |= v1DigestAlgorithm[i];
|
||||||
}
|
}
|
||||||
Manifest manifest = addDigestsToManifest(inputJar, v1DigestAlgorithmBitSet);
|
Manifest manifest =
|
||||||
copyFiles(manifest, inputJar, outputJar, timestamp, alignment);
|
addDigestsToManifest(inputJar, STRIP_PATTERN, v1DigestAlgorithmBitSet);
|
||||||
|
copyFiles(inputJar, STRIP_PATTERN, outputJar, timestamp, alignment);
|
||||||
signFile(
|
signFile(
|
||||||
manifest,
|
manifest,
|
||||||
publicKey, privateKey, v1DigestAlgorithm,
|
publicKey, privateKey, v1DigestAlgorithm,
|
||||||
|
Reference in New Issue
Block a user