Snap for 9892340 from 27f77f53c7bbce5944b55b7d808e24e328623bc6 to tm-qpr3-release

Change-Id: I49393c8fc2c15f0f4ef469ae5d068d1fc0184c60
diff --git a/src/main/java/com/android/apksig/ApkVerifier.java b/src/main/java/com/android/apksig/ApkVerifier.java
index fc28864..8ae5f78 100644
--- a/src/main/java/com/android/apksig/ApkVerifier.java
+++ b/src/main/java/com/android/apksig/ApkVerifier.java
@@ -1853,6 +1853,16 @@
         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"),
@@ -2294,6 +2304,16 @@
                         + "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 f64064c..aedb352 100644
--- a/src/main/java/com/android/apksig/Constants.java
+++ b/src/main/java/com/android/apksig/Constants.java
@@ -35,6 +35,11 @@
     public static final int VERSION_APK_SIGNATURE_SCHEME_V31 = 31;
     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 ee3c9d8..3cb109e 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.Constants.OID_RSA_ENCRYPTION;
 import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoDigestAlgorithmOid;
 import static com.android.apksig.internal.pkcs7.AlgorithmIdentifier.getSignerInfoSignatureAlgorithm;
@@ -247,6 +248,11 @@
         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 0ebef0e..f3fd641 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;
@@ -306,6 +307,11 @@
                 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.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 @@
         // 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 @@
                 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 83e0499..aaa1b2f 100644
--- a/src/test/java/com/android/apksig/ApkSignerTest.java
+++ b/src/test/java/com/android/apksig/ApkSignerTest.java
@@ -838,6 +838,106 @@
     }
 
     @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 9de2b59..35944fa 100644
--- a/src/test/java/com/android/apksig/ApkVerifierTest.java
+++ b/src/test/java/com/android/apksig/ApkVerifierTest.java
@@ -252,6 +252,20 @@
     }
 
     @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).
@@ -637,6 +651,23 @@
     }
 
     @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
new file mode 100644
index 0000000..198beeb
--- /dev/null
+++ b/src/test/resources/com/android/apksig/v1-only-10-signers.apk
Binary files differ
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
new file mode 100644
index 0000000..95e6c61
--- /dev/null
+++ b/src/test/resources/com/android/apksig/v1-only-11-signers.apk
Binary files differ
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
new file mode 100644
index 0000000..ad34c14
--- /dev/null
+++ b/src/test/resources/com/android/apksig/v2-only-10-signers.apk
Binary files differ
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
new file mode 100644
index 0000000..674b6e4
--- /dev/null
+++ b/src/test/resources/com/android/apksig/v2-only-11-signers.apk
Binary files differ