1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.apksig;
18 
19 import static com.android.apksig.internal.util.Resources.FIRST_RSA_1024_SIGNER_RESOURCE_NAME;
20 import static com.android.apksig.internal.util.Resources.FIRST_RSA_2048_SIGNER_RESOURCE_NAME;
21 import static com.android.apksig.internal.util.Resources.SECOND_RSA_1024_SIGNER_RESOURCE_NAME;
22 import static com.android.apksig.internal.util.Resources.SECOND_RSA_2048_SIGNER_RESOURCE_NAME;
23 // BEGIN-AOSP
24 import static com.android.apksig.internal.util.Resources.TEST_GCP_KEY_RING;
25 // END-AOSP
26 import static com.android.apksig.internal.util.Resources.THIRD_RSA_2048_SIGNER_RESOURCE_NAME;
27 
28 import static org.junit.Assert.assertEquals;
29 import static org.junit.Assert.assertFalse;
30 import static org.junit.Assert.assertThrows;
31 import static org.junit.Assert.assertTrue;
32 import static org.junit.Assert.fail;
33 import static org.junit.Assume.assumeNoException;
34 
35 import com.android.apksig.SigningCertificateLineage.SignerCapabilities;
36 import com.android.apksig.SigningCertificateLineage.SignerConfig;
37 import com.android.apksig.apk.ApkFormatException;
38 import com.android.apksig.internal.apk.ApkSigningBlockUtils;
39 import com.android.apksig.internal.apk.v3.V3SchemeConstants;
40 import com.android.apksig.internal.apk.v3.V3SchemeSigner;
41 import com.android.apksig.internal.util.ByteBufferUtils;
42 import com.android.apksig.internal.util.Resources;
43 // BEGIN-AOSP
44 import com.android.apksig.kms.aws.AwsSignerConfigGenerator;
45 import com.android.apksig.kms.aws.KeyAliasClient;
46 import com.android.apksig.kms.gcp.GcpSignerConfigGenerator;
47 import com.android.apksig.kms.gcp.KeyRingClient;
48 // END-AOSP
49 import com.android.apksig.util.DataSource;
50 
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.junit.runners.JUnit4;
55 
56 import java.io.File;
57 import java.nio.ByteBuffer;
58 import java.nio.ByteOrder;
59 import java.security.PrivateKey;
60 import java.security.cert.X509Certificate;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.Collections;
64 import java.util.HashSet;
65 import java.util.List;
66 import java.util.Set;
67 
68 @RunWith(JUnit4.class)
69 public class SigningCertificateLineageTest {
70 
71     // createLineageWithSignersFromResources and updateLineageWithSignerFromResources will add the
72     // SignerConfig for the signers added to the Lineage to this list.
73     private List<SignerConfig> mSigners;
74 
75     @Before
setUp()76     public void setUp() {
77         mSigners = new ArrayList<>();
78     }
79 
80     @Test
testLineageWithSingleSignerContainsExpectedSigner()81     public void testLineageWithSingleSignerContainsExpectedSigner() throws Exception {
82         SignerConfig signerConfig = Resources.toLineageSignerConfig(getClass(),
83                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
84 
85         SigningCertificateLineage lineage = new SigningCertificateLineage.Builder(
86                 signerConfig).build();
87 
88         assertLineageContainsExpectedSigners(lineage, FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
89     }
90 
91     @Test
testFirstRotationContainsExpectedSigners()92     public void testFirstRotationContainsExpectedSigners() throws Exception {
93         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
94                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
95         assertLineageContainsExpectedSigners(lineage, mSigners);
96         SignerConfig unknownSigner = Resources.toLineageSignerConfig(getClass(),
97                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
98         assertFalse("The signer " + unknownSigner.getCertificate().getSubjectDN()
99                 + " should not be in the lineage", lineage.isSignerInLineage(unknownSigner));
100     }
101 
102     @Test
testRotationWithExistingLineageContainsExpectedSigners()103     public void testRotationWithExistingLineageContainsExpectedSigners() throws Exception {
104         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
105                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
106         lineage = updateLineageWithSignerFromResources(lineage,
107                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
108         assertLineageContainsExpectedSigners(lineage, mSigners);
109     }
110 
111     @Test
testLineageFromBytesContainsExpectedSigners()112     public void testLineageFromBytesContainsExpectedSigners() throws Exception {
113         // This file contains the lineage with the three rsa-2048 signers
114         DataSource lineageDataSource = Resources.toDataSource(getClass(),
115                 "rsa-2048-lineage-3-signers");
116         SigningCertificateLineage lineage = SigningCertificateLineage.readFromBytes(
117                 lineageDataSource.getByteBuffer(0, (int) lineageDataSource.size()).array());
118         List<SignerConfig> signers = new ArrayList<>(3);
119         signers.add(
120                 Resources.toLineageSignerConfig(getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME));
121         signers.add(
122                 Resources.toLineageSignerConfig(getClass(), SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
123         signers.add(
124                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
125         assertLineageContainsExpectedSigners(lineage, signers);
126     }
127 
128     @Test
testLineageFromFileContainsExpectedSigners()129     public void testLineageFromFileContainsExpectedSigners() throws Exception {
130         // This file contains the lineage with the three rsa-2048 signers
131         DataSource lineageDataSource = Resources.toDataSource(getClass(),
132                 "rsa-2048-lineage-3-signers");
133         SigningCertificateLineage lineage = SigningCertificateLineage.readFromDataSource(
134                 lineageDataSource);
135         List<SignerConfig> signers = new ArrayList<>(3);
136         signers.add(
137                 Resources.toLineageSignerConfig(getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME));
138         signers.add(
139                 Resources.toLineageSignerConfig(getClass(), SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
140         signers.add(
141                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
142         assertLineageContainsExpectedSigners(lineage, signers);
143     }
144 
145     @Test
testLineageFromFileDoesNotContainUnknownSigner()146     public void testLineageFromFileDoesNotContainUnknownSigner() throws Exception {
147         // This file contains the lineage with the first two rsa-2048 signers
148         SigningCertificateLineage lineage = Resources.toSigningCertificateLineage(getClass(),
149                 "rsa-2048-lineage-2-signers");
150         SignerConfig unknownSigner = Resources.toLineageSignerConfig(getClass(),
151                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
152         assertFalse("The signer " + unknownSigner.getCertificate().getSubjectDN()
153                 + " should not be in the lineage", lineage.isSignerInLineage(unknownSigner));
154     }
155 
156     @Test(expected = IllegalArgumentException.class)
testLineageFromFileWithInvalidMagicFails()157     public void testLineageFromFileWithInvalidMagicFails() throws Exception {
158         // This file contains the lineage with two rsa-2048 signers and a modified MAGIC value
159         Resources.toSigningCertificateLineage(getClass(), "rsa-2048-lineage-invalid-magic");
160     }
161 
162     @Test(expected = IllegalArgumentException.class)
testLineageFromFileWithInvalidVersionFails()163     public void testLineageFromFileWithInvalidVersionFails() throws Exception {
164         // This file contains the lineage with two rsa-2048 signers and an invalid value of FF for
165         // the version
166         Resources.toSigningCertificateLineage(getClass(), "rsa-2048-lineage-invalid-version");
167     }
168 
169     @Test
testLineageWrittenToBytesContainsExpectedSigners()170     public void testLineageWrittenToBytesContainsExpectedSigners() throws Exception {
171         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
172                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
173         lineage = updateLineageWithSignerFromResources(lineage,
174                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
175         byte[] lineageBytes = lineage.getBytes();
176         lineage = SigningCertificateLineage.readFromBytes(lineageBytes);
177         assertLineageContainsExpectedSigners(lineage, mSigners);
178     }
179 
180     @Test
testLineageWrittenToFileContainsExpectedSigners()181     public void testLineageWrittenToFileContainsExpectedSigners() throws Exception {
182         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
183                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
184         lineage = updateLineageWithSignerFromResources(lineage,
185                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
186         File lineageFile = File.createTempFile(getClass().getSimpleName(), ".bin");
187         lineageFile.deleteOnExit();
188         lineage.writeToFile(lineageFile);
189         lineage = SigningCertificateLineage.readFromFile(lineageFile);
190         assertLineageContainsExpectedSigners(lineage, mSigners);
191     }
192 
193     @Test
testUpdatedCapabilitiesInLineage()194     public void testUpdatedCapabilitiesInLineage() throws Exception {
195         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
196                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
197         SignerConfig oldSignerConfig = mSigners.get(0);
198         List<Boolean> expectedCapabilityValues = Arrays.asList(false, false, false, false, false);
199         SignerCapabilities newCapabilities = buildSignerCapabilities(expectedCapabilityValues);
200         lineage.updateSignerCapabilities(oldSignerConfig, newCapabilities);
201         SignerCapabilities updatedCapabilities = lineage.getSignerCapabilities(oldSignerConfig);
202         assertExpectedCapabilityValues(updatedCapabilities, expectedCapabilityValues);
203     }
204 
205     @Test
testUpdatedCapabilitiesInLineageWrittenToFile()206     public void testUpdatedCapabilitiesInLineageWrittenToFile() throws Exception {
207         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
208                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
209         SignerConfig oldSignerConfig = mSigners.get(0);
210         List<Boolean> expectedCapabilityValues = Arrays.asList(false, false, false, false, false);
211         SignerCapabilities newCapabilities = buildSignerCapabilities(expectedCapabilityValues);
212         lineage.updateSignerCapabilities(oldSignerConfig, newCapabilities);
213         File lineageFile = File.createTempFile(getClass().getSimpleName(), ".bin");
214         lineageFile.deleteOnExit();
215         lineage.writeToFile(lineageFile);
216         lineage = SigningCertificateLineage.readFromFile(lineageFile);
217         SignerCapabilities updatedCapabilities = lineage.getSignerCapabilities(oldSignerConfig);
218         assertExpectedCapabilityValues(updatedCapabilities, expectedCapabilityValues);
219     }
220 
221     @Test
testCapabilitiesAreNotUpdatedWithDefaultValues()222     public void testCapabilitiesAreNotUpdatedWithDefaultValues() throws Exception {
223         // This file contains the lineage with the first two rsa-2048 signers with the first signer
224         // having all of the capabilities set to false.
225         SigningCertificateLineage lineage = Resources.toSigningCertificateLineage(getClass(),
226                 "rsa-2048-lineage-no-capabilities-first-signer");
227         List<Boolean> expectedCapabilityValues = Arrays.asList(false, false, false, false, false);
228         SignerConfig oldSignerConfig = Resources.toLineageSignerConfig(getClass(),
229                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
230         SignerCapabilities oldSignerCapabilities = lineage.getSignerCapabilities(oldSignerConfig);
231         assertExpectedCapabilityValues(oldSignerCapabilities, expectedCapabilityValues);
232         // The builder is called directly to ensure all of the capabilities are set to the default
233         // values and the caller configured flags are not modified in this SignerCapabilities.
234         SignerCapabilities newCapabilities = new SignerCapabilities.Builder().build();
235         lineage.updateSignerCapabilities(oldSignerConfig, newCapabilities);
236         SignerCapabilities updatedCapabilities = lineage.getSignerCapabilities(oldSignerConfig);
237         assertExpectedCapabilityValues(updatedCapabilities, expectedCapabilityValues);
238     }
239 
240     @Test
testUpdatedCapabilitiesInLineageByCertificate()241     public void testUpdatedCapabilitiesInLineageByCertificate() throws Exception {
242         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
243                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
244         X509Certificate oldSignerCertificate = mSigners.get(0).getCertificate();
245         List<Boolean> expectedCapabilityValues = Arrays.asList(false, false, false, false, false);
246         SignerCapabilities newCapabilities = buildSignerCapabilities(expectedCapabilityValues);
247 
248         lineage.updateSignerCapabilities(oldSignerCertificate, newCapabilities);
249 
250         assertExpectedCapabilityValues(lineage.getSignerCapabilities(oldSignerCertificate),
251                 expectedCapabilityValues);
252     }
253 
254     @Test
testUpdateSignerCapabilitiesCertificateNotInLineageThrowsException()255     public void testUpdateSignerCapabilitiesCertificateNotInLineageThrowsException()
256             throws Exception {
257         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
258                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
259         X509Certificate certificate = getSignerConfigFromResources(
260                 FIRST_RSA_1024_SIGNER_RESOURCE_NAME).getCertificate();
261         List<Boolean> expectedCapabilityValues = Arrays.asList(false, false, false, false, false);
262         SignerCapabilities newCapabilities = buildSignerCapabilities(expectedCapabilityValues);
263 
264         assertThrows(IllegalArgumentException.class, () ->
265                 lineage.updateSignerCapabilities(certificate, newCapabilities));
266     }
267 
268     @Test
testFirstRotationWitNonDefaultCapabilitiesForSigners()269     public void testFirstRotationWitNonDefaultCapabilitiesForSigners() throws Exception {
270         SignerConfig oldSigner = Resources.toLineageSignerConfig(getClass(),
271                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
272         SignerConfig newSigner = Resources.toLineageSignerConfig(getClass(),
273                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
274         List<Boolean> oldSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
275         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, true, false, false, false);
276         SigningCertificateLineage lineage = new SigningCertificateLineage.Builder(oldSigner,
277                 newSigner)
278                 .setOriginalCapabilities(buildSignerCapabilities(oldSignerCapabilityValues))
279                 .setNewCapabilities(buildSignerCapabilities(newSignerCapabilityValues))
280                 .build();
281         SignerCapabilities oldSignerCapabilities = lineage.getSignerCapabilities(oldSigner);
282         assertExpectedCapabilityValues(oldSignerCapabilities, oldSignerCapabilityValues);
283         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
284         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
285     }
286 
287     // BEGIN-AOSP
288     @Test
289     public void
testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_previousSignerAws()290             testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_previousSignerAws()
291                     throws Exception {
292         try (KeyAliasClient client = new KeyAliasClient()) {
293             client.listKeyAliases();
294         } catch (Exception e) {
295             assumeNoException("Test cannot run without access to test data in AWS", e);
296         }
297         SigningCertificateLineage lineage =
298                 createLineageWithSignersFromResources(
299                         Resources.toLineageSignerConfig(
300                                 getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME),
301                         AwsSignerConfigGenerator.getLineageSignerConfigFromResources(
302                                 getClass(), SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
303         SignerConfig oldSigner = mSigners.get(mSigners.size() - 1);
304         SignerConfig newSigner =
305                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
306         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
307         lineage =
308                 lineage.spawnDescendant(
309                         oldSigner, newSigner, buildSignerCapabilities(newSignerCapabilityValues));
310         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
311         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
312     }
313     // END-AOSP
314 
315     // BEGIN-AOSP
316     @Test
317     public void
testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_originalSignerAws()318             testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_originalSignerAws()
319                     throws Exception {
320         try (KeyAliasClient client = new KeyAliasClient()) {
321             client.listKeyAliases();
322         } catch (Exception e) {
323             assumeNoException("Test cannot run without access to test data in AWS", e);
324         }
325         SigningCertificateLineage lineage =
326                 createLineageWithSignersFromResources(
327                         AwsSignerConfigGenerator.getLineageSignerConfigFromResources(
328                                 getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME),
329                         Resources.toLineageSignerConfig(
330                                 getClass(), SECOND_RSA_1024_SIGNER_RESOURCE_NAME));
331         SignerConfig oldSigner = mSigners.get(mSigners.size() - 1);
332         SignerConfig newSigner =
333                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
334         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
335         lineage =
336                 lineage.spawnDescendant(
337                         oldSigner, newSigner, buildSignerCapabilities(newSignerCapabilityValues));
338         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
339         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
340     }
341     // END-AOSP
342 
343     // BEGIN-AOSP
344     @Test
345     public void
testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_previousSignerGcp()346             testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_previousSignerGcp()
347                     throws Exception {
348         try (KeyRingClient keyRingClient = new KeyRingClient(TEST_GCP_KEY_RING)) {
349             keyRingClient.getKeyRing();
350         } catch (Exception e) {
351             assumeNoException("Test cannot run without access to test data in GCP", e);
352         }
353         SigningCertificateLineage lineage =
354                 createLineageWithSignersFromResources(
355                         Resources.toLineageSignerConfig(
356                                 getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME),
357                         GcpSignerConfigGenerator.getLineageSignerConfigFromResources(
358                                 getClass(), SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
359         SignerConfig oldSigner = mSigners.get(mSigners.size() - 1);
360         SignerConfig newSigner =
361                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
362         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
363         lineage =
364                 lineage.spawnDescendant(
365                         oldSigner, newSigner, buildSignerCapabilities(newSignerCapabilityValues));
366         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
367         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
368     }
369     // END-AOSP
370 
371     // BEGIN-AOSP
372     @Test
373     public void
testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_originalSignerGcp()374             testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner_originalSignerGcp()
375                     throws Exception {
376         try (KeyRingClient keyRingClient = new KeyRingClient(TEST_GCP_KEY_RING)) {
377             keyRingClient.getKeyRing();
378         } catch (Exception e) {
379             assumeNoException("Test cannot run without access to test data in GCP", e);
380         }
381         SigningCertificateLineage lineage =
382                 createLineageWithSignersFromResources(
383                         GcpSignerConfigGenerator.getLineageSignerConfigFromResources(
384                                 getClass(), FIRST_RSA_2048_SIGNER_RESOURCE_NAME),
385                         Resources.toLineageSignerConfig(
386                                 getClass(), SECOND_RSA_1024_SIGNER_RESOURCE_NAME));
387         SignerConfig oldSigner = mSigners.get(mSigners.size() - 1);
388         SignerConfig newSigner =
389                 Resources.toLineageSignerConfig(getClass(), THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
390         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
391         lineage =
392                 lineage.spawnDescendant(
393                         oldSigner, newSigner, buildSignerCapabilities(newSignerCapabilityValues));
394         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
395         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
396     }
397     // END-AOSP
398 
399     @Test
testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner()400     public void testRotationWithExitingLineageAndNonDefaultCapabilitiesForNewSigner()
401             throws Exception {
402         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
403                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
404         SignerConfig oldSigner = mSigners.get(mSigners.size() - 1);
405         SignerConfig newSigner = Resources.toLineageSignerConfig(getClass(),
406                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
407         List<Boolean> newSignerCapabilityValues = Arrays.asList(false, false, false, false, false);
408         lineage = lineage.spawnDescendant(oldSigner, newSigner,
409                 buildSignerCapabilities(newSignerCapabilityValues));
410         SignerCapabilities newSignerCapabilities = lineage.getSignerCapabilities(newSigner);
411         assertExpectedCapabilityValues(newSignerCapabilities, newSignerCapabilityValues);
412     }
413 
414     @Test(expected = IllegalArgumentException.class)
testRotationWithExistingLineageUsingNonParentSignerFails()415     public void testRotationWithExistingLineageUsingNonParentSignerFails() throws Exception {
416         // When rotating the signing certificate the most recent signer must be provided to the
417         // spawnDescendant method. This test ensures that using an ancestor of the most recent
418         // signer will fail as expected.
419         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
420                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
421         SignerConfig oldestSigner = mSigners.get(0);
422         SignerConfig newSigner = Resources.toLineageSignerConfig(getClass(),
423                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
424         lineage.spawnDescendant(oldestSigner, newSigner);
425     }
426 
427     @Test
testLineageFromV3SignerAttribute()428     public void testLineageFromV3SignerAttribute() throws Exception {
429         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
430                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
431         // The format of the V3 Signer Attribute is as follows (little endian):
432         // * length-prefixed bytes: attribute pair
433         //   * uint32: ID
434         //   * bytes: value - encoded V3 SigningCertificateLineage
435         ByteBuffer v3SignerAttribute = ByteBuffer.wrap(
436                 V3SchemeSigner.generateV3SignerAttribute(lineage));
437         v3SignerAttribute.order(ByteOrder.LITTLE_ENDIAN);
438         ByteBuffer attribute = ApkSigningBlockUtils.getLengthPrefixedSlice(v3SignerAttribute);
439         // The generateV3SignerAttribute method should only use the PROOF_OF_ROTATION_ATTR_ID
440         // value for the ID.
441         int id = attribute.getInt();
442         assertEquals(
443                 "The ID of the v3SignerAttribute ByteBuffer is not the expected "
444                         + "PROOF_OF_ROTATION_ATTR_ID",
445                 V3SchemeConstants.PROOF_OF_ROTATION_ATTR_ID, id);
446         lineage = SigningCertificateLineage.readFromV3AttributeValue(
447                 ByteBufferUtils.toByteArray(attribute));
448         assertLineageContainsExpectedSigners(lineage, mSigners);
449     }
450 
451     @Test
testSortedSignerConfigsAreInSortedOrder()452     public void testSortedSignerConfigsAreInSortedOrder() throws Exception {
453         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
454                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
455         DefaultApkSignerEngine.SignerConfig oldSigner = getApkSignerEngineSignerConfigFromResources(
456                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
457         DefaultApkSignerEngine.SignerConfig newSigner = getApkSignerEngineSignerConfigFromResources(
458                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
459         List<DefaultApkSignerEngine.SignerConfig> signers = Arrays.asList(newSigner, oldSigner);
460         List<DefaultApkSignerEngine.SignerConfig> sortedSigners = lineage.sortSignerConfigs(
461                 signers);
462         assertEquals("The sorted signer list does not contain the expected number of elements",
463                 signers.size(), sortedSigners.size());
464         assertEquals("The first element in the sorted list should be the first signer", oldSigner,
465                 sortedSigners.get(0));
466         assertEquals("The second element in the sorted list should be the second signer", newSigner,
467                 sortedSigners.get(1));
468     }
469 
470     @Test(expected = IllegalArgumentException.class)
testSortedSignerConfigsWithUnknownSignerFails()471     public void testSortedSignerConfigsWithUnknownSignerFails() throws Exception {
472         // Since this test includes a signer that is not in the lineage the sort should fail with
473         // an IllegalArgumentException.
474         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
475                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
476         DefaultApkSignerEngine.SignerConfig oldSigner = getApkSignerEngineSignerConfigFromResources(
477                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
478         DefaultApkSignerEngine.SignerConfig newSigner = getApkSignerEngineSignerConfigFromResources(
479                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
480         DefaultApkSignerEngine.SignerConfig unknownSigner =
481                 getApkSignerEngineSignerConfigFromResources(THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
482         List<DefaultApkSignerEngine.SignerConfig> signers = Arrays.asList(newSigner, oldSigner,
483                 unknownSigner);
484         lineage.sortSignerConfigs(signers);
485     }
486 
487     @Test
testIsCertificateLatestInLineageWithLatestCertReturnsTrue()488     public void testIsCertificateLatestInLineageWithLatestCertReturnsTrue() throws Exception {
489         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
490                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
491                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
492         DefaultApkSignerEngine.SignerConfig latestSigner =
493                 getApkSignerEngineSignerConfigFromResources(THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
494 
495         assertTrue(lineage.isCertificateLatestInLineage(latestSigner.getCertificates().get(0)));
496     }
497 
498     @Test
testIsCertificateLatestInLineageWithOlderCertReturnsFalse()499     public void testIsCertificateLatestInLineageWithOlderCertReturnsFalse() throws Exception {
500         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
501                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
502                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
503         DefaultApkSignerEngine.SignerConfig olderSigner =
504                 getApkSignerEngineSignerConfigFromResources(SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
505 
506         assertFalse(lineage.isCertificateLatestInLineage(olderSigner.getCertificates().get(0)));
507     }
508 
509     @Test
testIsCertificateLatestInLineageWithUnknownCertReturnsFalse()510     public void testIsCertificateLatestInLineageWithUnknownCertReturnsFalse() throws Exception {
511         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
512                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
513         DefaultApkSignerEngine.SignerConfig unknownSigner =
514                 getApkSignerEngineSignerConfigFromResources(THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
515 
516         assertFalse(lineage.isCertificateLatestInLineage(unknownSigner.getCertificates().get(0)));
517     }
518 
519     @Test
testAllExpectedCertificatesAreInLineage()520     public void testAllExpectedCertificatesAreInLineage() throws Exception {
521         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
522                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
523         lineage = updateLineageWithSignerFromResources(lineage,
524                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
525         Set<X509Certificate> expectedCertSet = new HashSet<>();
526         for (int i = 0; i < mSigners.size(); i++) {
527             expectedCertSet.add(mSigners.get(i).getCertificate());
528         }
529         List<X509Certificate> certs = lineage.getCertificatesInLineage();
530         assertEquals(
531                 "The number of elements in the certificate list from the lineage does not equal "
532                         + "the expected number",
533                 expectedCertSet.size(), certs.size());
534         for (X509Certificate cert : certs) {
535             // remove the certificate from the Set to ensure duplicate certs were not returned.
536             assertTrue("An unexpected certificate, " + cert.getSubjectDN() + ", is in the lineage",
537                     expectedCertSet.remove(cert));
538         }
539     }
540 
541     @Test
testSublineageContainsExpectedSigners()542     public void testSublineageContainsExpectedSigners() throws Exception {
543         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
544                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
545         lineage = updateLineageWithSignerFromResources(lineage,
546                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
547         List<SignerConfig> subList = mSigners.subList(0, 2);
548         X509Certificate cert = subList.get(1).getCertificate();
549         SigningCertificateLineage subLineage = lineage.getSubLineage(cert);
550         assertLineageContainsExpectedSigners(subLineage, subList);
551     }
552 
553     @Test
testConsolidatedLineageContainsExpectedSigners()554     public void testConsolidatedLineageContainsExpectedSigners() throws Exception {
555         SigningCertificateLineage lineage = createLineageWithSignersFromResources(
556                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
557         SigningCertificateLineage updatedLineage = updateLineageWithSignerFromResources(lineage,
558                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
559         List<SigningCertificateLineage> lineages = Arrays.asList(lineage, updatedLineage);
560         SigningCertificateLineage consolidatedLineage =
561                 SigningCertificateLineage.consolidateLineages(lineages);
562         assertLineageContainsExpectedSigners(consolidatedLineage, mSigners);
563     }
564 
565     @Test(expected = IllegalArgumentException.class)
testConsolidatedLineageWithDisjointLineagesFail()566     public void testConsolidatedLineageWithDisjointLineagesFail() throws Exception {
567         List<SigningCertificateLineage> lineages = new ArrayList<>();
568         lineages.add(createLineageWithSignersFromResources(FIRST_RSA_1024_SIGNER_RESOURCE_NAME,
569                 SECOND_RSA_1024_SIGNER_RESOURCE_NAME));
570         lineages.add(createLineageWithSignersFromResources(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
571                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
572         SigningCertificateLineage.consolidateLineages(lineages);
573     }
574 
575     @Test
testLineageFromAPKContainsExpectedSigners()576     public void testLineageFromAPKContainsExpectedSigners() throws Exception {
577         SignerConfig firstSigner = getSignerConfigFromResources(
578                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
579         SignerConfig secondSigner = getSignerConfigFromResources(
580                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
581         SignerConfig thirdSigner = getSignerConfigFromResources(
582                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
583         List<SignerConfig> expectedSigners = Arrays.asList(firstSigner, secondSigner, thirdSigner);
584         DataSource apkDataSource = Resources.toDataSource(getClass(),
585                 "v1v2v3-with-rsa-2048-lineage-3-signers.apk");
586         SigningCertificateLineage lineageFromApk = SigningCertificateLineage.readFromApkDataSource(
587                 apkDataSource);
588         assertLineageContainsExpectedSigners(lineageFromApk, expectedSigners);
589     }
590 
591     @Test
testLineageFromAPKWithV31BlockContainsExpectedSigners()592     public void testLineageFromAPKWithV31BlockContainsExpectedSigners() throws Exception {
593         SignerConfig firstSigner = getSignerConfigFromResources(
594                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
595         SignerConfig secondSigner = getSignerConfigFromResources(
596                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
597         List<SignerConfig> expectedSigners = Arrays.asList(firstSigner, secondSigner);
598         DataSource apkDataSource = Resources.toDataSource(getClass(),
599                 "v31-rsa-2048_2-tgt-34-1-tgt-28.apk");
600         SigningCertificateLineage lineageFromApk = SigningCertificateLineage.readFromApkDataSource(
601                 apkDataSource);
602         assertLineageContainsExpectedSigners(lineageFromApk, expectedSigners);
603     }
604 
605     @Test
testOnlyV31LineageFromAPKWithV31BlockContainsExpectedSigners()606     public void testOnlyV31LineageFromAPKWithV31BlockContainsExpectedSigners() throws Exception {
607         SignerConfig firstSigner = getSignerConfigFromResources(
608             FIRST_RSA_2048_SIGNER_RESOURCE_NAME);
609         SignerConfig secondSigner = getSignerConfigFromResources(
610             SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
611         List<SignerConfig> expectedSigners = Arrays.asList(firstSigner, secondSigner);
612         DataSource apkDataSource = Resources.toDataSource(getClass(),
613             "v31-rsa-2048_2-tgt-34-1-tgt-28.apk");
614         SigningCertificateLineage lineageFromApk =
615             SigningCertificateLineage.readV31FromApkDataSource(
616                 apkDataSource);
617         assertLineageContainsExpectedSigners(lineageFromApk, expectedSigners);
618     }
619 
620 
621     @Test(expected = ApkFormatException.class)
testLineageFromAPKWithInvalidZipCDSizeFails()622     public void testLineageFromAPKWithInvalidZipCDSizeFails() throws Exception {
623         // This test verifies that attempting to read the lineage from an APK where the zip
624         // sections cannot be parsed fails. This APK is based off the
625         // v1v2v3-with-rsa-2048-lineage-3-signers.apk with a modified CD size in the EoCD.
626         DataSource apkDataSource = Resources.toDataSource(getClass(),
627                 "v1v2v3-with-rsa-2048-lineage-3-signers-invalid-zip.apk");
628         SigningCertificateLineage.readFromApkDataSource(apkDataSource);
629     }
630 
631     @Test
testLineageFromAPKWithNoLineageFails()632     public void testLineageFromAPKWithNoLineageFails() throws Exception {
633         // This test verifies that attempting to read the lineage from an APK without a lineage
634         // fails.
635         // This is a valid APK that has only been signed with the V1 and V2 signature schemes;
636         // since the lineage is an attribute in the V3 signature block this test should fail.
637         DataSource apkDataSource = Resources.toDataSource(getClass(),
638                 "golden-aligned-v1v2-out.apk");
639         try {
640             SigningCertificateLineage.readFromApkDataSource(apkDataSource);
641             fail("A failure should have been reported due to the APK not containing a V3 signing "
642                     + "block");
643         } catch (IllegalArgumentException expected) {}
644 
645         // This is a valid APK signed with the V1, V2, and V3 signature schemes, but there is no
646         // lineage in the V3 signature block.
647         apkDataSource = Resources.toDataSource(getClass(), "golden-aligned-v1v2v3-out.apk");
648         try {
649             SigningCertificateLineage.readFromApkDataSource(apkDataSource);
650             fail("A failure should have been reported due to the APK containing a V3 signing "
651                     + "block without the lineage attribute");
652         } catch (IllegalArgumentException expected) {}
653 
654         // This APK is based off the v1v2v3-with-rsa-2048-lineage-3-signers.apk with a bit flip
655         // in the lineage attribute ID in the V3 signature block.
656         apkDataSource = Resources.toDataSource(getClass(),
657                 "v1v2v3-with-rsa-2048-lineage-3-signers-invalid-lineage-attr.apk");
658         try {
659             SigningCertificateLineage.readFromApkDataSource(apkDataSource);
660             fail("A failure should have been reported due to the APK containing a V3 signing "
661                     + "block with a modified lineage attribute ID");
662         } catch (IllegalArgumentException expected) {}
663     }
664 
665     @Test
testV31LineageFromAPKWithNoV31LineageFails()666     public void testV31LineageFromAPKWithNoV31LineageFails() throws Exception {
667         DataSource apkDataSource = Resources.toDataSource(getClass(),
668             "golden-aligned-v1v2-out.apk");
669         try {
670             SigningCertificateLineage.readV31FromApkDataSource(apkDataSource);
671             fail("A failure should have been reported due to the APK not containing a V3 signing "
672                 + "block");
673         } catch (IllegalArgumentException expected) {}
674 
675         // This is a valid APK signed with the V1, V2, and V3 signature schemes, but there is no
676         // lineage in the V3 signature block.
677         apkDataSource = Resources.toDataSource(getClass(), "golden-aligned-v1v2v3-out.apk");
678         try {
679             SigningCertificateLineage.readV31FromApkDataSource(apkDataSource);
680             fail("A failure should have been reported due to the APK containing a V3 signing "
681                 + "block without the lineage attribute");
682         } catch (IllegalArgumentException expected) {}
683 
684         // This is a valid APK signed with the V1, V2, and V3 signature schemes, with a valid
685         // lineage in the V3 signature block, but no V3.1 lineage.
686         apkDataSource = Resources.toDataSource(getClass(),
687             "v1v2v3-with-rsa-2048-lineage-3-signers.apk");
688         try {
689             SigningCertificateLineage.readV31FromApkDataSource(apkDataSource);
690             fail("A failure should have been reported due to the APK containing a V3 signing "
691                 + "block without the lineage attribute");
692         } catch (IllegalArgumentException expected) {}
693     }
694 
695     @Test
696     /**
697      * old lineage: A -> B
698      * new lineage: A -> B
699      */
testCheckLineagesCompatibilitySameLineages()700     public void testCheckLineagesCompatibilitySameLineages() throws Exception {
701         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
702                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
703                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
704         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
705                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
706                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
707 
708         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
709     }
710 
711     @Test
712     /**
713      * old lineage: A -> B
714      * new lineage: A -> B -> C
715      */
testCheckLineagesCompatibilityUpdateLonger()716     public void testCheckLineagesCompatibilityUpdateLonger() throws Exception {
717         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
718                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
719                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
720         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
721                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
722                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
723                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
724 
725         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
726     }
727 
728     @Test
729     /**
730      * old lineage: A
731      * new lineage: A -> B -> C
732      */
testCheckLineagesCompatibilityUpdateExtended()733     public void testCheckLineagesCompatibilityUpdateExtended() throws Exception {
734         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
735                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME));
736         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
737                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
738                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
739                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
740 
741         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
742     }
743 
744     @Test
745     /**
746      * old lineage: A -> B
747      * new lineage: C -> B
748      */
testCheckLineagesCompatibilityUpdateFirstMismatch()749     public void testCheckLineagesCompatibilityUpdateFirstMismatch() throws Exception {
750         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
751                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
752                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
753         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
754                 Arrays.asList(THIRD_RSA_2048_SIGNER_RESOURCE_NAME,
755                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
756 
757         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
758     }
759 
760     @Test
761     /**
762      * old lineage: A -> B
763      * new lineage: A -> C
764      */
testCheckLineagesCompatibilityUpdateSecondMismatch()765     public void testCheckLineagesCompatibilityUpdateSecondMismatch() throws Exception {
766         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
767                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
768                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
769         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
770                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
771                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
772 
773         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
774     }
775 
776     @Test
777     /**
778      * old lineage: A -> B -> C
779      * new lineage: A -> B
780      */
testCheckLineagesCompatibilityUpdateShorter()781     public void testCheckLineagesCompatibilityUpdateShorter() throws Exception {
782         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
783                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
784                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
785                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
786         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
787                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
788                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
789 
790         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
791     }
792 
793     @Test
794     /**
795      * old lineage: A_withRollbackCapability -> B -> C
796      * new lineage: A -> B
797      */
testCheckLineagesCompatibilityUpdateShorterWithDifferentKeyRollback()798     public void testCheckLineagesCompatibilityUpdateShorterWithDifferentKeyRollback()
799         throws Exception {
800         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
801                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
802                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
803                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME), Arrays.asList(0));
804         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
805                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
806                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
807 
808         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
809     }
810     @Test
811     /**
812      * old lineage: A -> B_withRollbackCapability -> C
813      * new lineage: A -> B
814      */
testCheckLineagesCompatibilityUpdateShorterWithRollback()815     public void testCheckLineagesCompatibilityUpdateShorterWithRollback() throws Exception {
816         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
817                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
818                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
819                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME), Arrays.asList(1));
820         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
821                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
822                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
823 
824         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
825     }
826 
827     @Test
828     /**
829      * old lineage: A_withRollbackCapability -> B_withRollbackCapability -> C
830      * new lineage: A -> B
831      */
testCheckLineagesCompatibilityUpdateShorterWithMultipleRollbacks()832     public void testCheckLineagesCompatibilityUpdateShorterWithMultipleRollbacks()
833         throws Exception {
834         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
835                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
836                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
837                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME), Arrays.asList(0, 1));
838         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
839                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
840                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
841 
842         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
843     }
844 
845     @Test
846     /**
847      * old lineage: A_withRollbackCapability -> B
848      * new lineage: A -> C
849      */
testCheckLineagesCompatibilityUpdateShorterWithRollbackAdditionalCertificate()850     public void testCheckLineagesCompatibilityUpdateShorterWithRollbackAdditionalCertificate()
851         throws Exception {
852         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
853                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
854                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME), Arrays.asList(0));
855         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
856                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
857                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
858 
859         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
860     }
861 
862     @Test
863     /**
864      * old lineage: empty
865      * new lineage: A -> B
866      */
testCheckLineagesCompatibilityOldNotV31Signed()867     public void testCheckLineagesCompatibilityOldNotV31Signed() throws Exception {
868         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
869                 Arrays.asList(FIRST_RSA_1024_SIGNER_RESOURCE_NAME,
870                         SECOND_RSA_1024_SIGNER_RESOURCE_NAME));
871 
872             assertTrue(SigningCertificateLineage.checkLineagesCompatibility(
873                     /* oldLineage= */ null, newLineage));
874         }
875 
876     @Test
877     /**
878      * old lineage: A -> B
879      * new lineage: empty
880      */
testCheckLineagesCompatibilityNewNotV31Signed()881     public void testCheckLineagesCompatibilityNewNotV31Signed() throws Exception {
882         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
883                 Arrays.asList(FIRST_RSA_1024_SIGNER_RESOURCE_NAME,
884                         SECOND_RSA_1024_SIGNER_RESOURCE_NAME));
885 
886         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(
887                 oldLineage, /* newLineage= */ null));
888     }
889 
890     @Test
891     /**
892      * old lineage: empty
893      * new lineage: empty
894      */
testCheckLineagesCompatibilityBothNotV31Signed()895     public void testCheckLineagesCompatibilityBothNotV31Signed() throws Exception {
896         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(
897                 /* oldLineage= */ null, /* newLineage= */ null));
898     }
899 
900     @Test
901     /**
902      * old lineage: A -> B -> C
903      * new lineage: B -> C
904      */
testCheckLineagesCompatibilityUpdateTrimmed()905     public void testCheckLineagesCompatibilityUpdateTrimmed()
906         throws Exception {
907         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
908                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
909                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
910         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
911                 Arrays.asList(SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
912                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
913 
914         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
915     }
916 
917     @Test
918     /**
919      * old lineage: A -> B
920      * new lineage: B -> C
921      */
testCheckLineagesCompatibilityUpdateTrimmedAndExtended()922     public void testCheckLineagesCompatibilityUpdateTrimmedAndExtended()
923         throws Exception {
924         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
925                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
926                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME));
927         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
928                 Arrays.asList(SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
929                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
930 
931         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
932     }
933 
934     @Test
935     /**
936      * old lineage: A -> B -> C
937      * new lineage: C
938      */
testCheckLineagesCompatibilityUpdateTrimmedToOne()939     public void testCheckLineagesCompatibilityUpdateTrimmedToOne()
940         throws Exception {
941         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
942                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
943                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
944         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
945                 Arrays.asList(THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
946 
947         assertTrue(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
948     }
949 
950     @Test
951     /**
952      * old lineage: A -> B -> C
953      * new lineage: A -> C
954      */
testCheckLineagesCompatibilityUpdateWronglyTrimmed()955     public void testCheckLineagesCompatibilityUpdateWronglyTrimmed()
956         throws Exception {
957         SigningCertificateLineage oldLineage = createLineageWithSignersFromResources(
958                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
959                         SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
960         SigningCertificateLineage newLineage = createLineageWithSignersFromResources(
961                 Arrays.asList(FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
962                         THIRD_RSA_2048_SIGNER_RESOURCE_NAME));
963 
964         assertFalse(SigningCertificateLineage.checkLineagesCompatibility(oldLineage, newLineage));
965     }
966 
967     @Test
testMergeLineageWithTwoEqualLineagesReturnsMergedLineage()968     public void testMergeLineageWithTwoEqualLineagesReturnsMergedLineage() throws Exception {
969         // The mergeLineageWith method is intended to merge two separate lineages into a superset
970         // that spans both lineages. This method verifies if both lineages have the same signers,
971         // the merged lineage will have the same signers as well.
972         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
973                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
974         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
975                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
976 
977         SigningCertificateLineage mergedLineage = lineage1.mergeLineageWith(lineage2);
978 
979         assertLineageContainsExpectedSigners(mergedLineage, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
980                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
981     }
982 
983     @Test
testMergeLineageWithOverlappingLineageReturnsMergedLineage()984     public void testMergeLineageWithOverlappingLineageReturnsMergedLineage() throws Exception {
985         // When A -> B and B -> C are passed to mergeLineageWith, the merged lineage should be
986         // A -> B -> C.
987         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
988                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
989         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
990                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
991 
992         SigningCertificateLineage mergedLineage1 = lineage1.mergeLineageWith(lineage2);
993         SigningCertificateLineage mergedLineage2 = lineage2.mergeLineageWith(lineage1);
994 
995         assertLineageContainsExpectedSigners(mergedLineage1, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
996                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
997         assertLineageContainsExpectedSigners(mergedLineage2, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
998                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
999     }
1000 
1001     @Test
testMergeLineageWithNoOverlappingLineageThrowsException()1002     public void testMergeLineageWithNoOverlappingLineageThrowsException() throws Exception {
1003         // When two lineages do not have any overlap, an exception should be thrown since the two
1004         // lineages cannot be merged.
1005         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
1006                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
1007         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
1008                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1009 
1010         assertThrows(IllegalArgumentException.class, () -> lineage1.mergeLineageWith(lineage2));
1011         assertThrows(IllegalArgumentException.class, () -> lineage2.mergeLineageWith(lineage1));
1012     }
1013 
1014     @Test
testMergeLineageWithDivergedLineageThrowsException()1015     public void testMergeLineageWithDivergedLineageThrowsException() throws Exception {
1016         // When two lineages share a common ancestor but diverge at later signers, an exception
1017         // should be thrown since the two lineages cannot be merged.
1018         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
1019                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
1020         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
1021                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1022 
1023         assertThrows(IllegalArgumentException.class, () -> lineage1.mergeLineageWith(lineage2));
1024         assertThrows(IllegalArgumentException.class, () -> lineage2.mergeLineageWith(lineage1));
1025     }
1026 
1027     @Test
testMergeLineageWithSingleSublineageInLineageReturnsMergedLineage()1028     public void testMergeLineageWithSingleSublineageInLineageReturnsMergedLineage()
1029             throws Exception {
1030         // If A -> B -> C and B are passed to mergeLineageWith, then the merged lineage should be
1031         // A -> B -> C.
1032         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
1033                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
1034                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1035         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
1036                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
1037 
1038         SigningCertificateLineage mergedLineage1 = lineage1.mergeLineageWith(lineage2);
1039         SigningCertificateLineage mergedLineage2 = lineage2.mergeLineageWith(lineage1);
1040 
1041         assertLineageContainsExpectedSigners(mergedLineage1, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
1042                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1043         assertLineageContainsExpectedSigners(mergedLineage2, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
1044                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1045     }
1046 
1047     @Test
testMergeLineageWithAncestorSublineageInLineageReturnsMergedLineage()1048     public void testMergeLineageWithAncestorSublineageInLineageReturnsMergedLineage()
1049             throws Exception {
1050         // If A -> B -> C and A -> B are passed to mergeLineageWith, then the merged lineage should
1051         // be A -> B -> C.
1052         SigningCertificateLineage lineage1 = createLineageWithSignersFromResources(
1053                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME,
1054                 THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1055         SigningCertificateLineage lineage2 = createLineageWithSignersFromResources(
1056                 FIRST_RSA_2048_SIGNER_RESOURCE_NAME, SECOND_RSA_2048_SIGNER_RESOURCE_NAME);
1057 
1058         SigningCertificateLineage mergedLineage1 = lineage1.mergeLineageWith(lineage2);
1059         SigningCertificateLineage mergedLineage2 = lineage2.mergeLineageWith(lineage1);
1060 
1061         assertLineageContainsExpectedSigners(mergedLineage1, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
1062                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1063         assertLineageContainsExpectedSigners(mergedLineage2, FIRST_RSA_2048_SIGNER_RESOURCE_NAME,
1064                 SECOND_RSA_2048_SIGNER_RESOURCE_NAME, THIRD_RSA_2048_SIGNER_RESOURCE_NAME);
1065     }
1066 
1067     /**
1068      * Builds a new {@code SigningCertificateLinage.SignerCapabilities} object using the values in
1069      * the provided {@code List}. The {@code List} should contain {@code boolean} values to be
1070      * passed to the following methods in the
1071      * {@code SigningCertificateLineage.SignerCapabilities.Builder} (if a value is not provided the
1072      * noted default is used):
1073      *
1074      *  {@code SigningCertificateLineage.SignerCapabilities.Builder.setInstalledData} [{@code true}]
1075      *  {@code SigningCertificateLineage.SignerCapabilities.Builder.setSharedUid} [{@code true}]
1076      *  {@code SigningCertificateLineage.SignerCapabilities.Builder.setPermission} [{@code true}]
1077      *  {@code SigningCertificateLineage.SignerCapabilities.Builder.setRollback} [{@code false}]
1078      *  {@code SigningCertificateLineage.SignerCapabilities.Builder.setAuth} [{@code true}]
1079      *
1080      * This method should not be used when testing caller configured capabilities since the setXX
1081      * method for each capability is called.
1082      */
buildSignerCapabilities(List<Boolean> capabilityValues)1083     private SignerCapabilities buildSignerCapabilities(List<Boolean> capabilityValues) {
1084         return new SignerCapabilities.Builder()
1085                 .setInstalledData(capabilityValues.size() > 0 ? capabilityValues.get(0) : true)
1086                 .setSharedUid(capabilityValues.size() > 1 ? capabilityValues.get(1) : true)
1087                 .setPermission(capabilityValues.size() > 2 ? capabilityValues.get(2) : true)
1088                 .setRollback(capabilityValues.size() > 3 ? capabilityValues.get(3) : false)
1089                 .setAuth(capabilityValues.size() > 4 ? capabilityValues.get(4) : true)
1090                 .build();
1091     }
1092 
1093     /**
1094      * Verifies the specified {@code SigningCertificateLinage.SignerCapabilities} contains the
1095      * expected values from the provided {@code List}. The {@code List} should contain {@code
1096      * boolean} values to be verified against the {@code
1097      * SigningCertificateLinage.SignerCapabilities} methods in the following order:
1098      *
1099      * <p>{@mcode SigningCertificateLineage.SignerCapabilities.hasInstalledData} {@mcode
1100      * SigningCertificateLineage.SignerCapabilities.hasSharedUid} {@mcode
1101      * SigningCertificateLineage.SignerCapabilities.hasPermission} {@mcode
1102      * SigningCertificateLineage.SignerCapabilities.hasRollback} {@mcode
1103      * SigningCertificateLineage.SignerCapabilities.hasAuth}
1104      */
assertExpectedCapabilityValues( SignerCapabilities capabilities, List<Boolean> expectedCapabilityValues)1105     private void assertExpectedCapabilityValues(
1106             SignerCapabilities capabilities, List<Boolean> expectedCapabilityValues) {
1107         assertTrue("The expectedCapabilityValues do not contain the expected number of elements",
1108                 expectedCapabilityValues.size() >= 5);
1109         assertEquals(
1110                 "The installed data capability is not set to the expected value",
1111                 expectedCapabilityValues.get(0), capabilities.hasInstalledData());
1112         assertEquals(
1113                 "The shared UID capability is not set to the expected value",
1114                 expectedCapabilityValues.get(1), capabilities.hasSharedUid());
1115         assertEquals(
1116                 "The permission capability is not set to the expected value",
1117                 expectedCapabilityValues.get(2), capabilities.hasPermission());
1118         assertEquals(
1119                 "The rollback capability is not set to the expected value",
1120                 expectedCapabilityValues.get(3), capabilities.hasRollback());
1121         assertEquals(
1122                 "The auth capability is not set to the expected value",
1123                 expectedCapabilityValues.get(4), capabilities.hasAuth());
1124     }
1125 
1126     /**
1127      * Creates a new {@code SigningCertificateLineage} with the specified signers from the
1128      * resources. {@code mSigners} will be updated with the
1129      * {@code SigningCertificateLineage.SignerConfig} for each signer added to the lineage.
1130      */
createLineageWithSignersFromResources( String oldSignerResourceName, String newSignerResourceName)1131     private SigningCertificateLineage createLineageWithSignersFromResources(
1132             String oldSignerResourceName, String newSignerResourceName) throws Exception {
1133         SignerConfig oldSignerConfig = Resources.toLineageSignerConfig(getClass(),
1134                 oldSignerResourceName);
1135         mSigners.add(oldSignerConfig);
1136         SignerConfig newSignerConfig = Resources.toLineageSignerConfig(getClass(),
1137                 newSignerResourceName);
1138         mSigners.add(newSignerConfig);
1139         return new SigningCertificateLineage.Builder(oldSignerConfig, newSignerConfig).build();
1140     }
1141 
1142     /**
1143      * Creates a new {@code SigningCertificateLineage} with the specified signers from the
1144      * resources. {@code mSigners} will be updated with the {@code
1145      * SigningCertificateLineage.SignerConfig} for each signer added to the lineage.
1146      */
createLineageWithSignersFromResources( SigningCertificateLineage.SignerConfig oldSignerConfig, SigningCertificateLineage.SignerConfig newSignerConfig)1147     private SigningCertificateLineage createLineageWithSignersFromResources(
1148             SigningCertificateLineage.SignerConfig oldSignerConfig,
1149             SigningCertificateLineage.SignerConfig newSignerConfig)
1150             throws Exception {
1151         mSigners.add(oldSignerConfig);
1152         mSigners.add(newSignerConfig);
1153         return new SigningCertificateLineage.Builder(oldSignerConfig, newSignerConfig).build();
1154     }
1155 
createLineageWithSignersFromResources( String signerResourceName)1156     private SigningCertificateLineage createLineageWithSignersFromResources(
1157             String signerResourceName) throws Exception {
1158         SignerConfig signerConfig = Resources.toLineageSignerConfig(getClass(),
1159             signerResourceName);
1160         mSigners.add(signerConfig);
1161         return new SigningCertificateLineage.Builder(signerConfig).build();
1162     }
1163 
createLineageWithSignersFromResources( List<String> signerResourcesNames)1164     private SigningCertificateLineage createLineageWithSignersFromResources(
1165             List<String> signerResourcesNames)
1166             throws Exception {
1167         if (signerResourcesNames.isEmpty()) {
1168             throw new Exception();
1169         }
1170         SigningCertificateLineage lineage =
1171                 createLineageWithSignersFromResources(signerResourcesNames.get(0));
1172         for (String resourceName : signerResourcesNames.subList(1, signerResourcesNames.size())) {
1173             lineage = updateLineageWithSignerFromResources(lineage, resourceName);
1174         }
1175         return lineage;
1176     }
1177 
createLineageWithSignersFromResources( List<String> signerResourcesNames, List<Integer> rollbackCapabilityNodes)1178     private SigningCertificateLineage createLineageWithSignersFromResources(
1179             List<String> signerResourcesNames,
1180             List<Integer> rollbackCapabilityNodes)
1181         throws Exception {
1182         SigningCertificateLineage lineage =
1183                 createLineageWithSignersFromResources(signerResourcesNames);
1184         for (Integer i : rollbackCapabilityNodes) {
1185             if (i < mSigners.size()) {
1186                 SignerCapabilities newCapabilities = new SignerCapabilities.Builder()
1187                     .setRollback(true).build();
1188                 lineage.updateSignerCapabilities(mSigners.get(i), newCapabilities);
1189             }
1190         }
1191         return lineage;
1192     }
1193     /**
1194      * Creates a new {@code SigningCertificateLineage} with the specified signers from the
1195      * resources.
1196      */
createLineageWithSignersFromResources(String... signers)1197     private SigningCertificateLineage createLineageWithSignersFromResources(String... signers)
1198             throws Exception {
1199         SignerConfig ancestorSignerConfig = Resources.toLineageSignerConfig(getClass(), signers[0]);
1200         SigningCertificateLineage lineage = new SigningCertificateLineage.Builder(
1201                 ancestorSignerConfig).build();
1202         for (int i = 1; i < signers.length; i++) {
1203             SignerConfig descendantSignerConfig = Resources.toLineageSignerConfig(getClass(),
1204                     signers[i]);
1205             lineage = lineage.spawnDescendant(ancestorSignerConfig, descendantSignerConfig);
1206             ancestorSignerConfig = descendantSignerConfig;
1207         }
1208         return lineage;
1209     }
1210 
1211     /**
1212      * Updates the specified {@code SigningCertificateLineage} with the signer from the resources.
1213      * Requires that the {@code mSigners} list contains the previous signers in the lineage since
1214      * the most recent signer must be specified when adding a new signer to the lineage.
1215      */
updateLineageWithSignerFromResources( SigningCertificateLineage lineage, String newSignerResourceName)1216     private SigningCertificateLineage updateLineageWithSignerFromResources(
1217             SigningCertificateLineage lineage, String newSignerResourceName) throws Exception {
1218         // To add a new Signer to an existing lineage the config of the last signer must be
1219         // specified. If this class was used to create the lineage then the last signer should
1220         // be in the mSigners list.
1221         assertTrue("The mSigners list did not contain the expected signers to update the lineage",
1222                 mSigners.size() >= 1);
1223         SignerConfig oldSignerConfig = mSigners.get(mSigners.size() - 1);
1224         SignerConfig newSignerConfig = Resources.toLineageSignerConfig(getClass(),
1225                 newSignerResourceName);
1226         mSigners.add(newSignerConfig);
1227         return lineage.spawnDescendant(oldSignerConfig, newSignerConfig);
1228     }
1229 
1230     /**
1231      * Asserts the provided {@code lineage} contains the {@code expectedSigners} from the test's
1232      * resources.
1233      */
assertLineageContainsExpectedSigners(SigningCertificateLineage lineage, String... expectedSigners)1234     protected static void assertLineageContainsExpectedSigners(SigningCertificateLineage lineage,
1235             String... expectedSigners) throws Exception {
1236         assertLineageContainsExpectedSigners(lineage,
1237                 getSignerConfigsFromResources(expectedSigners));
1238     }
1239 
getSignerConfigsFromResources(String... signers)1240     private static List<SignerConfig> getSignerConfigsFromResources(String... signers)
1241             throws Exception {
1242         List<SignerConfig> signerConfigs = new ArrayList<>();
1243         for (String signer : signers) {
1244             signerConfigs.add(getSignerConfigFromResources(signer));
1245         }
1246         return signerConfigs;
1247     }
1248 
assertLineageContainsExpectedSigners(SigningCertificateLineage lineage, List<SignerConfig> signers)1249     private static void assertLineageContainsExpectedSigners(SigningCertificateLineage lineage,
1250             List<SignerConfig> signers) {
1251         assertEquals("The lineage does not contain the expected number of signers",
1252                 signers.size(), lineage.size());
1253         for (SignerConfig signer : signers) {
1254             assertTrue("The signer " + signer.getCertificate().getSubjectDN()
1255                     + " is expected to be in the lineage", lineage.isSignerInLineage(signer));
1256         }
1257     }
1258 
assertLineageContainsExpectedSignersWithCapabilities( SigningCertificateLineage lineage, String[] signers, SignerCapabilities[] capabilities)1259     protected static void assertLineageContainsExpectedSignersWithCapabilities(
1260             SigningCertificateLineage lineage, String[] signers,
1261             SignerCapabilities[] capabilities) throws Exception {
1262         List<SignerConfig> signerConfigs = getSignerConfigsFromResources(signers);
1263         assertEquals("The lineage does not contain the expected number of signers",
1264                 signerConfigs.size(), lineage.size());
1265         assertEquals(
1266                 "The capabilities does not contain the expected number for the provided signers",
1267                 signerConfigs.size(), capabilities.length);
1268         for (int i = 0; i < signerConfigs.size(); i++) {
1269             SignerConfig signerConfig = signerConfigs.get(i);
1270             assertTrue("The signer " + signerConfig.getCertificate().getSubjectDN()
1271                     + " is expected to be in the lineage", lineage.isSignerInLineage(signerConfig));
1272             assertEquals(lineage.getSignerCapabilities(signerConfig), capabilities[i]);
1273         }
1274     }
1275 
getSignerConfigFromResources( String resourcePrefix)1276     private static SignerConfig getSignerConfigFromResources(
1277             String resourcePrefix) throws Exception {
1278         PrivateKey privateKey =
1279                 Resources.toPrivateKey(SigningCertificateLineageTest.class,
1280                         resourcePrefix + ".pk8");
1281         X509Certificate cert = Resources.toCertificate(SigningCertificateLineageTest.class,
1282                 resourcePrefix + ".x509.pem");
1283         return new SignerConfig.Builder(new KeyConfig.Jca(privateKey), cert).build();
1284     }
1285 
getApkSignerEngineSignerConfigFromResources( String resourcePrefix)1286     private static DefaultApkSignerEngine.SignerConfig getApkSignerEngineSignerConfigFromResources(
1287             String resourcePrefix) throws Exception {
1288         return getApkSignerEngineSignerConfigFromResources(resourcePrefix, 0, null);
1289     }
1290 
getApkSignerEngineSignerConfigFromResources( String resourcePrefix, int minSdkVersion, SigningCertificateLineage lineage)1291     private static DefaultApkSignerEngine.SignerConfig getApkSignerEngineSignerConfigFromResources(
1292             String resourcePrefix, int minSdkVersion, SigningCertificateLineage lineage)
1293             throws Exception {
1294         PrivateKey privateKey =
1295                 Resources.toPrivateKey(SigningCertificateLineageTest.class,
1296                         resourcePrefix + ".pk8");
1297         X509Certificate cert = Resources.toCertificate(SigningCertificateLineageTest.class,
1298                 resourcePrefix + ".x509.pem");
1299         DefaultApkSignerEngine.SignerConfig.Builder configBuilder =
1300                 new DefaultApkSignerEngine.SignerConfig.Builder(
1301                         resourcePrefix,
1302                         new KeyConfig.Jca(privateKey),
1303                         Collections.singletonList(cert));
1304         if (minSdkVersion > 0) {
1305             configBuilder.setLineageForMinSdkVersion(lineage, minSdkVersion);
1306         }
1307         return configBuilder.build();
1308     }
1309 }
1310