diff options
author | Hajime Morrita <morrita@google.com> | 2021-04-07 22:54:39 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-04-07 22:54:39 +0000 |
commit | 80a8da9c6f45892979bfa64dcc41ed04f9358fc0 (patch) | |
tree | 8d7ce164e8ae0e6ecebf992e6d2c0163193e7a81 | |
parent | e4e7d57a4c15be9a89520fbdbc2560a9d55be485 (diff) | |
parent | bb8b0c83615288a71616e5f7072805df14aa80b8 (diff) | |
download | apksig-80a8da9c6f45892979bfa64dcc41ed04f9358fc0.tar.gz |
Add support for V1 signing with the pinlinst.meta file am: 88f873c6c7 am: bb8b0c8361
Original change: https://android-review.googlesource.com/c/platform/tools/apksig/+/1666086
Change-Id: I98ca73f6ae879b8cbe6df0deddfb8b4f22cc7891
-rw-r--r-- | src/main/java/com/android/apksig/ApkSigner.java | 61 | ||||
-rw-r--r-- | src/test/java/com/android/apksig/ApkSignerTest.java | 46 | ||||
-rw-r--r-- | src/test/resources/com/android/apksig/golden-pinsapp-signed.apk | bin | 0 -> 8732 bytes | |||
-rwxr-xr-x | src/test/resources/com/android/apksig/pinsapp-unsigned.apk | bin | 0 -> 2205 bytes |
4 files changed, 83 insertions, 24 deletions
diff --git a/src/main/java/com/android/apksig/ApkSigner.java b/src/main/java/com/android/apksig/ApkSigner.java index d4da569..8cca444 100644 --- a/src/main/java/com/android/apksig/ApkSigner.java +++ b/src/main/java/com/android/apksig/ApkSigner.java @@ -510,6 +510,28 @@ public class ApkSigner { } } + // Step 7.5. Generate pinlist.meta file if necessary. + // This has to be before the step 8 so that the file is signed. + if (pinByteRanges != null) { + // Covers JAR signature and zip central dir entry. + // The signature files don't have to be pinned, but pinning them isn't that wasteful + // since the total size is small. + pinByteRanges.add(new Hints.ByteRange(outputOffset, Long.MAX_VALUE)); + String entryName = Hints.PIN_BYTE_RANGE_ZIP_ENTRY_NAME; + byte[] uncompressedData = Hints.encodeByteRangeList(pinByteRanges); + + requestOutputEntryInspection(signerEngine, entryName, uncompressedData); + outputOffset += + outputDataToOutputApk( + entryName, + uncompressedData, + outputOffset, + outputCdRecords, + lastModifiedTimeForNewEntries, + lastModifiedDateForNewEntries, + outputApkOut); + } + // Step 8. Generate and output JAR signatures, if necessary. This may output more Local File // Header + data entries and add to the list of output Central Directory records. ApkSignerEngine.OutputJarSignatureRequest outputJarSignatureRequest = @@ -520,15 +542,7 @@ public class ApkSigner { String entryName = entry.getName(); byte[] uncompressedData = entry.getData(); - ApkSignerEngine.InspectJarEntryRequest inspectEntryRequest = - signerEngine.outputJarEntry(entryName); - if (inspectEntryRequest != null) { - inspectEntryRequest - .getDataSink() - .consume(uncompressedData, 0, uncompressedData.length); - inspectEntryRequest.done(); - } - + requestOutputEntryInspection(signerEngine, entryName, uncompressedData); outputOffset += outputDataToOutputApk( entryName, @@ -542,21 +556,6 @@ public class ApkSigner { outputJarSignatureRequest.done(); } - if (pinByteRanges != null) { - pinByteRanges.add(new Hints.ByteRange(outputOffset, Long.MAX_VALUE)); // central dir - String entryName = Hints.PIN_BYTE_RANGE_ZIP_ENTRY_NAME; - byte[] uncompressedData = Hints.encodeByteRangeList(pinByteRanges); - outputOffset += - outputDataToOutputApk( - entryName, - uncompressedData, - outputOffset, - outputCdRecords, - lastModifiedTimeForNewEntries, - lastModifiedDateForNewEntries, - outputApkOut); - } - // Step 9. Construct output ZIP Central Directory in an in-memory buffer long outputCentralDirSizeBytes = 0; for (CentralDirectoryRecord record : outputCdRecords) { @@ -616,6 +615,20 @@ public class ApkSigner { } } + private static void requestOutputEntryInspection( + ApkSignerEngine signerEngine, + String entryName, + byte[] uncompressedData) + throws IOException { + ApkSignerEngine.InspectJarEntryRequest inspectEntryRequest = + signerEngine.outputJarEntry(entryName); + if (inspectEntryRequest != null) { + inspectEntryRequest.getDataSink().consume( + uncompressedData, 0, uncompressedData.length); + inspectEntryRequest.done(); + } + } + private static long outputDataToOutputApk( String entryName, byte[] uncompressedData, diff --git a/src/test/java/com/android/apksig/ApkSignerTest.java b/src/test/java/com/android/apksig/ApkSignerTest.java index 40255a4..67f339f 100644 --- a/src/test/java/com/android/apksig/ApkSignerTest.java +++ b/src/test/java/com/android/apksig/ApkSignerTest.java @@ -46,6 +46,8 @@ import com.android.apksig.util.DataSource; import com.android.apksig.util.DataSources; import com.android.apksig.zip.ZipFormatException; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -365,6 +367,15 @@ public class ApkSignerTest { .setV2SigningEnabled(true) .setV3SigningEnabled(true) .setVerityEnabled(true)); + + signGolden( + "pinsapp-unsigned.apk", + new File(outDir, "golden-pinsapp-signed.apk"), + new ApkSigner.Builder(rsa2048SignerConfig) + .setV1SigningEnabled(true) + .setV2SigningEnabled(true) + .setV3SigningEnabled(true) + .setVerityEnabled(true)); } private static void signGolden( @@ -1249,6 +1260,41 @@ public class ApkSignerTest { assertSourceStampVerified(signedApk, sourceStampVerificationResult); } + @Test + public void testSignApk_Pinlist() throws Exception { + List<ApkSigner.SignerConfig> rsa2048SignerConfig = + Collections.singletonList( + getDefaultSignerConfigFromResources(FIRST_RSA_2048_SIGNER_RESOURCE_NAME)); + assertGolden( + "pinsapp-unsigned.apk", + "golden-pinsapp-signed.apk", + new ApkSigner.Builder(rsa2048SignerConfig) + .setV1SigningEnabled(true) + .setV2SigningEnabled(true) + .setV3SigningEnabled(true) + .setVerityEnabled(true)); + assertTrue("pinlist.meta file must be in the signed APK.", + resourceZipFileContains("golden-pinsapp-signed.apk", "pinlist.meta")); + } + + private static boolean resourceZipFileContains(String resourceName, String zipEntryName) + throws IOException { + ZipInputStream zip = new ZipInputStream( + Resources.toInputStream(ApkSignerTest.class, resourceName)); + while (true) { + ZipEntry entry = zip.getNextEntry(); + if (entry == null) { + break; + } + + if (entry.getName().equals(zipEntryName)) { + return true; + } + } + + return false; + } + private RSAPublicKey getRSAPublicKeyFromSigningBlock(File apk, int signatureVersionId) throws Exception { int signatureVersionBlockId; diff --git a/src/test/resources/com/android/apksig/golden-pinsapp-signed.apk b/src/test/resources/com/android/apksig/golden-pinsapp-signed.apk Binary files differnew file mode 100644 index 0000000..43c39f1 --- /dev/null +++ b/src/test/resources/com/android/apksig/golden-pinsapp-signed.apk diff --git a/src/test/resources/com/android/apksig/pinsapp-unsigned.apk b/src/test/resources/com/android/apksig/pinsapp-unsigned.apk Binary files differnew file mode 100755 index 0000000..b6a6e8f --- /dev/null +++ b/src/test/resources/com/android/apksig/pinsapp-unsigned.apk |