diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-12 15:57:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-05-12 15:57:28 +0000 |
commit | 5cad88e4e9c04b30d0706f8636159236aad92703 (patch) | |
tree | 478da93aabf9c04b3eb9ee6fa1b7fca17776fd52 | |
parent | c2b69bcc45dfac3a745e5f2fefcec42594dddb6c (diff) | |
parent | 6c589e93f0fcb5cf6b01afcad5e2747c6263a565 (diff) | |
download | apksig-5cad88e4e9c04b30d0706f8636159236aad92703.tar.gz |
Merge cherrypicks of ['googleplex-android-review.googlesource.com/22389785'] into sc-v2-platform-release.android-platform-12.1.0_r27android-platform-12.1.0_r26android-platform-12.1.0_r25android-platform-12.1.0_r24android-platform-12.1.0_r23android-platform-12.1.0_r22android-platform-12.1.0_r21android-platform-12.1.0_r20android-platform-12.1.0_r19android-platform-12.1.0_r18android-platform-12.1.0_r17android12L-platform-release
Change-Id: Ida7cc03cf1047b4443ef8fbf574f34ca78d585a3
-rw-r--r-- | src/main/java/com/android/apksig/ApkVerifier.java | 29 | ||||
-rw-r--r-- | src/main/java/com/android/apksig/Constants.java | 5 | ||||
-rw-r--r-- | src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java | 6 | ||||
-rw-r--r-- | src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java | 6 | ||||
-rw-r--r-- | src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java | 8 | ||||
-rw-r--r-- | src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java | 5 | ||||
-rw-r--r-- | src/test/java/com/android/apksig/ApkSignerTest.java | 100 | ||||
-rw-r--r-- | src/test/java/com/android/apksig/ApkVerifierTest.java | 31 | ||||
-rw-r--r-- | src/test/resources/com/android/apksig/v1-only-10-signers.apk | bin | 0 -> 18389 bytes | |||
-rw-r--r-- | src/test/resources/com/android/apksig/v1-only-11-signers.apk | bin | 0 -> 22297 bytes | |||
-rw-r--r-- | src/test/resources/com/android/apksig/v2-only-10-signers.apk | bin | 0 -> 20688 bytes | |||
-rw-r--r-- | src/test/resources/com/android/apksig/v2-only-11-signers.apk | bin | 0 -> 24784 bytes |
12 files changed, 190 insertions, 0 deletions
diff --git a/src/main/java/com/android/apksig/ApkVerifier.java b/src/main/java/com/android/apksig/ApkVerifier.java index 354dfbd..c0cc9c5 100644 --- a/src/main/java/com/android/apksig/ApkVerifier.java +++ b/src/main/java/com/android/apksig/ApkVerifier.java @@ -1198,6 +1198,15 @@ public class ApkVerifier { } private void mergeFrom(ApkSigningBlockUtils.Result source) { + if (source == null) { + return; + } + if (source.containsErrors()) { + mErrors.addAll(source.getErrors()); + } + if (source.containsWarnings()) { + mWarnings.addAll(source.getWarnings()); + } switch (source.signatureSchemeVersion) { case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2: mVerifiedUsingV2Scheme = source.verified; @@ -1718,6 +1727,16 @@ public class ApkVerifier { JAR_SIG_NO_SIGNATURES("No JAR signatures"), /** + * APK signature scheme v1 has exceeded the maximum number of jar signers. + * <ul> + * <li>Parameter 1: maximum allowed signers ({@code Integer})</li> + * <li>Parameter 2: total number of signers ({@code Integer})</li> + * </ul> + */ + JAR_SIG_MAX_SIGNATURES_EXCEEDED( + "APK Signature Scheme v1 only supports a maximum of %1$d signers, found %2$d"), + + /** * APK does not contain any entries covered by JAR signatures. */ JAR_SIG_NO_SIGNED_ZIP_ENTRIES("No JAR entries covered by JAR signatures"), @@ -2159,6 +2178,16 @@ public class ApkVerifier { + "no such signature was found. Signature stripped?"), /** + * APK signature scheme v2 has exceeded the maximum number of signers. + * <ul> + * <li>Parameter 1: maximum allowed signers ({@code Integer})</li> + * <li>Parameter 2: total number of signers ({@code Integer})</li> + * </ul> + */ + V2_SIG_MAX_SIGNATURES_EXCEEDED( + "APK Signature Scheme V2 only supports a maximum of %1$d signers, found %2$d"), + + /** * APK Signature Scheme v2 signature contains no signers. */ V2_SIG_NO_SIGNERS("No signers in APK Signature Scheme v2 signature"), diff --git a/src/main/java/com/android/apksig/Constants.java b/src/main/java/com/android/apksig/Constants.java index 680c5c3..c771aca 100644 --- a/src/main/java/com/android/apksig/Constants.java +++ b/src/main/java/com/android/apksig/Constants.java @@ -34,6 +34,11 @@ public class Constants { public static final int VERSION_APK_SIGNATURE_SCHEME_V3 = 3; public static final int VERSION_APK_SIGNATURE_SCHEME_V4 = 4; + /** + * The maximum number of signers supported by the v1 and v2 APK Signature Schemes. + */ + public static final int MAX_APK_SIGNERS = 10; + public static final String MANIFEST_ENTRY_NAME = V1SchemeConstants.MANIFEST_ENTRY_NAME; public static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = diff --git a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java index 85301ca..758ddd1 100644 --- a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java +++ b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeSigner.java @@ -16,6 +16,7 @@ package com.android.apksig.internal.apk.v1; +import static com.android.apksig.Constants.MAX_APK_SIGNERS; import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoDigestAlgorithmOid; import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoSignatureAlgorithm; @@ -246,6 +247,11 @@ public abstract class V1SchemeSigner { if (signerConfigs.isEmpty()) { throw new IllegalArgumentException("At least one signer config must be provided"); } + if (signerConfigs.size() > MAX_APK_SIGNERS) { + throw new IllegalArgumentException( + "APK Signature Scheme v1 only supports a maximum of " + MAX_APK_SIGNERS + ", " + + signerConfigs.size() + " provided"); + } OutputManifestFile manifest = generateManifestFile( jarEntryDigestAlgorithm, jarEntryDigests, sourceManifestBytes); diff --git a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java index 6d7e997..d3caeff 100644 --- a/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java +++ b/src/main/java/com/android/apksig/internal/apk/v1/V1SchemeVerifier.java @@ -16,6 +16,7 @@ package com.android.apksig.internal.apk.v1; +import static com.android.apksig.Constants.MAX_APK_SIGNERS; import static com.android.apksig.internal.oid.OidConstants.getSigAlgSupportedApiLevels; import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getJcaDigestAlgorithm; import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getJcaSignatureAlgorithm; @@ -301,6 +302,11 @@ public abstract class V1SchemeVerifier { result.addError(Issue.JAR_SIG_NO_SIGNATURES); return; } + if (signers.size() > MAX_APK_SIGNERS) { + result.addError(Issue.JAR_SIG_MAX_SIGNATURES_EXCEEDED, MAX_APK_SIGNERS, + signers.size()); + return; + } // Verify each signer's signature block file .(RSA|DSA|EC) against the corresponding // signature file .SF. Any error encountered for any signer terminates verification, to diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java index b69b7d3..06da96c 100644 --- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java +++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeSigner.java @@ -16,6 +16,7 @@ package com.android.apksig.internal.apk.v2; +import static com.android.apksig.Constants.MAX_APK_SIGNERS; import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedElements; import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeAsSequenceOfLengthPrefixedPairsOfIntAndLengthPrefixedBytes; import static com.android.apksig.internal.apk.ApkSigningBlockUtils.encodeCertificates; @@ -28,6 +29,7 @@ import com.android.apksig.internal.apk.SignatureAlgorithm; import com.android.apksig.internal.util.Pair; import com.android.apksig.util.DataSource; import com.android.apksig.util.RunnablesExecutor; + import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -184,6 +186,12 @@ public abstract class V2SchemeSigner { // FORMAT: // * length-prefixed sequence of length-prefixed signer blocks. + if (signerConfigs.size() > MAX_APK_SIGNERS) { + throw new IllegalArgumentException( + "APK Signature Scheme v2 only supports a maximum of " + MAX_APK_SIGNERS + ", " + + signerConfigs.size() + " provided"); + } + List<byte[]> signerBlocks = new ArrayList<>(signerConfigs.size()); if (preservedV2SignerBlocks != null && preservedV2SignerBlocks.size() > 0) { signerBlocks.addAll(preservedV2SignerBlocks); diff --git a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java index f367908..4d6e3e1 100644 --- a/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java +++ b/src/main/java/com/android/apksig/internal/apk/v2/V2SchemeVerifier.java @@ -16,6 +16,8 @@ package com.android.apksig.internal.apk.v2; +import static com.android.apksig.Constants.MAX_APK_SIGNERS; + import com.android.apksig.ApkVerifier.Issue; import com.android.apksig.apk.ApkFormatException; import com.android.apksig.apk.ApkUtils; @@ -222,6 +224,9 @@ public abstract class V2SchemeVerifier { return; } } + if (signerCount > MAX_APK_SIGNERS) { + result.addError(Issue.V2_SIG_MAX_SIGNATURES_EXCEEDED, MAX_APK_SIGNERS, signerCount); + } } /** diff --git a/src/test/java/com/android/apksig/ApkSignerTest.java b/src/test/java/com/android/apksig/ApkSignerTest.java index d799201..7dcf110 100644 --- a/src/test/java/com/android/apksig/ApkSignerTest.java +++ b/src/test/java/com/android/apksig/ApkSignerTest.java @@ -818,6 +818,106 @@ public class ApkSignerTest { } @Test + public void testV1SigningAllowedWithMaximumNumberOfSigners() throws Exception { + // The APK Signature Scheme v1 supports a maximum of 10 signers; this test verifies a + // signing config with the maximum number of signers is allowed to sign the APK. + List<ApkSigner.SignerConfig> signers = List.of( + getDefaultSignerConfigFromResources("dsa-1024"), + getDefaultSignerConfigFromResources("dsa-2048"), + getDefaultSignerConfigFromResources("dsa-3072"), + getDefaultSignerConfigFromResources("rsa-1024"), + getDefaultSignerConfigFromResources("rsa-2048"), + getDefaultSignerConfigFromResources("rsa-3072"), + getDefaultSignerConfigFromResources("rsa-4096"), + getDefaultSignerConfigFromResources("rsa-8192"), + getDefaultSignerConfigFromResources("ec-p256"), + getDefaultSignerConfigFromResources("ec-p384") + ); + sign("original.apk", + new ApkSigner.Builder(signers) + .setV1SigningEnabled(true) + .setV2SigningEnabled(false) + .setV3SigningEnabled(false) + .setV4SigningEnabled(false)); + } + + @Test + public void testV1SigningRejectedWithMoreThanMaximumNumberOfSigners() throws Exception { + // This test ensures a v1 signing config with more than the maximum supported number + // of signers will fail to sign. + List<ApkSigner.SignerConfig> signers = List.of( + getDefaultSignerConfigFromResources("dsa-1024"), + getDefaultSignerConfigFromResources("dsa-2048"), + getDefaultSignerConfigFromResources("dsa-3072"), + getDefaultSignerConfigFromResources("rsa-1024"), + getDefaultSignerConfigFromResources("rsa-2048"), + getDefaultSignerConfigFromResources("rsa-3072"), + getDefaultSignerConfigFromResources("rsa-4096"), + getDefaultSignerConfigFromResources("rsa-8192"), + getDefaultSignerConfigFromResources("ec-p256"), + getDefaultSignerConfigFromResources("ec-p384"), + getDefaultSignerConfigFromResources("ec-p521") + ); + assertThrows(IllegalArgumentException.class, () -> + sign("original.apk", + new ApkSigner.Builder(signers) + .setV1SigningEnabled(true) + .setV2SigningEnabled(false) + .setV3SigningEnabled(false) + .setV4SigningEnabled(false))); + } + + @Test + public void testV2SigningAllowedWithMaximumNumberOfSigners() throws Exception { + // The APK Signature Scheme v2 supports a maximum of 10 signers; this test verifies a + // signing config with the maximum number of signers is allowed to sign the APK. + List<ApkSigner.SignerConfig> signers = List.of( + getDefaultSignerConfigFromResources("dsa-1024"), + getDefaultSignerConfigFromResources("dsa-2048"), + getDefaultSignerConfigFromResources("dsa-3072"), + getDefaultSignerConfigFromResources("rsa-1024"), + getDefaultSignerConfigFromResources("rsa-2048"), + getDefaultSignerConfigFromResources("rsa-3072"), + getDefaultSignerConfigFromResources("rsa-4096"), + getDefaultSignerConfigFromResources("rsa-8192"), + getDefaultSignerConfigFromResources("ec-p256"), + getDefaultSignerConfigFromResources("ec-p384") + ); + sign("original.apk", + new ApkSigner.Builder(signers) + .setV1SigningEnabled(false) + .setV2SigningEnabled(true) + .setV3SigningEnabled(false) + .setV4SigningEnabled(false)); + } + + @Test + public void testV2SigningRejectedWithMoreThanMaximumNumberOfSigners() throws Exception { + // This test ensures a v2 signing config with more than the maximum supported number + // of signers will fail to sign. + List<ApkSigner.SignerConfig> signers = List.of( + getDefaultSignerConfigFromResources("dsa-1024"), + getDefaultSignerConfigFromResources("dsa-2048"), + getDefaultSignerConfigFromResources("dsa-3072"), + getDefaultSignerConfigFromResources("rsa-1024"), + getDefaultSignerConfigFromResources("rsa-2048"), + getDefaultSignerConfigFromResources("rsa-3072"), + getDefaultSignerConfigFromResources("rsa-4096"), + getDefaultSignerConfigFromResources("rsa-8192"), + getDefaultSignerConfigFromResources("ec-p256"), + getDefaultSignerConfigFromResources("ec-p384"), + getDefaultSignerConfigFromResources("ec-p521") + ); + assertThrows(IllegalArgumentException.class, () -> + sign("original.apk", + new ApkSigner.Builder(signers) + .setV1SigningEnabled(false) + .setV2SigningEnabled(true) + .setV3SigningEnabled(false) + .setV4SigningEnabled(false))); + } + + @Test public void testWeirdZipCompressionMethod() throws Exception { // Any ZIP compression method other than STORED is treated as DEFLATED by Android. // This APK declares compression method 21 (neither STORED nor DEFLATED) for CERT.RSA entry, diff --git a/src/test/java/com/android/apksig/ApkVerifierTest.java b/src/test/java/com/android/apksig/ApkVerifierTest.java index 9e1a75e..79950dc 100644 --- a/src/test/java/com/android/apksig/ApkVerifierTest.java +++ b/src/test/java/com/android/apksig/ApkVerifierTest.java @@ -245,6 +245,20 @@ public class ApkVerifierTest { } @Test + public void testV1MaxSupportedSignersAccepted() throws Exception { + // The APK Signature Scheme V1 supports a maximum of 10 signers; this test ensures an + // APK signed with that many signers successfully verifies. + assertVerified(verify("v1-only-10-signers.apk")); + } + + @Test + public void testV1MoreThanMaxSupportedSignersRejected() throws Exception { + // This test ensure an APK signed with more than the supported number of signers fails + // to verify. + assertVerificationFailure("v1-only-11-signers.apk", Issue.JAR_SIG_MAX_SIGNATURES_EXCEEDED); + } + + @Test public void testV2StrippedRejected() throws Exception { // APK signed with v1 and v2 schemes, but v2 signature was stripped from the file (by using // zipalign). @@ -630,6 +644,23 @@ public class ApkVerifierTest { } @Test + public void testV2MaxSupportedSignersAccepted() throws Exception { + // The APK Signature Scheme v2 supports a maximum of 10 signers; this test ensures an + // APK signed with that many signers successfully verifies. + assertVerified(verifyForMinSdkVersion("v2-only-10-signers.apk", AndroidSdkVersion.N)); + } + + @Test + public void testV2MoreThanMaxSupportedSignersRejected() throws Exception { + // This test ensure an APK signed with more than the supported number of signers fails + // to verify. + assertVerificationFailure( + verifyForMinSdkVersion("v2-only-11-signers.apk", AndroidSdkVersion.N), + Issue.V2_SIG_MAX_SIGNATURES_EXCEEDED); + } + + + @Test public void testCorrectCertUsedFromPkcs7SignedDataCertsSet() throws Exception { // Obtained by prepending the rsa-1024 certificate to the PKCS#7 SignedData certificates set // of v1-only-with-rsa-pkcs1-sha1-1.2.840.113549.1.1.1-2048.apk META-INF/CERT.RSA. The certs diff --git a/src/test/resources/com/android/apksig/v1-only-10-signers.apk b/src/test/resources/com/android/apksig/v1-only-10-signers.apk Binary files differnew file mode 100644 index 0000000..198beeb --- /dev/null +++ b/src/test/resources/com/android/apksig/v1-only-10-signers.apk diff --git a/src/test/resources/com/android/apksig/v1-only-11-signers.apk b/src/test/resources/com/android/apksig/v1-only-11-signers.apk Binary files differnew file mode 100644 index 0000000..95e6c61 --- /dev/null +++ b/src/test/resources/com/android/apksig/v1-only-11-signers.apk diff --git a/src/test/resources/com/android/apksig/v2-only-10-signers.apk b/src/test/resources/com/android/apksig/v2-only-10-signers.apk Binary files differnew file mode 100644 index 0000000..ad34c14 --- /dev/null +++ b/src/test/resources/com/android/apksig/v2-only-10-signers.apk diff --git a/src/test/resources/com/android/apksig/v2-only-11-signers.apk b/src/test/resources/com/android/apksig/v2-only-11-signers.apk Binary files differnew file mode 100644 index 0000000..674b6e4 --- /dev/null +++ b/src/test/resources/com/android/apksig/v2-only-11-signers.apk |