Accept lineage for source stamps in signer

Bug: 169094510
Test: gradle test
Change-Id: I1ba4e276baebe304256822caa8a7f9892ee1570c
Merged-In: I1ba4e276baebe304256822caa8a7f9892ee1570c
diff --git a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
index 34e8f85..c7cb660 100644
--- a/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
+++ b/src/apksigner/java/com/android/apksigner/ApkSignerTool.java
@@ -147,8 +147,9 @@
         int maxSdkVersion = Integer.MAX_VALUE;
         List<SignerParams> signers = new ArrayList<>(1);
         SignerParams signerParams = new SignerParams();
-        SignerParams sourceStampSignerParams = new SignerParams();
         SigningCertificateLineage lineage = null;
+        SignerParams sourceStampSignerParams = new SignerParams();
+        SigningCertificateLineage sourceStampLineage = null;
         List<ProviderInstallSpec> providers = new ArrayList<>();
         ProviderInstallSpec providerParams = new ProviderInstallSpec();
         OptionsParser optionsParser = new OptionsParser(params);
@@ -252,6 +253,10 @@
             } else if ("stamp-signer".equals(optionName)) {
                 sourceStampFlagFound = true;
                 sourceStampSignerParams = processSignerParams(optionsParser);
+            } else if ("stamp-lineage".equals(optionName)) {
+                File stampLineageFile = new File(
+                        optionsParser.getRequiredValue("Stamp Lineage File"));
+                sourceStampLineage = getLineageFromInputFile(stampLineageFile);
             } else {
                 throw new ParameterException(
                         "Unsupported option: " + optionOriginalForm + ". See --help for supported"
@@ -358,7 +363,8 @@
             apkSignerBuilder.setV4SignatureOutputFile(outputV4SignatureFile);
         }
         if (sourceStampSignerConfig != null) {
-            apkSignerBuilder.setSourceStampSignerConfig(sourceStampSignerConfig);
+            apkSignerBuilder.setSourceStampSignerConfig(sourceStampSignerConfig)
+                    .setSourceStampSigningCertificateLineage(sourceStampLineage);
         }
         ApkSigner apkSigner = apkSignerBuilder.build();
         try {
@@ -578,7 +584,7 @@
         }
 
         @SuppressWarnings("resource") // false positive -- this resource is not opened here
-        PrintStream warningsOut = warningsTreatedAsErrors ? System.err : System.out;
+                PrintStream warningsOut = warningsTreatedAsErrors ? System.err : System.out;
         for (ApkVerifier.IssueWithParams warning : result.getWarnings()) {
             warningsEncountered = true;
             warningsOut.println("WARNING: " + warning);
@@ -976,10 +982,10 @@
 
     private static void printUsage(String page) {
         try (BufferedReader in =
-                new BufferedReader(
-                        new InputStreamReader(
-                                ApkSignerTool.class.getResourceAsStream(page),
-                                StandardCharsets.UTF_8))) {
+                     new BufferedReader(
+                             new InputStreamReader(
+                                     ApkSignerTool.class.getResourceAsStream(page),
+                                     StandardCharsets.UTF_8))) {
             String line;
             while ((line = in.readLine()) != null) {
                 System.out.println(line);
@@ -996,7 +1002,6 @@
      * @param name    the name to be used to identify the certificate.
      * @param verbose boolean indicating whether public key details from the certificate should be
      *                displayed.
-     *
      * @throws NoSuchAlgorithmException     if an instance of MD5, SHA-1, or SHA-256 cannot be
      *                                      obtained.
      * @throws CertificateEncodingException if an error is encountered when encoding the
diff --git a/src/main/java/com/android/apksig/ApkSigner.java b/src/main/java/com/android/apksig/ApkSigner.java
index 154e917..d4da569 100644
--- a/src/main/java/com/android/apksig/ApkSigner.java
+++ b/src/main/java/com/android/apksig/ApkSigner.java
@@ -86,6 +86,7 @@
 
     private final List<SignerConfig> mSignerConfigs;
     private final SignerConfig mSourceStampSignerConfig;
+    private final SigningCertificateLineage mSourceStampSigningCertificateLineage;
     private final boolean mForceSourceStampOverwrite;
     private final Integer mMinSdkVersion;
     private final boolean mV1SigningEnabled;
@@ -114,6 +115,7 @@
     private ApkSigner(
             List<SignerConfig> signerConfigs,
             SignerConfig sourceStampSignerConfig,
+            SigningCertificateLineage sourceStampSigningCertificateLineage,
             boolean forceSourceStampOverwrite,
             Integer minSdkVersion,
             boolean v1SigningEnabled,
@@ -136,6 +138,7 @@
 
         mSignerConfigs = signerConfigs;
         mSourceStampSignerConfig = sourceStampSignerConfig;
+        mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage;
         mForceSourceStampOverwrite = forceSourceStampOverwrite;
         mMinSdkVersion = minSdkVersion;
         mV1SigningEnabled = v1SigningEnabled;
@@ -304,6 +307,10 @@
                                         mSourceStampSignerConfig.getCertificates())
                                 .build());
             }
+            if (mSourceStampSigningCertificateLineage != null) {
+                signerEngineBuilder.setSourceStampSigningCertificateLineage(
+                        mSourceStampSigningCertificateLineage);
+            }
             signerEngine = signerEngineBuilder.build();
         }
 
@@ -1022,6 +1029,7 @@
     public static class Builder {
         private final List<SignerConfig> mSignerConfigs;
         private SignerConfig mSourceStampSignerConfig;
+        private SigningCertificateLineage mSourceStampSigningCertificateLineage;
         private boolean mForceSourceStampOverwrite = false;
         private boolean mV1SigningEnabled = true;
         private boolean mV2SigningEnabled = true;
@@ -1101,6 +1109,16 @@
         }
 
         /**
+         * Sets the source stamp {@link SigningCertificateLineage}. This structure provides proof of
+         * signing certificate rotation for certificates previously used to sign source stamps.
+         */
+        public Builder setSourceStampSigningCertificateLineage(
+                SigningCertificateLineage sourceStampSigningCertificateLineage) {
+            mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage;
+            return this;
+        }
+
+        /**
          * Sets whether the APK should overwrite existing source stamp, if found.
          *
          * @param force {@code true} to require the APK to be overwrite existing source stamp
@@ -1465,6 +1483,7 @@
             return new ApkSigner(
                     mSignerConfigs,
                     mSourceStampSignerConfig,
+                    mSourceStampSigningCertificateLineage,
                     mForceSourceStampOverwrite,
                     mMinSdkVersion,
                     mV1SigningEnabled,
diff --git a/src/main/java/com/android/apksig/DefaultApkSignerEngine.java b/src/main/java/com/android/apksig/DefaultApkSignerEngine.java
index f7fdef8..5fb2600 100644
--- a/src/main/java/com/android/apksig/DefaultApkSignerEngine.java
+++ b/src/main/java/com/android/apksig/DefaultApkSignerEngine.java
@@ -99,6 +99,7 @@
     private final String mCreatedBy;
     private final List<SignerConfig> mSignerConfigs;
     private final SignerConfig mSourceStampSignerConfig;
+    private final SigningCertificateLineage mSourceStampSigningCertificateLineage;
     private final int mMinSdkVersion;
     private final SigningCertificateLineage mSigningCertificateLineage;
 
@@ -161,6 +162,7 @@
     private DefaultApkSignerEngine(
             List<SignerConfig> signerConfigs,
             SignerConfig sourceStampSignerConfig,
+            SigningCertificateLineage sourceStampSigningCertificateLineage,
             int minSdkVersion,
             boolean v1SigningEnabled,
             boolean v2SigningEnabled,
@@ -191,6 +193,7 @@
         mCreatedBy = createdBy;
         mSignerConfigs = signerConfigs;
         mSourceStampSignerConfig = sourceStampSignerConfig;
+        mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage;
         mMinSdkVersion = minSdkVersion;
         mSigningCertificateLineage = signingCertificateLineage;
 
@@ -1474,6 +1477,7 @@
     public static class Builder {
         private List<SignerConfig> mSignerConfigs;
         private SignerConfig mStampSignerConfig;
+        private SigningCertificateLineage mSourceStampSigningCertificateLineage;
         private final int mMinSdkVersion;
 
         private boolean mV1SigningEnabled = true;
@@ -1565,6 +1569,7 @@
             return new DefaultApkSignerEngine(
                     mSignerConfigs,
                     mStampSignerConfig,
+                    mSourceStampSigningCertificateLineage,
                     mMinSdkVersion,
                     mV1SigningEnabled,
                     mV2SigningEnabled,
@@ -1583,6 +1588,16 @@
         }
 
         /**
+         * Sets the source stamp {@link SigningCertificateLineage}. This structure provides proof of
+         * signing certificate rotation for certificates previously used to sign source stamps.
+         */
+        public Builder setSourceStampSigningCertificateLineage(
+                SigningCertificateLineage sourceStampSigningCertificateLineage) {
+            mSourceStampSigningCertificateLineage = sourceStampSigningCertificateLineage;
+            return this;
+        }
+
+        /**
          * Sets whether the APK should be signed using JAR signing (aka v1 signature scheme).
          *
          * <p>By default, the APK will be signed using this scheme.