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